passenger 4.0.33 → 4.0.34

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (112) hide show
  1. checksums.yaml +15 -0
  2. checksums.yaml.gz.asc +12 -0
  3. data.tar.gz.asc +7 -7
  4. data/NEWS +60 -0
  5. data/bin/passenger-config +1 -1
  6. data/bin/passenger-install-apache2-module +510 -40
  7. data/bin/passenger-install-nginx-module +26 -2
  8. data/build/cxx_tests.rb +1 -1
  9. data/build/documentation.rb +19 -21
  10. data/build/integration_tests.rb +39 -12
  11. data/build/misc.rb +18 -0
  12. data/build/packaging.rb +116 -56
  13. data/build/rpm.rb +20 -11
  14. data/build/ruby_tests.rb +2 -3
  15. data/build/test_basics.rb +9 -0
  16. data/debian.template/passenger.conf +2 -0
  17. data/debian.template/passenger.load +2 -0
  18. data/dev/run_travis.sh +3 -5
  19. data/dev/test_rpm_packaging.sh +28 -0
  20. data/doc/Users guide Apache.idmap.txt +6 -4
  21. data/doc/users_guide_snippets/installation.txt +20 -2
  22. data/doc/users_guide_snippets/tips.txt +1 -1
  23. data/ext/common/ApplicationPool2/Pool.h +1 -1
  24. data/ext/common/Constants.h +5 -1
  25. data/ext/common/agents/HelperAgent/RequestHandler.h +1 -1
  26. data/ext/common/agents/Watchdog/AgentWatcher.cpp +20 -0
  27. data/ext/common/agents/Watchdog/Main.cpp +10 -0
  28. data/ext/ruby/passenger_native_support.c +23 -11
  29. data/helper-scripts/classic-rails-loader.rb +9 -3
  30. data/helper-scripts/classic-rails-preloader.rb +10 -4
  31. data/helper-scripts/download_binaries/extconf.rb +46 -22
  32. data/helper-scripts/meteor-loader.rb +0 -1
  33. data/helper-scripts/node-loader.js +2 -1
  34. data/helper-scripts/prespawn +7 -1
  35. data/helper-scripts/rack-loader.rb +32 -3
  36. data/helper-scripts/rack-preloader.rb +10 -4
  37. data/lib/phusion_passenger.rb +40 -21
  38. data/lib/phusion_passenger/abstract_installer.rb +7 -4
  39. data/lib/phusion_passenger/analytics_logger.rb +4 -3
  40. data/lib/phusion_passenger/config/about_command.rb +27 -6
  41. data/lib/phusion_passenger/{config.rb → config/main.rb} +3 -2
  42. data/lib/phusion_passenger/config/restart_app_command.rb +1 -1
  43. data/lib/phusion_passenger/config/validate_install_command.rb +231 -0
  44. data/lib/phusion_passenger/constants.rb +2 -0
  45. data/lib/phusion_passenger/loader_shared_helpers.rb +92 -19
  46. data/lib/phusion_passenger/native_support.rb +33 -11
  47. data/lib/phusion_passenger/packaging.rb +1 -0
  48. data/lib/phusion_passenger/platform_info.rb +5 -2
  49. data/lib/phusion_passenger/platform_info/apache.rb +229 -60
  50. data/lib/phusion_passenger/platform_info/apache_detector.rb +26 -31
  51. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +4 -4
  52. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +4 -4
  53. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +1 -1
  54. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +1 -1
  55. data/lib/phusion_passenger/platform_info/linux.rb +2 -1
  56. data/lib/phusion_passenger/platform_info/ruby.rb +7 -0
  57. data/lib/phusion_passenger/preloader_shared_helpers.rb +2 -1
  58. data/lib/phusion_passenger/request_handler.rb +2 -1
  59. data/lib/phusion_passenger/request_handler/thread_handler.rb +2 -1
  60. data/lib/phusion_passenger/standalone/runtime_installer.rb +35 -13
  61. data/lib/phusion_passenger/standalone/start_command.rb +2 -2
  62. data/lib/phusion_passenger/utils.rb +1 -23
  63. data/lib/phusion_passenger/utils/ansi_colors.rb +7 -1
  64. data/lib/phusion_passenger/utils/download.rb +36 -2
  65. data/lib/phusion_passenger/utils/native_support_utils.rb +65 -0
  66. data/resources/templates/apache2/apache_install_broken.txt.erb +20 -0
  67. data/resources/templates/apache2/config_snippets.txt.erb +2 -4
  68. data/resources/templates/apache2/present_choice_for_no_update_config.txt.erb +5 -0
  69. data/resources/templates/installer_common/cannot_access_files_as_root.txt.erb +15 -0
  70. data/resources/templates/installer_common/run_installer_as_root.txt.erb +6 -3
  71. data/resources/templates/nginx/nginx_module_sources_not_available.txt.erb +1 -1
  72. data/resources/templates/nginx/other_nginx_installations_exist.txt.erb +17 -0
  73. data/rpm/apache-passenger.conf.in +26 -0
  74. data/rpm/config.json +30 -0
  75. data/rpm/passenger.logrotate +7 -0
  76. data/rpm/passenger.spec.template +456 -0
  77. data/rpm/passenger_dynamic_thread_group.patch +16 -0
  78. data/rpm/passenger_tests_default_config_example.patch +44 -0
  79. data/rpm/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +21 -0
  80. data/rpm/rubygem-passenger-4.0.18-gcc47-include-sys_types.patch +45 -0
  81. data/test/config.json.rpm-automation +15 -0
  82. data/test/integration_tests/downloaded_binaries_tests.rb +80 -2
  83. data/test/integration_tests/native_packaging_spec.rb +136 -44
  84. data/test/integration_tests/standalone_tests.rb +2 -11
  85. data/test/ruby/analytics_logger_spec.rb +65 -19
  86. data/test/ruby/utils_spec.rb +2 -0
  87. metadata +532 -548
  88. metadata.gz.asc +7 -7
  89. data/resources/templates/apache2/no_write_permission_to_passenger_root.txt.erb +0 -9
  90. data/rpm/README.rdoc +0 -117
  91. data/rpm/config/apache-passenger.conf.in +0 -19
  92. data/rpm/config/nginx-passenger.conf.in +0 -10
  93. data/rpm/config/rubygem-passenger.te +0 -10
  94. data/rpm/doc/README.nginx-alternatives +0 -5
  95. data/rpm/doc/example_yum_repository_htaccess +0 -5
  96. data/rpm/doc/footer.shtml +0 -12
  97. data/rpm/doc/header.shtml +0 -156
  98. data/rpm/nginx-alternatives.spec +0 -97
  99. data/rpm/passenger-release.spec +0 -91
  100. data/rpm/passenger.spec +0 -667
  101. data/rpm/patches/passenger-force-native.patch +0 -63
  102. data/rpm/release/RPM-GPG-KEY-stealthymonkeys +0 -33
  103. data/rpm/release/build-release.sh +0 -35
  104. data/rpm/release/build.rb +0 -301
  105. data/rpm/release/create-mirrors.sh +0 -16
  106. data/rpm/release/mirrors +0 -1
  107. data/rpm/release/mock-repo/comps.xml +0 -21
  108. data/rpm/release/mock-repo/rubygem-daemon_controller-0.2.5-1.noarch.rpm +0 -0
  109. data/rpm/release/mock-repo/rubygem-file-tail-1.0.5-1.noarch.rpm +0 -0
  110. data/rpm/release/mock-repo/rubygem-spruz-0.2.2-1.noarch.rpm +0 -0
  111. data/rpm/release/mocksetup-first.sh +0 -102
  112. data/rpm/release/mocksetup.sh +0 -67
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NjJhYjliOWQ0ZTA5ZGVlZmYyOGYzZmI3OGZjNDE2ZjY5Mzg5ZjQ2Mw==
5
+ data.tar.gz: !binary |-
6
+ MWJkNzVhNWVhOTQ5NDllZDcwMTRiNzNiZjcwZmQ5OTI1MjBiYWIzMA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YzMxMmQxMzkwNGM4ODBiYWYzMWNiZGNkY2M2ZDg2ZGU1MGUxODNkNTA5YmNm
10
+ YTgzOTI0NDQ5YzRjMWI3ZDE5YjE5YzI5NTIzYTYyMzA0YzhiNGU1YjdhNjBl
11
+ NGQ5ODY0N2EwZWFlNDk5NWMyMmI3ODZjZTIzYTEwYmY1NjNiNjU=
12
+ data.tar.gz: !binary |-
13
+ MTY0YTUxMjdhZmFiMDc0YzAzZGY3YjY3ZjVlYWMxN2ZlZjk3MGZmZWVjNmFk
14
+ ZTA5NDQwYjU1ODczZmQ2NDhjMmU3NGEwN2Y5MzZmMTM4YzkwOWE4ZDdhNDVl
15
+ OThmYzdiNjAyZjhmMDI2ODMxNmFmODk3NTQzYmI4ZDRiNzM4ZGY=
@@ -0,0 +1,12 @@
1
+ -----BEGIN PGP SIGNATURE-----
2
+ Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
+ Comment: GPGTools - http://gpgtools.org
4
+
5
+ iQEcBAABAgAGBQJS1vGUAAoJECrHRaUKISqMkX8IAK95IieSbNT29p85XwYr1H83
6
+ GItWs0fCk1QD36B/W8pu0PuXXm0ImeicGSI2arI5jzGdlX0KOrKyD+78R0hT23TN
7
+ cbvi7HflwdDDxxDEMpmhEML5tJZYKWmv0A729NVoNbP6jSEs8upUjxZJcQfrKFFL
8
+ YEoBwdU7YX2Z8a1XD5mr60XXSHyvJ2chFqTWlvODrIeQqAk8FuJgPEA+x9eV5pxb
9
+ JLKIcZY7FPwSJFsFHkG2395MZcdphQl2xQ63yzO9lL6ncYkCWlM8djFKzekoThlf
10
+ tMSJjnmw08pKCMvk19i0ASSoNuFdHHwORWY9s4A08o2ZiAVf9Edv9PvYXBpmV0Q=
11
+ =8Sfb
12
+ -----END PGP SIGNATURE-----
data.tar.gz.asc CHANGED
@@ -2,11 +2,11 @@
2
2
  Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
3
  Comment: GPGTools - http://gpgtools.org
4
4
 
5
- iQEcBAABAgAGBQJSxXh6AAoJECrHRaUKISqMPwMH/j/0ykK8uEZ7k7sGv9Ch/aYX
6
- TCPIgAwnnT1fckLnlKgMrPuLVos2BtMbCTD8gc0MWI2EYCI9JlQsrcgpWU9qAKEI
7
- JUGiwxVS9D0YbVFhdfSkqzeDu3VzNHCLB57OzRZr32ICCM6bOqkXcmrQ4gbMvk3Q
8
- dzDnESAbOybGNZ5PLQj5PXgNY6BWPt9FFrZ0zbM8CLLo3Jyk0t2+XEhknvLRrJYs
9
- M/kNcrrRCxXFiXYygCalsGHySmyYUumC5eZlkiPTfiaVMQBc6sZ2ZAROVSn2OUt+
10
- 6aISpr4WR2Nk2pvhkxIWUjyZL9BP/H44I/v7rDVwSF4Iz3P32YRV0x1XkttuNYg=
11
- =GZg/
5
+ iQEcBAABAgAGBQJS1vGUAAoJECrHRaUKISqM1zsIAIQfj5kkFgjPlMRhI+KaHbk1
6
+ 7fhcnu1HiuxJxy5h0egMm7FKm53/6MigQk2jwzjL30MKmGAgGNcYKAHz5DNImqwK
7
+ fX/j8LIiUaxCJZkyxsMWseZmX+nL40lMlIu30PTpAWBJeFOsF9r/XL2b8JmofAKV
8
+ 1NjrSOi7vZh9MUIts0VmDc1D06ZJJgoWC1HvTqHuDG2E7EOcxATMBJ5zF1taDRx/
9
+ nTFfLBhEUplByOcnFYMIasZl+3uVoije+Hzk5qOC9+LhBo4bSqXsp3g8PO5BVkok
10
+ ysqD05YYWw/+EwfZSZuYWTofddAZPGSfavp8GNTl+ZMyIzSuwfx+SoCl3sCix9M=
11
+ =NIdk
12
12
  -----END PGP SIGNATURE-----
data/NEWS CHANGED
@@ -1,3 +1,63 @@
1
+ Release 4.0.34
2
+ --------------
3
+
4
+ * The Node.js loader code now sets the `isApplicationLoader` attribute on the
5
+ bootstrapping module. This provides a way for apps and frameworks that check
6
+ for `module.parent` to check whether the current file is loaded by Phusion
7
+ Passenger, or by other software that work in a similar way.
8
+
9
+ This change has been introduced to solve a compatibility issue with CompoundJS.
10
+ CompoundJS users should modify their server.js, and change the following:
11
+
12
+ if (!module.parent) {
13
+
14
+ to:
15
+
16
+ if (!module.parent || module.parent.isApplicationLoader) {
17
+
18
+ * Improved support for Meteor in development mode. Terminating Phusion Passenger
19
+ now leaves less garbage Meteor processes behind.
20
+ * It is now possible to disable the usage of the Ruby native extension by setting
21
+ the environment variable `PASSENGER_USE_RUBY_NATIVE_SUPPORT=0`.
22
+ * Fixed incorrect detection of the Apache MPM on Ubuntu 13.10.
23
+ * When using RVM, if you set PassengerRuby/passenger_ruby to the raw Ruby binary
24
+ instead of the wrapper script, Phusion Passenger will now print an error.
25
+ * Added support for RVM >= 1.25 wrapper scripts.
26
+ * Fixed loading passenger_native_support on Ruby 1.9.2.
27
+ * The Union Station analytics code now works even without native_support.
28
+ * Fixed `passenger-install-apache2-module` and `passenger-install-nginx-module` in
29
+ Homebrew.
30
+ * Binaries are now downloaded from an Amazon S3 mirror if the main binary server
31
+ is unavailable.
32
+ * And finally, although this isn't really a change in 4.0.34, it should be noted.
33
+ In version 4.0.33 we changed the way Phusion Passenger's own Ruby source files
34
+ are loaded, in order to fix some Debian and RPM packaging issues. The following
35
+ doesn't work anymore:
36
+
37
+ require 'phusion_passenger/foo'
38
+
39
+ Instead, it should become:
40
+
41
+ PhusionPassenger.require_passenger_lib 'foo'
42
+
43
+ However, we overlooked the fact that this change breaks Ruby apps which use
44
+ our Out-of-Band GC feature, because such apps had to call
45
+ `require 'phusion_passenger/rack/out_of_band_gc'`. Unfortunately we're not able
46
+ to maintain compatibility without reintroducing the Debian and RPM packaging
47
+ issues. Users should modify the following:
48
+
49
+ require 'phusion_passenger/rack/out_of_band_gc'
50
+
51
+ to:
52
+
53
+ if PhusionPassenger.respond_to?(:require_passenger_lib)
54
+ # Phusion Passenger >= 4.0.33
55
+ PhusionPassenger.require_passenger_lib 'rack/out_of_band_gc'
56
+ else
57
+ # Phusion Passenger < 4.0.33
58
+ require 'phusion_passenger/rack/out_of_band_gc'
59
+ end
60
+
1
61
  Release 4.0.33
2
62
  --------------
3
63
 
@@ -33,5 +33,5 @@ require 'phusion_passenger'
33
33
  ## Magic comment: end bootstrap ##
34
34
 
35
35
  PhusionPassenger.locate_directories
36
- PhusionPassenger.require_passenger_lib 'config'
36
+ PhusionPassenger.require_passenger_lib 'config/main'
37
37
  PhusionPassenger::Config.run!(ARGV)
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: binary
2
3
  # Phusion Passenger - https://www.phusionpassenger.com/
3
- # Copyright (c) 2010-2013 Phusion
4
+ # Copyright (c) 2010-2014 Phusion
4
5
  #
5
6
  # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
7
  #
@@ -52,7 +53,12 @@ PhusionPassenger.require_passenger_lib 'utils/terminal_choice_menu'
52
53
  class Installer < PhusionPassenger::AbstractInstaller
53
54
  include PhusionPassenger
54
55
  TerminalChoiceMenu = PhusionPassenger::Utils::TerminalChoiceMenu
55
-
56
+
57
+ AUTOINSTALL_BEGIN_LOAD_BLOCK = "### Begin automatically installed #{PROGRAM_NAME} load snippet ###"
58
+ AUTOINSTALL_END_LOAD_BLOCK = "### End automatically installed #{PROGRAM_NAME} load snippet ###"
59
+ AUTOINSTALL_BEGIN_CONF_BLOCK = "### Begin automatically installed #{PROGRAM_NAME} config snippet ###"
60
+ AUTOINSTALL_END_CONF_BLOCK = "### End automatically installed #{PROGRAM_NAME} config snippet ###"
61
+
56
62
  def dependencies
57
63
  specs = [
58
64
  'depcheck_specs/compiler_toolchain',
@@ -102,7 +108,7 @@ class Installer < PhusionPassenger::AbstractInstaller
102
108
  end
103
109
 
104
110
  def run_steps
105
- if PhusionPassenger.natively_packaged?
111
+ if PhusionPassenger.natively_packaged? && PhusionPassenger.apache2_module_source_dir.nil?
106
112
  if apache_module_available?
107
113
  notify_apache_module_installed
108
114
  show_deployment_example
@@ -112,7 +118,7 @@ class Installer < PhusionPassenger::AbstractInstaller
112
118
  exit
113
119
  end
114
120
 
115
- Dir.chdir(PhusionPassenger.source_root)
121
+ Dir.chdir(PhusionPassenger.apache2_module_source_dir)
116
122
  show_welcome_screen
117
123
  query_interested_languages
118
124
  check_gem_install_permission_problems || exit(1)
@@ -123,8 +129,9 @@ class Installer < PhusionPassenger::AbstractInstaller
123
129
  check_whether_os_is_broken
124
130
  check_whether_system_has_enough_ram
125
131
  check_write_permission_to_passenger_root || exit(1)
126
- if install_apache2_module
127
- show_apache2_config_snippets
132
+ check_write_permission_to_web_server_config_files || exit(1)
133
+ if compile_apache2_module
134
+ install_apache2_config_snippets || exit(1)
128
135
  show_deployment_example
129
136
  else
130
137
  show_possible_solutions_for_compilation_and_installation_problems
@@ -150,6 +157,7 @@ private
150
157
  puts
151
158
  if interactive?
152
159
  puts "Use <space> to select."
160
+ puts "<dgray>If the menu doesn't display correctly, ensure that your terminal supports UTF-8.</dgray>"
153
161
  else
154
162
  puts "Override selection with --languages."
155
163
  end
@@ -188,13 +196,12 @@ private
188
196
  detector.report
189
197
  @apache2 = detector.result_for(PlatformInfo.apxs2)
190
198
  if @apache2.nil?
191
- # Yes this can happen (see https://groups.google.com/forum/#!topic/phusion-passenger/JcUJOBzILB4)
192
- # but I have no idea how and why. I need people who can help me reproduce this.
193
- # Until then, let's output an error.
194
- raise "An internal error occurred. No information detected for #{PlatformInfo.apxs2} " +
195
- "(@apache2 is nil). Please contact this program's authors for support, and please " +
196
- "attach the full output of this installer, as well as the full output of the command " +
197
- "'passenger-config --detect-apache2'."
199
+ render_template 'apache2/apache_install_broken',
200
+ :apxs2 => PlatformInfo.apxs2,
201
+ :sudo_s_e => PhusionPassenger::PlatformInfo.ruby_sudo_shell_command("-E"),
202
+ :ruby => PhusionPassenger::PlatformInfo.ruby_command,
203
+ :passenger_config => "#{PhusionPassenger.bin_dir}/passenger-config"
204
+ return false
198
205
  end
199
206
  if detector.results.size > 1
200
207
  other_installs = detector.results - [@apache2]
@@ -214,8 +221,10 @@ private
214
221
  return result
215
222
  else
216
223
  puts '<yellow>Continuing installation because --auto is given.</yellow>'
224
+ return true
217
225
  end
218
226
  else
227
+ puts '<green>All good!</green>'
219
228
  return true
220
229
  end
221
230
  ensure
@@ -230,7 +239,7 @@ private
230
239
  # ...
231
240
  # Server compiled with....
232
241
  # -D APACHE_MPM_DIR="server/mpm/prefork"
233
- output = `#{PlatformInfo.httpd} -V`
242
+ output = PlatformInfo.httpd_V
234
243
  output =~ /^Server MPM: +(.*)$/
235
244
  if $1
236
245
  mpm = $1.downcase
@@ -257,10 +266,12 @@ private
257
266
  puts
258
267
  line
259
268
  if Process.uid == 0
260
- render_template 'apache2/no_write_permission_to_passenger_root'
269
+ render_template 'installer_common/cannot_access_files_as_root',
270
+ :type => "directory",
271
+ :files => [PhusionPassenger.apache2_module_source_dir]
261
272
  else
262
273
  render_template 'installer_common/run_installer_as_root',
263
- :dir => PhusionPassenger.source_root,
274
+ :dir => PhusionPassenger.apache2_module_source_dir,
264
275
  :sudo => PhusionPassenger::PlatformInfo.ruby_sudo_command,
265
276
  :sudo_s_e => PhusionPassenger::PlatformInfo.ruby_sudo_shell_command("-E"),
266
277
  :ruby => PhusionPassenger::PlatformInfo.ruby_command,
@@ -270,41 +281,489 @@ private
270
281
  ensure
271
282
  File.unlink("__test__.txt") rescue nil
272
283
  end
284
+
285
+ def check_write_permission_to_web_server_config_files
286
+ return true if !@update_config
287
+ config_file = PlatformInfo.httpd_default_config_file
288
+ return if !config_file || !File.exist?(config_file)
289
+
290
+ all_config_files = PlatformInfo.httpd_included_config_files(config_file)
291
+ if all_config_files[:unreadable_files].any?
292
+ puts
293
+ line
294
+ if Process.uid == 0
295
+ render_template 'installer_common/cannot_access_files_as_root',
296
+ :access => "read from",
297
+ :files => all_config_files[:unreadable_files]
298
+ else
299
+ render_template 'installer_common/run_installer_as_root',
300
+ :access => "read from",
301
+ :desc => "an Apache configuration file",
302
+ :sudo => PhusionPassenger::PlatformInfo.ruby_sudo_command,
303
+ :sudo_s_e => PhusionPassenger::PlatformInfo.ruby_sudo_shell_command("-E"),
304
+ :ruby => PhusionPassenger::PlatformInfo.ruby_command,
305
+ :installer => "#{PhusionPassenger.bin_dir}/passenger-install-apache2-module #{ORIG_ARGV.join(' ')}"
306
+ end
307
+ puts
308
+ render_template 'apache2/present_choice_for_no_update_config'
309
+ return false
310
+ end
311
+
312
+ unwriteable_files = []
313
+ all_config_files[:files].each do |filename|
314
+ if !File.writable_real?(filename)
315
+ unwriteable_files << filename
316
+ end
317
+ end
318
+ if unwriteable_files.empty?
319
+ return true
320
+ else
321
+ puts
322
+ line
323
+ if Process.uid == 0
324
+ render_template 'installer_common/cannot_access_files_as_root',
325
+ :files => unwriteable_files
326
+ else
327
+ render_template 'installer_common/run_installer_as_root',
328
+ :desc => "an Apache configuration file",
329
+ :sudo => PhusionPassenger::PlatformInfo.ruby_sudo_command,
330
+ :sudo_s_e => PhusionPassenger::PlatformInfo.ruby_sudo_shell_command("-E"),
331
+ :ruby => PhusionPassenger::PlatformInfo.ruby_command,
332
+ :installer => "#{PhusionPassenger.bin_dir}/passenger-install-apache2-module #{ORIG_ARGV.join(' ')}"
333
+ end
334
+ puts
335
+ render_template 'apache2/present_choice_for_no_update_config'
336
+ return false
337
+ end
338
+ end
273
339
 
274
- def install_apache2_module
340
+ def compile_apache2_module
275
341
  puts
276
342
  line
277
343
  puts '<banner>Compiling and installing Apache 2 module...</banner>'
278
- puts "cd #{PhusionPassenger.source_root}"
279
- if ENV['TRACE']
280
- puts "#{PlatformInfo.rake_command} --trace apache2:clean apache2 RELEASE=yes"
281
- return sh("#{PlatformInfo.rake_command} --trace apache2:clean apache2 RELEASE=yes")
344
+ if @compile
345
+ puts "cd #{PhusionPassenger.apache2_module_source_dir}"
346
+ if ENV['TRACE']
347
+ rake = "#{PlatformInfo.rake_command} --trace RELEASE=yes"
348
+ else
349
+ rake = "#{PlatformInfo.rake_command} RELEASE=yes"
350
+ end
351
+ command = "#{rake} apache2:clean apache2"
352
+ if PhusionPassenger.native_packaging_method == "homebrew"
353
+ # Running apache2:clean deletes some object files needed
354
+ # by passenger-install-nginx-module, so we ensure those
355
+ # object files are compiled.
356
+ command << " nginx"
357
+ end
358
+ return sh(command)
282
359
  else
283
- puts "#{PlatformInfo.rake_command} apache2:clean apache2 RELEASE=yes"
284
- return sh("#{PlatformInfo.rake_command} apache2:clean apache2 RELEASE=yes")
360
+ puts "Skipping compilation"
361
+ return true
285
362
  end
286
363
  end
287
364
 
288
- def show_apache2_config_snippets(bare = false)
289
- if bare
290
- puts "LoadModule passenger_module #{PhusionPassenger.apache2_module_path}"
291
- puts "PassengerRoot #{PhusionPassenger.source_root}"
292
- puts "PassengerDefaultRuby #{PlatformInfo.ruby_command}"
365
+ def load_snippet
366
+ return "LoadModule passenger_module #{PhusionPassenger.apache2_module_path}"
367
+ end
368
+
369
+ def config_snippet
370
+ return "<IfModule mod_passenger.c>\n" +
371
+ " PassengerRoot #{PhusionPassenger.source_root}\n" +
372
+ " PassengerDefaultRuby #{PlatformInfo.ruby_command}\n" +
373
+ "</IfModule>"
374
+ end
375
+
376
+ def apache2_config_snippets
377
+ return "#{load_snippet}\n#{config_snippet}\n"
378
+ end
379
+
380
+ def backup_config_files(config_file, all_config_files)
381
+ now = Time.now.strftime("%Y-%m-%d-%H:%M:%S")
382
+ archive = "#{config_file}.#{GLOBAL_NAMESPACE_DIRNAME}-backup-#{now}.tar.gz"
383
+ backup_files = all_config_files.dup
384
+
385
+ # Some people create a regular file in /etc/apache2/mods-enabled, for convenience
386
+ # reasons. This file is not actually managed by a2enmod. We will remove such files
387
+ # because we're going to use mods-eanbled ourselves, so we need to back them up.
388
+ if (dir = PlatformInfo.httpd_mods_enabled_directory) && PlatformInfo.a2enmod
389
+ if File.file?("#{dir}/#{APACHE2_MODULE_CONF_NAME}.load")
390
+ backup_files << "#{dir}/#{APACHE2_MODULE_CONF_NAME}.load"
391
+ end
392
+ if File.file?("#{dir}/#{APACHE2_MODULE_CONF_NAME}.conf")
393
+ backup_files << "#{dir}/#{APACHE2_MODULE_CONF_NAME}.conf"
394
+ end
395
+ end
396
+
397
+ puts "Backing up existing configuration files to #{archive}..."
398
+ backup_files.uniq!
399
+ backup_files.map! { |x| x.sub(/^\//, '') }
400
+ Dir.chdir("/") do
401
+ sh! "tar", "-czf", archive, *backup_files
402
+ end
403
+ end
404
+
405
+ def uninstall_or_comment_out_existing_config_snippets(all_config_files)
406
+ files_containing_autoinstall_load_blocks = []
407
+ files_containing_autoinstall_conf_blocks = []
408
+
409
+ # Some people create a regular file in /etc/apache2/mods-enabled, for convenience
410
+ # reasons. This file is not actually managed by a2enmod. We remove such files
411
+ # because we're going to use mods-enabled ourselves. They've already been backed up.
412
+ if (dir = PlatformInfo.httpd_mods_enabled_directory) && PlatformInfo.a2enmod
413
+ filename = "#{dir}/#{APACHE2_MODULE_CONF_NAME}.load"
414
+ if File.file?(filename) && !File.symlink?(filename)
415
+ puts "Removing #{filename}"
416
+ File.unlink(filename)
417
+ end
418
+ filename = "#{dir}/#{APACHE2_MODULE_CONF_NAME}.conf"
419
+ if File.file?(filename) && !File.symlink?(filename)
420
+ puts "Removing #{filename}"
421
+ File.unlink(filename)
422
+ end
423
+ end
424
+
425
+ # Uncomment Phusion Passenger config snippets.
426
+ all_config_files.each do |filename|
427
+ next if !File.exist?(filename)
428
+
429
+ contents = File.open(filename, "rb") do |f|
430
+ f.read
431
+ end
432
+ if contents =~ /#{Regexp.escape AUTOINSTALL_BEGIN_LOAD_BLOCK}.*?#{Regexp.escape AUTOINSTALL_END_LOAD_BLOCK}/m
433
+ files_containing_autoinstall_load_blocks << filename
434
+ end
435
+ if contents =~ /#{Regexp.escape AUTOINSTALL_BEGIN_CONF_BLOCK}.*?#{Regexp.escape AUTOINSTALL_END_CONF_BLOCK}/m
436
+ files_containing_autoinstall_conf_blocks << filename
437
+ end
438
+ subst1 = contents.gsub!(/^([ \t]*LoadModule[ \t]+passenger_module[ \t]+.*)$/i, '# \1')
439
+ subst2 = contents.gsub!(/^([ \t]*PassengerRoot[ \t]+.*)$/i, '# \1')
440
+ subst3 = contents.gsub!(/^([ \t]*PassengerDefaultRuby[ \t]+.*)$/i, '# \1')
441
+ if subst1 || subst2 || subst3
442
+ puts "Uninstalling previous #{PROGRAM_NAME} from #{filename}..."
443
+ File.open(filename, "wb") do |f|
444
+ f.write(contents)
445
+ end
446
+ end
447
+ end
448
+
449
+ # If there are multiple auto-install comment blocks, remove the duplicates.
450
+ # First, we remove all comment blocks from all files besides the first one.
451
+ if files_containing_autoinstall_load_blocks.size > 1
452
+ files_containing_autoinstall_load_blocks[1..-1].each do |filename|
453
+ puts "Removing duplicate load snippets from #{filename}..."
454
+ remove_comment_blocks(filename,
455
+ AUTOINSTALL_BEGIN_LOAD_BLOCK,
456
+ AUTOINSTALL_END_LOAD_BLOCK)
457
+ end
458
+ end
459
+ if files_containing_autoinstall_conf_blocks.size > 1
460
+ files_containing_autoinstall_conf_blocks[1..-1].each do |filename|
461
+ puts "Removing duplicate conf snippets from #{filename}..."
462
+ remove_comment_blocks(filename,
463
+ AUTOINSTALL_BEGIN_CONF_BLOCK,
464
+ AUTOINSTALL_END_CONF_BLOCK)
465
+ end
466
+ end
467
+
468
+ # Then we are left with exactly 0 or exactly 1 file with comment blocks
469
+ # of each type. There may be duplicates inside that single file, so
470
+ # remove duplicates there too.
471
+ if files_containing_autoinstall_load_blocks.size > 0
472
+ filename = files_containing_autoinstall_load_blocks[0]
473
+ puts "Removing duplicate load snippets inside #{filename}..."
474
+ remove_duplicate_comment_blocks(filename,
475
+ AUTOINSTALL_BEGIN_LOAD_BLOCK,
476
+ AUTOINSTALL_END_LOAD_BLOCK)
477
+ end
478
+ if files_containing_autoinstall_conf_blocks.size > 0
479
+ filename = files_containing_autoinstall_conf_blocks[0]
480
+ puts "Removing duplicate configuration snippets inside #{filename}..."
481
+ remove_duplicate_comment_blocks(filename,
482
+ AUTOINSTALL_BEGIN_CONF_BLOCK,
483
+ AUTOINSTALL_END_CONF_BLOCK)
484
+ end
485
+
486
+ # One or more files may have been removed, so filter out the ones
487
+ # that are left.
488
+ all_config_files.reject! do |filename|
489
+ !File.exist?(filename)
490
+ end
491
+ end
492
+
493
+ def remove_comment_blocks(filename, begin_marker, end_marker)
494
+ contents = File.open(filename, "rb") do |f|
495
+ f.read
496
+ end
497
+ regexp = /#{Regexp.escape begin_marker}.*?#{Regexp.escape end_marker}\n?/m
498
+ contents.gsub!(regexp, '')
499
+ File.open(filename, "wb") do |f|
500
+ f.write(contents)
501
+ end
502
+ end
503
+
504
+ def remove_duplicate_comment_blocks(filename, begin_marker, end_marker)
505
+ contents = File.open(filename, "rb") do |f|
506
+ f.read
507
+ end
508
+ regexp = /#{Regexp.escape begin_marker}.*?#{Regexp.escape end_marker}\n?/m
509
+ if m = regexp.match(contents)
510
+ offset = m.end(0)
511
+ rest = contents.slice!(m.end(0) .. -1)
512
+ rest.gsub!(regexp, '')
513
+ contents << rest
514
+ File.open(filename, "wb") do |f|
515
+ f.write(contents)
516
+ end
517
+ end
518
+ end
519
+
520
+ def add_new_config_snippets(all_config_files)
521
+ # Look for the file containing the auto-install load and conf comment blocks.
522
+ # The uninstall_or_comment_out_existing_config_snippets method has already
523
+ # guaranteed that there is at most 1 file per comment block type, and that
524
+ # inside each file there are no duplicate comment blocks.
525
+ load_block_file = find_config_file_containing_comment_block(all_config_files,
526
+ AUTOINSTALL_BEGIN_LOAD_BLOCK,
527
+ AUTOINSTALL_END_LOAD_BLOCK)
528
+ conf_block_file = find_config_file_containing_comment_block(all_config_files,
529
+ AUTOINSTALL_BEGIN_CONF_BLOCK,
530
+ AUTOINSTALL_END_CONF_BLOCK)
531
+ if load_block_file && conf_block_file
532
+ puts "Updating #{PROGRAM_NAME} module load snippet inside #{load_block_file}..."
533
+ update_comment_block(load_block_file,
534
+ AUTOINSTALL_BEGIN_LOAD_BLOCK,
535
+ AUTOINSTALL_END_LOAD_BLOCK,
536
+ load_snippet)
537
+ puts "Updating #{PROGRAM_NAME} configuration snippet inside #{conf_block_file}..."
538
+ update_comment_block(conf_block_file,
539
+ AUTOINSTALL_BEGIN_CONF_BLOCK,
540
+ AUTOINSTALL_END_CONF_BLOCK,
541
+ config_snippet)
542
+ elsif !load_block_file && !conf_block_file
543
+ create_load_snippet_file(:maybe_in_mods_available)
544
+ create_conf_snippet_file(:maybe_in_mods_available)
545
+ if PlatformInfo.httpd_mods_available_directory && PlatformInfo.a2enmod
546
+ sh! "#{PlatformInfo.a2enmod} #{APACHE2_MODULE_CONF_NAME}"
547
+ end
548
+ # It looks like either the load or conf file isn't available.
549
+ # If the file that is available is inside mods-available, then it
550
+ # means that the mods-available files are broken.
551
+ elsif is_file_inside_mods_available?(load_block_file, "#{APACHE2_MODULE_CONF_NAME}.load") ||
552
+ is_file_inside_mods_available?(conf_block_file, "#{APACHE2_MODULE_CONF_NAME}.conf")
553
+ # We fix it if a2enmod is available. Otherwise, we remove the block.
554
+ if PlatformInfo.a2enmod
555
+ if !load_block_file
556
+ create_load_snippet_file(:must_be_in_mods_available)
557
+ else
558
+ create_conf_snippet_file(:must_be_in_mods_available)
559
+ end
560
+ else
561
+ if load_block_file
562
+ puts "Removing load snippets from #{filename}..."
563
+ remove_comment_blocks(load_block_file,
564
+ AUTOINSTALL_BEGIN_LOAD_BLOCK,
565
+ AUTOINSTALL_END_LOAD_BLOCK)
566
+ else
567
+ puts "Removing configuration snippets from #{filename}..."
568
+ remove_comment_blocks(conf_block_file,
569
+ AUTOINSTALL_BEGIN_CONF_BLOCK,
570
+ AUTOINSTALL_END_CONF_BLOCK)
571
+ end
572
+ create_load_snippet_file(:must_be_in_mods_available)
573
+ create_conf_snippet_file(:must_be_in_mods_available)
574
+ end
575
+ sh! "#{PlatformInfo.a2enmod} passenger"
293
576
  else
294
- puts
295
- line
296
- render_template 'apache2/config_snippets',
297
- :module_location => PhusionPassenger.apache2_module_path,
298
- :passenger_root => PhusionPassenger.source_root,
299
- :ruby => PlatformInfo.ruby_command
300
- if PhusionPassenger.originally_packaged?
301
- wait
577
+ if !load_block_file
578
+ create_load_snippet_file(:not_in_mods_available)
579
+ puts "Updating #{PROGRAM_NAME} configuration snippet inside #{conf_block_file}..."
580
+ update_comment_block(conf_block_file,
581
+ AUTOINSTALL_BEGIN_CONF_BLOCK,
582
+ AUTOINSTALL_END_CONF_BLOCK,
583
+ config_snippet)
302
584
  else
303
- wait(10)
585
+ create_conf_snippet_file(:not_in_mods_available)
586
+ puts "Updating #{PROGRAM_NAME} module load snippet inside #{load_block_file}..."
587
+ update_comment_block(load_block_file,
588
+ AUTOINSTALL_BEGIN_LOAD_BLOCK,
589
+ AUTOINSTALL_END_LOAD_BLOCK,
590
+ load_snippet)
304
591
  end
305
592
  end
306
593
  end
307
-
594
+
595
+ def find_config_file_containing_comment_block(all_config_files, begin_marker, end_marker)
596
+ regexp = /#{Regexp.escape begin_marker}.*?#{Regexp.escape end_marker}/m
597
+ all_config_files.each do |filename|
598
+ contents = File.open(filename, "rb") do |f|
599
+ f.read
600
+ end
601
+ if contents =~ regexp
602
+ return filename
603
+ end
604
+ end
605
+ return nil
606
+ end
607
+
608
+ def update_comment_block(filename, begin_marker, end_marker, block_contents)
609
+ regexp = /#{Regexp.escape begin_marker}.*?#{Regexp.escape end_marker}\n?/m
610
+ contents = File.open(filename, "rb") do |f|
611
+ f.read
612
+ end
613
+ if contents.sub!(regexp, "#{begin_marker}\n#{block_contents}\n#{end_marker}\n")
614
+ File.open(filename, "wb") do |f|
615
+ f.write(contents)
616
+ end
617
+ return true
618
+ else
619
+ return false
620
+ end
621
+ end
622
+
623
+ def remove_comment_blocks(filename, begin_marker, end_marker)
624
+ regexp = /#{Regexp.escape begin_marker}.*?#{Regexp.escape end_marker}\n?/m
625
+ contents = File.open(filename, "rb") do |f|
626
+ f.read
627
+ end
628
+ contents.gsub!(regexp, "")
629
+ File.open(filename, "wb") do |f|
630
+ f.write(contents)
631
+ end
632
+ end
633
+
634
+ def is_file_inside_mods_available?(filename, basename)
635
+ if dir = PlatformInfo.httpd_mods_available_directory
636
+ return filename == "#{dir}/#{basename}"
637
+ else
638
+ return false
639
+ end
640
+ end
641
+
642
+ def create_load_snippet_file(where)
643
+ case where
644
+ when :maybe_in_mods_available
645
+ if PlatformInfo.httpd_mods_available_directory && PlatformInfo.a2enmod
646
+ filename = "#{PlatformInfo.httpd_mods_available_directory}/#{APACHE2_MODULE_CONF_NAME}.load"
647
+ else
648
+ filename = PlatformInfo.httpd_default_config_file
649
+ end
650
+ when :must_be_in_mods_available
651
+ if PlatformInfo.httpd_mods_available_directory && PlatformInfo.a2enmod
652
+ filename = "#{PlatformInfo.httpd_mods_available_directory}/#{APACHE2_MODULE_CONF_NAME}.load"
653
+ else
654
+ raise "Apache does not support the mods-available directory"
655
+ end
656
+ when :not_in_mods_available
657
+ filename = PlatformInfo.httpd_default_config_file
658
+ else
659
+ raise ArgumentError
660
+ end
661
+
662
+ if File.exist?(filename)
663
+ # If this is a file inside mods-available, and the file didn't have a symlink
664
+ # in mods-enabled, then the uninstall phase did not remove duplicates from this
665
+ # file. So here we remove duplicates again.
666
+ puts "Removing duplicate load snippets inside #{filename}..."
667
+ remove_duplicate_comment_blocks(filename,
668
+ AUTOINSTALL_BEGIN_LOAD_BLOCK,
669
+ AUTOINSTALL_END_LOAD_BLOCK)
670
+
671
+ puts "Installing #{PROGRAM_NAME} module load snippet to #{filename}..."
672
+ should_add = !update_comment_block(filename,
673
+ AUTOINSTALL_BEGIN_LOAD_BLOCK,
674
+ AUTOINSTALL_END_LOAD_BLOCK,
675
+ load_snippet)
676
+ else
677
+ puts "Installing #{PROGRAM_NAME} module load snippet to #{filename}..."
678
+ should_add = true
679
+ end
680
+ if should_add
681
+ File.open(filename, "ab") do |f|
682
+ f.write("\n#{AUTOINSTALL_BEGIN_LOAD_BLOCK}\n" +
683
+ "#{load_snippet}\n" +
684
+ "#{AUTOINSTALL_END_LOAD_BLOCK}\n")
685
+ end
686
+ end
687
+ end
688
+
689
+ def create_conf_snippet_file(where)
690
+ case where
691
+ when :maybe_in_mods_available
692
+ if PlatformInfo.httpd_mods_available_directory && PlatformInfo.a2enmod
693
+ filename = "#{PlatformInfo.httpd_mods_available_directory}/#{APACHE2_MODULE_CONF_NAME}.conf"
694
+ else
695
+ filename = PlatformInfo.httpd_default_config_file
696
+ end
697
+ when :must_be_in_mods_available
698
+ if PlatformInfo.httpd_mods_available_directory && PlatformInfo.a2enmod
699
+ filename = "#{PlatformInfo.httpd_mods_available_directory}/#{APACHE2_MODULE_CONF_NAME}.conf"
700
+ else
701
+ raise "Apache does not support the mods-available directory"
702
+ end
703
+ when :not_in_mods_available
704
+ filename = PlatformInfo.httpd_default_config_file
705
+ else
706
+ raise ArgumentError
707
+ end
708
+
709
+ if File.exist?(filename)
710
+ # If this is a file inside mods-available, and the file didn't have a symlink
711
+ # in mods-enabled, then the uninstall phase did not remove duplicates from this
712
+ # file. So here we remove duplicates again.
713
+ puts "Removing duplicate configuration snippets inside #{filename}..."
714
+ remove_duplicate_comment_blocks(filename,
715
+ AUTOINSTALL_BEGIN_CONF_BLOCK,
716
+ AUTOINSTALL_END_CONF_BLOCK)
717
+
718
+ puts "Installing #{PROGRAM_NAME} module configuration snippet to #{filename}..."
719
+ should_add = !update_comment_block(filename,
720
+ AUTOINSTALL_BEGIN_CONF_BLOCK,
721
+ AUTOINSTALL_END_CONF_BLOCK,
722
+ config_snippet)
723
+ else
724
+ puts "Installing #{PROGRAM_NAME} module configuration snippet to #{filename}..."
725
+ should_add = true
726
+ end
727
+ if should_add
728
+ File.open(filename, "ab") do |f|
729
+ f.write("\n#{AUTOINSTALL_BEGIN_CONF_BLOCK}\n" +
730
+ "#{config_snippet}\n" +
731
+ "#{AUTOINSTALL_END_CONF_BLOCK}\n")
732
+ end
733
+ end
734
+ end
735
+
736
+ def install_apache2_config_snippets
737
+ if !@update_config
738
+ show_apache2_config_snippets
739
+ return true
740
+ end
741
+
742
+ config_file = PlatformInfo.httpd_default_config_file
743
+ if config_file && File.exist?(config_file)
744
+ puts
745
+ line
746
+ puts "<banner>Updating Apache configuration files...</banner>"
747
+ config_file = PlatformInfo.httpd_default_config_file
748
+ all_config_files = PlatformInfo.httpd_included_config_files(config_file)[:files]
749
+ backup_config_files(config_file, all_config_files) if @backup_config
750
+ uninstall_or_comment_out_existing_config_snippets(all_config_files)
751
+ add_new_config_snippets(all_config_files)
752
+ return true
753
+ else
754
+ show_apache2_config_snippets
755
+ return true
756
+ end
757
+ end
758
+
759
+ def show_apache2_config_snippets
760
+ puts
761
+ line
762
+ render_template 'apache2/config_snippets',
763
+ :snippet => apache2_config_snippets
764
+ wait
765
+ end
766
+
308
767
  def show_deployment_example
309
768
  new_screen
310
769
  render_template 'apache2/deployment_example',
@@ -350,7 +809,7 @@ private
350
809
  end
351
810
 
352
811
  ORIG_ARGV = ARGV.dup
353
- options = {}
812
+ options = { :compile => true, :update_config => false, :backup_config => true }
354
813
  parser = OptionParser.new do |opts|
355
814
  opts.banner = "Usage: passenger-install-apache2-module [options]"
356
815
  opts.separator ""
@@ -373,6 +832,17 @@ parser = OptionParser.new do |opts|
373
832
  "#{indent}'ruby,python,nodejs,meteor')") do |value|
374
833
  options[:languages] = value.split(",")
375
834
  end
835
+ opts.on("--no-compile", "Skip compilation.") do
836
+ options[:compile] = false
837
+ end
838
+ #opts.on("--no-update-config", "Do not automatically update Apache config\n" <<
839
+ # "#{indent}files.") do
840
+ # options[:update_config] = false
841
+ #end
842
+ #opts.on("--no-backup-config", "When updating Apache config files, do not\n" <<
843
+ # "#{indent}create backups of the existing files.") do
844
+ # options[:backup_config] = false
845
+ #end
376
846
  opts.on("--snippet", "Show just the Apache config snippet.") do
377
847
  options[:snippet] = true
378
848
  end
@@ -388,7 +858,7 @@ end
388
858
 
389
859
  installer = Installer.new(options)
390
860
  if options[:snippet]
391
- installer.send(:show_apache2_config_snippets, true)
861
+ puts installer.send(:apache2_config_snippets)
392
862
  else
393
863
  installer.run
394
864
  end