passenger 5.0.0.beta3 → 5.0.0.rc1

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 (218) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +11 -5
  5. data/CHANGELOG +38 -0
  6. data/CONTRIBUTING.md +1 -4
  7. data/Gemfile +0 -1
  8. data/Gemfile.lock +0 -2
  9. data/Rakefile +33 -33
  10. data/bin/passenger +1 -1
  11. data/bin/passenger-config +1 -1
  12. data/bin/passenger-install-apache2-module +800 -800
  13. data/bin/passenger-install-nginx-module +592 -592
  14. data/bin/passenger-memory-stats +127 -127
  15. data/bin/passenger-status +216 -216
  16. data/build/agents.rb +127 -127
  17. data/build/apache2.rb +87 -87
  18. data/build/basics.rb +60 -60
  19. data/build/common_library.rb +165 -165
  20. data/build/cplusplus_support.rb +51 -51
  21. data/build/cxx_tests.rb +268 -268
  22. data/build/debian.rb +143 -143
  23. data/build/documentation.rb +58 -58
  24. data/build/integration_tests.rb +81 -81
  25. data/build/misc.rb +132 -132
  26. data/build/nginx.rb +20 -20
  27. data/build/node_tests.rb +7 -7
  28. data/build/oxt_tests.rb +14 -14
  29. data/build/packaging.rb +570 -570
  30. data/build/preprocessor.rb +260 -260
  31. data/build/rake_extensions.rb +71 -71
  32. data/build/ruby_extension.rb +29 -29
  33. data/build/ruby_tests.rb +6 -6
  34. data/build/test_basics.rb +37 -37
  35. data/debian.template/control.template +3 -5
  36. data/dev/copy_boost_headers +134 -134
  37. data/dev/install_scripts_bootstrap_code.rb +25 -25
  38. data/dev/list_tests +20 -20
  39. data/dev/ruby_server.rb +223 -223
  40. data/dev/runner +18 -18
  41. data/doc/ServerOptimizationGuide.txt.md +55 -2
  42. data/doc/Users guide Nginx.txt +0 -26
  43. data/doc/Users guide Standalone.txt +5 -1
  44. data/doc/users_guide_snippets/tips.txt +9 -0
  45. data/ext/common/ApplicationPool2/Group.h +23 -11
  46. data/ext/common/ApplicationPool2/Implementation.cpp +32 -7
  47. data/ext/common/ApplicationPool2/Pool.h +22 -17
  48. data/ext/common/ApplicationPool2/SmartSpawner.h +4 -1
  49. data/ext/common/ApplicationPool2/Spawner.h +1 -1
  50. data/ext/common/Constants.h +1 -1
  51. data/ext/common/agents/Base.cpp +35 -20
  52. data/ext/common/agents/HelperAgent/Main.cpp +8 -1
  53. data/ext/common/agents/HelperAgent/OptionParser.h +18 -4
  54. data/ext/common/agents/HelperAgent/RequestHandler.h +2 -83
  55. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +54 -1
  56. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +7 -4
  57. data/ext/common/agents/Main.cpp +1 -1
  58. data/ext/common/agents/Watchdog/Main.cpp +54 -19
  59. data/ext/nginx/Configuration.c +7 -0
  60. data/ext/nginx/ContentHandler.c +9 -1
  61. data/helper-scripts/backtrace-sanitizer.rb +106 -87
  62. data/helper-scripts/crash-watch.rb +32 -0
  63. data/helper-scripts/download_binaries/extconf.rb +38 -38
  64. data/helper-scripts/meteor-loader.rb +107 -107
  65. data/helper-scripts/prespawn +101 -101
  66. data/helper-scripts/rack-loader.rb +96 -96
  67. data/helper-scripts/rack-preloader.rb +137 -137
  68. data/lib/phusion_passenger.rb +292 -292
  69. data/lib/phusion_passenger/abstract_installer.rb +438 -438
  70. data/lib/phusion_passenger/active_support3_extensions/init.rb +168 -170
  71. data/lib/phusion_passenger/admin_tools.rb +20 -20
  72. data/lib/phusion_passenger/admin_tools/instance.rb +178 -178
  73. data/lib/phusion_passenger/admin_tools/instance_registry.rb +61 -61
  74. data/lib/phusion_passenger/admin_tools/memory_stats.rb +267 -267
  75. data/lib/phusion_passenger/apache2/config_options.rb +182 -182
  76. data/lib/phusion_passenger/common_library.rb +479 -485
  77. data/lib/phusion_passenger/config/about_command.rb +161 -161
  78. data/lib/phusion_passenger/config/admin_command_command.rb +129 -129
  79. data/lib/phusion_passenger/config/agent_compiler.rb +121 -121
  80. data/lib/phusion_passenger/config/build_native_support_command.rb +43 -43
  81. data/lib/phusion_passenger/config/command.rb +25 -25
  82. data/lib/phusion_passenger/config/compile_agent_command.rb +62 -62
  83. data/lib/phusion_passenger/config/compile_nginx_engine_command.rb +88 -73
  84. data/lib/phusion_passenger/config/detach_process_command.rb +72 -72
  85. data/lib/phusion_passenger/config/download_agent_command.rb +246 -227
  86. data/lib/phusion_passenger/config/download_nginx_engine_command.rb +245 -224
  87. data/lib/phusion_passenger/config/install_agent_command.rb +144 -132
  88. data/lib/phusion_passenger/config/install_standalone_runtime_command.rb +205 -185
  89. data/lib/phusion_passenger/config/installation_utils.rb +204 -204
  90. data/lib/phusion_passenger/config/list_instances_command.rb +64 -64
  91. data/lib/phusion_passenger/config/main.rb +152 -152
  92. data/lib/phusion_passenger/config/nginx_engine_compiler.rb +319 -300
  93. data/lib/phusion_passenger/config/reopen_logs_command.rb +67 -67
  94. data/lib/phusion_passenger/config/restart_app_command.rb +155 -155
  95. data/lib/phusion_passenger/config/system_metrics_command.rb +13 -13
  96. data/lib/phusion_passenger/config/utils.rb +95 -95
  97. data/lib/phusion_passenger/config/validate_install_command.rb +198 -198
  98. data/lib/phusion_passenger/console_text_template.rb +25 -25
  99. data/lib/phusion_passenger/constants.rb +90 -90
  100. data/lib/phusion_passenger/debug_logging.rb +106 -106
  101. data/lib/phusion_passenger/loader_shared_helpers.rb +447 -432
  102. data/lib/phusion_passenger/message_channel.rb +312 -312
  103. data/lib/phusion_passenger/message_client.rb +176 -176
  104. data/lib/phusion_passenger/native_support.rb +369 -369
  105. data/lib/phusion_passenger/nginx/config_options.rb +297 -297
  106. data/lib/phusion_passenger/packaging.rb +131 -131
  107. data/lib/phusion_passenger/platform_info.rb +360 -360
  108. data/lib/phusion_passenger/platform_info/apache.rb +767 -767
  109. data/lib/phusion_passenger/platform_info/apache_detector.rb +199 -199
  110. data/lib/phusion_passenger/platform_info/binary_compatibility.rb +107 -107
  111. data/lib/phusion_passenger/platform_info/compiler.rb +570 -570
  112. data/lib/phusion_passenger/platform_info/curl.rb +32 -32
  113. data/lib/phusion_passenger/platform_info/cxx_portability.rb +188 -188
  114. data/lib/phusion_passenger/platform_info/depcheck.rb +372 -372
  115. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +109 -109
  116. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +4 -4
  117. data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +10 -34
  118. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +101 -101
  119. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +5 -5
  120. data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +13 -13
  121. data/lib/phusion_passenger/platform_info/linux.rb +55 -55
  122. data/lib/phusion_passenger/platform_info/operating_system.rb +149 -149
  123. data/lib/phusion_passenger/platform_info/ruby.rb +468 -448
  124. data/lib/phusion_passenger/platform_info/zlib.rb +9 -9
  125. data/lib/phusion_passenger/plugin.rb +66 -66
  126. data/lib/phusion_passenger/preloader_shared_helpers.rb +126 -126
  127. data/lib/phusion_passenger/public_api.rb +191 -191
  128. data/lib/phusion_passenger/rack/out_of_band_gc.rb +93 -94
  129. data/lib/phusion_passenger/rack/thread_handler_extension.rb +231 -227
  130. data/lib/phusion_passenger/request_handler.rb +567 -577
  131. data/lib/phusion_passenger/request_handler/thread_handler.rb +379 -381
  132. data/lib/phusion_passenger/ruby_core_enhancements.rb +86 -86
  133. data/lib/phusion_passenger/ruby_core_io_enhancements.rb +74 -74
  134. data/lib/phusion_passenger/simple_benchmarking.rb +25 -25
  135. data/lib/phusion_passenger/standalone/app_finder.rb +153 -150
  136. data/lib/phusion_passenger/standalone/command.rb +44 -40
  137. data/lib/phusion_passenger/standalone/config_utils.rb +53 -53
  138. data/lib/phusion_passenger/standalone/control_utils.rb +38 -59
  139. data/lib/phusion_passenger/standalone/main.rb +73 -73
  140. data/lib/phusion_passenger/standalone/start_command.rb +697 -685
  141. data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +193 -155
  142. data/lib/phusion_passenger/standalone/start_command/nginx_engine.rb +162 -133
  143. data/lib/phusion_passenger/standalone/status_command.rb +64 -64
  144. data/lib/phusion_passenger/standalone/stop_command.rb +72 -72
  145. data/lib/phusion_passenger/standalone/version_command.rb +9 -9
  146. data/lib/phusion_passenger/union_station/connection.rb +32 -32
  147. data/lib/phusion_passenger/union_station/core.rb +251 -251
  148. data/lib/phusion_passenger/union_station/transaction.rb +126 -126
  149. data/lib/phusion_passenger/utils.rb +199 -167
  150. data/lib/phusion_passenger/utils/ansi_colors.rb +128 -128
  151. data/lib/phusion_passenger/utils/download.rb +196 -196
  152. data/lib/phusion_passenger/utils/file_system_watcher.rb +158 -158
  153. data/lib/phusion_passenger/utils/hosts_file_parser.rb +101 -101
  154. data/lib/phusion_passenger/utils/lock.rb +31 -31
  155. data/lib/phusion_passenger/utils/native_support_utils.rb +31 -31
  156. data/lib/phusion_passenger/utils/progress_bar.rb +26 -26
  157. data/lib/phusion_passenger/utils/shellwords.rb +20 -20
  158. data/lib/phusion_passenger/utils/terminal_choice_menu.rb +206 -206
  159. data/lib/phusion_passenger/utils/unseekable_socket.rb +272 -272
  160. data/lib/phusion_passenger/vendor/crash_watch/app.rb +129 -0
  161. data/lib/phusion_passenger/vendor/crash_watch/gdb_controller.rb +341 -0
  162. data/lib/phusion_passenger/vendor/crash_watch/version.rb +24 -0
  163. data/lib/phusion_passenger/vendor/daemon_controller.rb +877 -0
  164. data/lib/phusion_passenger/vendor/daemon_controller/lock_file.rb +127 -0
  165. data/lib/phusion_passenger/vendor/daemon_controller/spawn.rb +26 -0
  166. data/lib/phusion_passenger/vendor/daemon_controller/version.rb +29 -0
  167. data/packaging/rpm/passenger_spec/passenger.spec.template +0 -1
  168. data/passenger.gemspec +0 -1
  169. data/resources/templates/config/nginx_engine_compiler/possible_solutions_for_download_and_extraction_problems.txt.erb +27 -0
  170. data/resources/templates/standalone/config.erb +19 -15
  171. data/test/integration_tests/apache2_tests.rb +566 -566
  172. data/test/integration_tests/downloaded_binaries_tests.rb +126 -125
  173. data/test/integration_tests/native_packaging_spec.rb +296 -296
  174. data/test/integration_tests/nginx_tests.rb +393 -393
  175. data/test/integration_tests/shared/example_webapp_tests.rb +282 -280
  176. data/test/integration_tests/source_packaging_test.rb +138 -138
  177. data/test/integration_tests/spec_helper.rb +5 -5
  178. data/test/integration_tests/standalone_tests.rb +367 -367
  179. data/test/ruby/debug_logging_spec.rb +133 -133
  180. data/test/ruby/message_channel_spec.rb +186 -186
  181. data/test/ruby/rack/loader_spec.rb +28 -28
  182. data/test/ruby/rack/preloader_spec.rb +34 -34
  183. data/test/ruby/rails3.0/loader_spec.rb +12 -12
  184. data/test/ruby/rails3.0/preloader_spec.rb +18 -18
  185. data/test/ruby/rails3.1/loader_spec.rb +12 -12
  186. data/test/ruby/rails3.1/preloader_spec.rb +18 -18
  187. data/test/ruby/rails3.2/loader_spec.rb +12 -12
  188. data/test/ruby/rails3.2/preloader_spec.rb +18 -18
  189. data/test/ruby/rails4.0/loader_spec.rb +12 -12
  190. data/test/ruby/rails4.0/preloader_spec.rb +18 -18
  191. data/test/ruby/rails4.1/loader_spec.rb +12 -12
  192. data/test/ruby/rails4.1/preloader_spec.rb +18 -18
  193. data/test/ruby/request_handler_spec.rb +730 -730
  194. data/test/ruby/shared/loader_sharedspec.rb +224 -224
  195. data/test/ruby/shared/rails/union_station_extensions_sharedspec.rb +327 -327
  196. data/test/ruby/shared/ruby_loader_sharedspec.rb +47 -47
  197. data/test/ruby/spec_helper.rb +65 -65
  198. data/test/ruby/standalone/runtime_installer_spec.rb +384 -384
  199. data/test/ruby/union_station_spec.rb +276 -276
  200. data/test/ruby/utils/file_system_watcher_spec.rb +220 -220
  201. data/test/ruby/utils/hosts_file_parser.rb +248 -248
  202. data/test/ruby/utils/tee_input_spec.rb +215 -215
  203. data/test/ruby/utils/unseekable_socket_spec.rb +57 -57
  204. data/test/ruby/utils_spec.rb +21 -21
  205. data/test/stub/rack/config.ru +87 -87
  206. data/test/stub/rack/library.rb +8 -8
  207. data/test/stub/rack/start.rb +30 -30
  208. data/test/support/apache2_controller.rb +191 -191
  209. data/test/support/nginx_controller.rb +90 -99
  210. data/test/support/placebo-preloader.rb +57 -57
  211. data/test/support/test_helper.rb +435 -435
  212. metadata +11 -21
  213. metadata.gz.asc +7 -7
  214. data/lib/phusion_passenger/standalone/command2.rb +0 -292
  215. data/lib/phusion_passenger/standalone/start2_command.rb +0 -799
  216. data/resources/templates/standalone/download_tool_missing.txt.erb +0 -18
  217. data/resources/templates/standalone/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -17
  218. data/resources/templates/standalone/run_installer_as_root.txt.erb +0 -8
@@ -37,443 +37,443 @@ require 'etc'
37
37
 
38
38
  module PhusionPassenger
39
39
 
40
- # Abstract base class for text mode installers. Used by
41
- # passenger-install-apache2-module and passenger-install-nginx-module.
42
- #
43
- # Subclasses must at least implement the #run_steps method which handles
44
- # the installation itself.
45
- #
46
- # Usage:
47
- #
48
- # installer = ConcereteInstallerClass.new(options...)
49
- # installer.run
50
- class AbstractInstaller
51
- PASSENGER_WEBSITE = "https://www.phusionpassenger.com"
52
- PHUSION_WEBSITE = "www.phusion.nl"
53
-
54
- # Create an AbstractInstaller. All options will be stored as instance
55
- # variables, for example:
56
- #
57
- # installer = AbstractInstaller.new(:foo => "bar")
58
- # installer.instance_variable_get(:"@foo") # => "bar"
59
- def initialize(options = {})
60
- @stdout = STDOUT
61
- @stderr = STDERR
62
- @auto = !STDIN.tty?
63
- @colors = Utils::AnsiColors.new(options[:colorize] || :auto)
64
- options.each_pair do |key, value|
65
- instance_variable_set(:"@#{key}", value)
66
- end
67
- end
68
-
69
- # Start the installation by calling the #install! method.
70
- def run
71
- before_install
72
- run_steps
73
- return true
74
- rescue Abort
75
- puts
76
- return false
77
- rescue SignalException, SystemExit
78
- raise
79
- rescue PlatformInfo::RuntimeError => e
80
- new_screen
81
- puts "<red>An error occurred</red>"
82
- puts
83
- puts e.message
84
- exit 1
85
- rescue Exception => e
86
- show_support_options_for_installer_bug(e)
87
- exit 2
88
- ensure
89
- after_install
90
- end
91
-
92
- protected
93
- class Abort < StandardError
94
- end
95
-
96
- class CommandError < Abort
97
- end
98
-
99
-
100
- def interactive?
101
- return !@auto
102
- end
103
-
104
- def non_interactive?
105
- return !interactive?
106
- end
107
-
108
-
109
- def before_install
110
- if STDOUT.respond_to?(:set_encoding)
111
- STDOUT.set_encoding("UTF-8")
112
- end
113
- STDOUT.write(@colors.default_terminal_color)
114
- STDOUT.flush
115
- end
116
-
117
- def after_install
118
- STDOUT.write(@colors.reset)
119
- STDOUT.flush
120
- end
121
-
122
- def users_guide_path
123
- return PhusionPassenger.index_doc_path
124
- end
125
-
126
- def users_guide_url
127
- return INDEX_DOC_URL
128
- end
129
-
130
- def dependencies
131
- return [[], []]
132
- end
133
-
134
- def check_dependencies(show_new_screen = true)
135
- new_screen if show_new_screen
136
- puts "<banner>Checking for required software...</banner>"
137
- puts
138
-
139
- PhusionPassenger.require_passenger_lib 'platform_info/depcheck'
140
- specs, ids = dependencies
141
- runner = PlatformInfo::Depcheck::ConsoleRunner.new
142
-
143
- specs.each do |spec|
144
- PlatformInfo::Depcheck.load(spec)
145
- end
146
- ids.each do |id|
147
- runner.add(id)
148
- end
149
-
150
- if runner.check_all
151
- return true
152
- else
153
- puts
154
- puts "<red>Some required software is not installed.</red>"
155
- puts "But don't worry, this installer will tell you how to install them.\n"
156
- puts "<b>Press Enter to continue, or Ctrl-C to abort.</b>"
157
- if PhusionPassenger.originally_packaged?
158
- wait
159
- else
160
- wait(10)
161
- end
162
-
163
- line
164
- puts
165
- puts "<banner>Installation instructions for required software</banner>"
166
- puts
167
- runner.missing_dependencies.each do |dep|
168
- puts " * To install <yellow>#{dep.name}</yellow>:"
169
- puts " #{dep.install_instructions}"
170
- puts
171
- end
172
- puts "If the aforementioned instructions didn't solve your problem, then please take"
173
- puts "a look at the Users Guide:"
174
- puts
175
- puts " <yellow>#{users_guide_path}</yellow>"
176
- puts " <yellow>#{users_guide_url}</yellow>"
177
- return false
178
- end
179
- end
180
-
181
- def check_whether_os_is_broken
182
- # No known broken OSes at the moment.
183
- end
184
-
185
- def check_gem_install_permission_problems
186
- return true if PhusionPassenger.custom_packaged?
187
- begin
188
- require 'rubygems'
189
- rescue LoadError
190
- return true
191
- end
192
-
193
- if Process.uid != 0 &&
194
- PhusionPassenger.build_system_dir =~ /^#{Regexp.escape home_dir}\// &&
195
- PhusionPassenger.build_system_dir =~ /^#{Regexp.escape Gem.dir}\// &&
196
- File.stat(PhusionPassenger.build_system_dir).uid == 0
197
- new_screen
198
- render_template 'installer_common/gem_install_permission_problems'
199
- return false
200
- else
201
- return true
202
- end
203
- end
204
-
205
- def check_directory_accessible_by_web_server
206
- return true if PhusionPassenger.custom_packaged?
207
- inaccessible_directories = []
208
- list_parent_directories(PhusionPassenger.build_system_dir).each do |path|
209
- if !world_executable?(path)
210
- inaccessible_directories << path
211
- end
212
- end
213
- if !inaccessible_directories.empty?
214
- new_screen
215
- render_template 'installer_common/world_inaccessible_directories',
216
- :directories => inaccessible_directories
217
- wait
218
- end
219
- end
220
-
221
- def check_whether_system_has_enough_ram(required = 1024)
222
- begin
223
- meminfo = File.read("/proc/meminfo")
224
- if meminfo =~ /^MemTotal: *(\d+) kB$/
225
- ram_mb = $1.to_i / 1024
226
- if meminfo =~ /^SwapTotal: *(\d+) kB$/
227
- swap_mb = $1.to_i / 1024
228
- else
229
- swap_mb = 0
230
- end
231
- end
232
- rescue Errno::ENOENT, Errno::EACCES
233
- # Don't do anything on systems without memory information.
234
- ram_mb = nil
235
- swap_mb = nil
236
- end
237
- if ram_mb && swap_mb && ram_mb + swap_mb < required
238
- new_screen
239
- render_template 'installer_common/low_amount_of_memory_warning',
240
- :required => required,
241
- :current => ram_mb + swap_mb,
242
- :ram => ram_mb,
243
- :swap => swap_mb,
244
- :doc_path => users_guide_path,
245
- :doc_url => users_guide_url
246
- wait
247
- end
248
- end
249
-
250
- def show_support_options_for_installer_bug(e)
251
- # We do not use template rendering here. Since we've determined that there's
252
- # a bug, *anything* may be broken, so we use the safest codepath to ensure that
253
- # the user sees the proper messages.
254
- begin
255
- line
256
- @stderr.puts "*** EXCEPTION: #{e} (#{e.class})\n " +
257
- e.backtrace.join("\n ")
258
- new_screen
259
- puts '<red>Oops, something went wrong :-(</red>'
260
- puts
261
- puts "We're sorry, but it looks like this installer ran into an unexpected problem.\n" +
262
- "Please visit the following website for support. We'll do our best to help you.\n\n" +
263
- " <b>#{SUPPORT_URL}</b>\n\n" +
264
- "When submitting a support inquiry, please copy and paste the entire installer\n" +
265
- "output."
266
- rescue Exception => e2
267
- # Raise original exception so that it doesn't get lost.
268
- raise e
269
- end
270
- end
271
-
272
-
273
- def use_stderr
274
- old_stdout = @stdout
275
- begin
276
- @stdout = @stderr
277
- yield
278
- ensure
279
- @stdout = old_stdout
280
- end
281
- end
282
-
283
- def print(text)
284
- @stdout.write(@colors.ansi_colorize(text))
285
- @stdout.flush
286
- end
287
-
288
- def puts(text = nil)
289
- if text
290
- @stdout.puts(@colors.ansi_colorize(text.to_s))
291
- else
292
- @stdout.puts
293
- end
294
- @stdout.flush
295
- end
296
-
297
- def puts_error(text)
298
- @stderr.puts(@colors.ansi_colorize("<red>#{text}</red>"))
299
- @stderr.flush
300
- end
301
-
302
- def render_template(name, options = {})
303
- options.merge!(:colors => @colors)
304
- puts ConsoleTextTemplate.new({ :file => name }, options).result
305
- end
306
-
307
- def new_screen
308
- puts
309
- line
310
- puts
311
- end
312
-
313
- def line
314
- puts "--------------------------------------------"
315
- end
316
-
317
- def prompt(message, default_value = nil)
318
- done = false
319
- while !done
320
- print "#{message}: "
321
-
322
- if non_interactive? && default_value
323
- puts default_value
324
- return default_value
325
- end
326
-
327
- begin
328
- result = STDIN.readline
329
- rescue EOFError
330
- exit 2
331
- end
332
- result.strip!
333
- if result.empty?
334
- if default_value
335
- result = default_value
336
- done = true
337
- else
338
- done = !block_given? || yield(result)
339
- end
340
- else
341
- done = !block_given? || yield(result)
342
- end
343
- end
344
- return result
345
- rescue Interrupt
346
- raise Abort
347
- end
348
-
349
- def prompt_confirmation(message)
350
- result = prompt("#{message} [y/n]") do |value|
351
- if value.downcase == 'y' || value.downcase == 'n'
352
- true
353
- else
354
- puts_error "Invalid input '#{value}'; please enter either 'y' or 'n'."
355
- false
356
- end
357
- end
358
- return result.downcase == 'y'
359
- rescue Interrupt
360
- raise Abort
361
- end
362
-
363
- def prompt_confirmation_with_default(message, default)
364
- if default
365
- default_str = "[Y/n]"
366
- else
367
- default_str = "[y/N]"
368
- end
369
- result = prompt("#{message} #{default_str}") do |value|
370
- if value.downcase == 'y' || value.downcase == 'n'
371
- true
372
- elsif value.empty?
373
- true
374
- else
375
- puts_error "Invalid input '#{value}'; please enter either 'y' or 'n'."
376
- false
377
- end
378
- end
379
- if result.empty?
380
- return default
381
- else
382
- return result.downcase == 'y'
383
- end
384
- rescue Interrupt
385
- raise Abort
386
- end
387
-
388
- def wait(timeout = nil)
389
- if interactive?
390
- if timeout
391
- require 'timeout' unless defined?(Timeout)
392
- begin
393
- Timeout.timeout(timeout) do
394
- STDIN.readline
395
- end
396
- rescue Timeout::Error
397
- # Do nothing.
398
- end
399
- else
400
- STDIN.readline
401
- end
402
- end
403
- rescue Interrupt
404
- raise Abort
405
- end
406
-
407
- def home_dir
408
- return PhusionPassenger.home_dir
409
- end
410
-
411
-
412
- def sh(*args)
413
- puts "# #{args.join(' ')}"
414
- result = system(*args)
415
- if result
416
- return true
417
- elsif $?.signaled? && $?.termsig == Signal.list["INT"]
418
- raise Interrupt
419
- else
420
- return false
421
- end
422
- end
423
-
424
- def sh!(*args)
425
- if !sh(*args)
426
- puts_error "*** Command failed: #{args.join(' ')}"
427
- raise CommandError
428
- end
429
- end
430
-
431
- def rake(*args)
432
- PhusionPassenger.require_passenger_lib 'platform_info/ruby'
433
- if !PlatformInfo.rake_command
434
- puts_error 'Cannot find Rake.'
435
- raise Abort
436
- end
437
- sh("#{PlatformInfo.rake_command} #{args.join(' ')}")
438
- end
439
-
440
- def rake!(*args)
441
- PhusionPassenger.require_passenger_lib 'platform_info/ruby'
442
- if !PlatformInfo.rake_command
443
- puts_error 'Cannot find Rake.'
444
- raise Abort
445
- end
446
- sh!("#{PlatformInfo.rake_command} #{args.join(' ')}")
447
- end
448
-
449
- def download(url, output, options = {})
450
- options[:logger] ||= begin
451
- logger = Logger.new(STDOUT)
452
- logger.level = Logger::WARN
453
- logger.formatter = proc { |severity, datetime, progname, msg| "*** #{msg}\n" }
454
- logger
455
- end
456
- return PhusionPassenger::Utils::Download.download(url, output, options)
457
- end
458
-
459
- def list_parent_directories(dir)
460
- dirs = []
461
- components = File.expand_path(dir).split(File::SEPARATOR)
462
- components.shift # Remove leading /
463
- components.size.times do |i|
464
- dirs << File::SEPARATOR + components[0 .. i].join(File::SEPARATOR)
465
- end
466
- return dirs.reverse
467
- end
468
-
469
- def world_executable?(dir)
470
- begin
471
- stat = File.stat(dir)
472
- rescue Errno::EACCESS
473
- return false
474
- end
475
- return stat.mode & 0000001 != 0
476
- end
477
- end
40
+ # Abstract base class for text mode installers. Used by
41
+ # passenger-install-apache2-module and passenger-install-nginx-module.
42
+ #
43
+ # Subclasses must at least implement the #run_steps method which handles
44
+ # the installation itself.
45
+ #
46
+ # Usage:
47
+ #
48
+ # installer = ConcereteInstallerClass.new(options...)
49
+ # installer.run
50
+ class AbstractInstaller
51
+ PASSENGER_WEBSITE = "https://www.phusionpassenger.com"
52
+ PHUSION_WEBSITE = "www.phusion.nl"
53
+
54
+ # Create an AbstractInstaller. All options will be stored as instance
55
+ # variables, for example:
56
+ #
57
+ # installer = AbstractInstaller.new(:foo => "bar")
58
+ # installer.instance_variable_get(:"@foo") # => "bar"
59
+ def initialize(options = {})
60
+ @stdout = STDOUT
61
+ @stderr = STDERR
62
+ @auto = !STDIN.tty?
63
+ @colors = Utils::AnsiColors.new(options[:colorize] || :auto)
64
+ options.each_pair do |key, value|
65
+ instance_variable_set(:"@#{key}", value)
66
+ end
67
+ end
68
+
69
+ # Start the installation by calling the #install! method.
70
+ def run
71
+ before_install
72
+ run_steps
73
+ return true
74
+ rescue Abort
75
+ puts
76
+ return false
77
+ rescue SignalException, SystemExit
78
+ raise
79
+ rescue PlatformInfo::RuntimeError => e
80
+ new_screen
81
+ puts "<red>An error occurred</red>"
82
+ puts
83
+ puts e.message
84
+ exit 1
85
+ rescue Exception => e
86
+ show_support_options_for_installer_bug(e)
87
+ exit 2
88
+ ensure
89
+ after_install
90
+ end
91
+
92
+ protected
93
+ class Abort < StandardError
94
+ end
95
+
96
+ class CommandError < Abort
97
+ end
98
+
99
+
100
+ def interactive?
101
+ return !@auto
102
+ end
103
+
104
+ def non_interactive?
105
+ return !interactive?
106
+ end
107
+
108
+
109
+ def before_install
110
+ if STDOUT.respond_to?(:set_encoding)
111
+ STDOUT.set_encoding("UTF-8")
112
+ end
113
+ STDOUT.write(@colors.default_terminal_color)
114
+ STDOUT.flush
115
+ end
116
+
117
+ def after_install
118
+ STDOUT.write(@colors.reset)
119
+ STDOUT.flush
120
+ end
121
+
122
+ def users_guide_path
123
+ return PhusionPassenger.index_doc_path
124
+ end
125
+
126
+ def users_guide_url
127
+ return INDEX_DOC_URL
128
+ end
129
+
130
+ def dependencies
131
+ return [[], []]
132
+ end
133
+
134
+ def check_dependencies(show_new_screen = true)
135
+ new_screen if show_new_screen
136
+ puts "<banner>Checking for required software...</banner>"
137
+ puts
138
+
139
+ PhusionPassenger.require_passenger_lib 'platform_info/depcheck'
140
+ specs, ids = dependencies
141
+ runner = PlatformInfo::Depcheck::ConsoleRunner.new
142
+
143
+ specs.each do |spec|
144
+ PlatformInfo::Depcheck.load(spec)
145
+ end
146
+ ids.each do |id|
147
+ runner.add(id)
148
+ end
149
+
150
+ if runner.check_all
151
+ return true
152
+ else
153
+ puts
154
+ puts "<red>Some required software is not installed.</red>"
155
+ puts "But don't worry, this installer will tell you how to install them.\n"
156
+ puts "<b>Press Enter to continue, or Ctrl-C to abort.</b>"
157
+ if PhusionPassenger.originally_packaged?
158
+ wait
159
+ else
160
+ wait(10)
161
+ end
162
+
163
+ line
164
+ puts
165
+ puts "<banner>Installation instructions for required software</banner>"
166
+ puts
167
+ runner.missing_dependencies.each do |dep|
168
+ puts " * To install <yellow>#{dep.name}</yellow>:"
169
+ puts " #{dep.install_instructions}"
170
+ puts
171
+ end
172
+ puts "If the aforementioned instructions didn't solve your problem, then please take"
173
+ puts "a look at the Users Guide:"
174
+ puts
175
+ puts " <yellow>#{users_guide_path}</yellow>"
176
+ puts " <yellow>#{users_guide_url}</yellow>"
177
+ return false
178
+ end
179
+ end
180
+
181
+ def check_whether_os_is_broken
182
+ # No known broken OSes at the moment.
183
+ end
184
+
185
+ def check_gem_install_permission_problems
186
+ return true if PhusionPassenger.custom_packaged?
187
+ begin
188
+ require 'rubygems'
189
+ rescue LoadError
190
+ return true
191
+ end
192
+
193
+ if Process.uid != 0 &&
194
+ PhusionPassenger.build_system_dir =~ /^#{Regexp.escape home_dir}\// &&
195
+ PhusionPassenger.build_system_dir =~ /^#{Regexp.escape Gem.dir}\// &&
196
+ File.stat(PhusionPassenger.build_system_dir).uid == 0
197
+ new_screen
198
+ render_template 'installer_common/gem_install_permission_problems'
199
+ return false
200
+ else
201
+ return true
202
+ end
203
+ end
204
+
205
+ def check_directory_accessible_by_web_server
206
+ return true if PhusionPassenger.custom_packaged?
207
+ inaccessible_directories = []
208
+ list_parent_directories(PhusionPassenger.build_system_dir).each do |path|
209
+ if !world_executable?(path)
210
+ inaccessible_directories << path
211
+ end
212
+ end
213
+ if !inaccessible_directories.empty?
214
+ new_screen
215
+ render_template 'installer_common/world_inaccessible_directories',
216
+ :directories => inaccessible_directories
217
+ wait
218
+ end
219
+ end
220
+
221
+ def check_whether_system_has_enough_ram(required = 1024)
222
+ begin
223
+ meminfo = File.read("/proc/meminfo")
224
+ if meminfo =~ /^MemTotal: *(\d+) kB$/
225
+ ram_mb = $1.to_i / 1024
226
+ if meminfo =~ /^SwapTotal: *(\d+) kB$/
227
+ swap_mb = $1.to_i / 1024
228
+ else
229
+ swap_mb = 0
230
+ end
231
+ end
232
+ rescue Errno::ENOENT, Errno::EACCES
233
+ # Don't do anything on systems without memory information.
234
+ ram_mb = nil
235
+ swap_mb = nil
236
+ end
237
+ if ram_mb && swap_mb && ram_mb + swap_mb < required
238
+ new_screen
239
+ render_template 'installer_common/low_amount_of_memory_warning',
240
+ :required => required,
241
+ :current => ram_mb + swap_mb,
242
+ :ram => ram_mb,
243
+ :swap => swap_mb,
244
+ :doc_path => users_guide_path,
245
+ :doc_url => users_guide_url
246
+ wait
247
+ end
248
+ end
249
+
250
+ def show_support_options_for_installer_bug(e)
251
+ # We do not use template rendering here. Since we've determined that there's
252
+ # a bug, *anything* may be broken, so we use the safest codepath to ensure that
253
+ # the user sees the proper messages.
254
+ begin
255
+ line
256
+ @stderr.puts "*** EXCEPTION: #{e} (#{e.class})\n " +
257
+ e.backtrace.join("\n ")
258
+ new_screen
259
+ puts '<red>Oops, something went wrong :-(</red>'
260
+ puts
261
+ puts "We're sorry, but it looks like this installer ran into an unexpected problem.\n" +
262
+ "Please visit the following website for support. We'll do our best to help you.\n\n" +
263
+ " <b>#{SUPPORT_URL}</b>\n\n" +
264
+ "When submitting a support inquiry, please copy and paste the entire installer\n" +
265
+ "output."
266
+ rescue Exception => e2
267
+ # Raise original exception so that it doesn't get lost.
268
+ raise e
269
+ end
270
+ end
271
+
272
+
273
+ def use_stderr
274
+ old_stdout = @stdout
275
+ begin
276
+ @stdout = @stderr
277
+ yield
278
+ ensure
279
+ @stdout = old_stdout
280
+ end
281
+ end
282
+
283
+ def print(text)
284
+ @stdout.write(@colors.ansi_colorize(text))
285
+ @stdout.flush
286
+ end
287
+
288
+ def puts(text = nil)
289
+ if text
290
+ @stdout.puts(@colors.ansi_colorize(text.to_s))
291
+ else
292
+ @stdout.puts
293
+ end
294
+ @stdout.flush
295
+ end
296
+
297
+ def puts_error(text)
298
+ @stderr.puts(@colors.ansi_colorize("<red>#{text}</red>"))
299
+ @stderr.flush
300
+ end
301
+
302
+ def render_template(name, options = {})
303
+ options.merge!(:colors => @colors)
304
+ puts ConsoleTextTemplate.new({ :file => name }, options).result
305
+ end
306
+
307
+ def new_screen
308
+ puts
309
+ line
310
+ puts
311
+ end
312
+
313
+ def line
314
+ puts "--------------------------------------------"
315
+ end
316
+
317
+ def prompt(message, default_value = nil)
318
+ done = false
319
+ while !done
320
+ print "#{message}: "
321
+
322
+ if non_interactive? && default_value
323
+ puts default_value
324
+ return default_value
325
+ end
326
+
327
+ begin
328
+ result = STDIN.readline
329
+ rescue EOFError
330
+ exit 2
331
+ end
332
+ result.strip!
333
+ if result.empty?
334
+ if default_value
335
+ result = default_value
336
+ done = true
337
+ else
338
+ done = !block_given? || yield(result)
339
+ end
340
+ else
341
+ done = !block_given? || yield(result)
342
+ end
343
+ end
344
+ return result
345
+ rescue Interrupt
346
+ raise Abort
347
+ end
348
+
349
+ def prompt_confirmation(message)
350
+ result = prompt("#{message} [y/n]") do |value|
351
+ if value.downcase == 'y' || value.downcase == 'n'
352
+ true
353
+ else
354
+ puts_error "Invalid input '#{value}'; please enter either 'y' or 'n'."
355
+ false
356
+ end
357
+ end
358
+ return result.downcase == 'y'
359
+ rescue Interrupt
360
+ raise Abort
361
+ end
362
+
363
+ def prompt_confirmation_with_default(message, default)
364
+ if default
365
+ default_str = "[Y/n]"
366
+ else
367
+ default_str = "[y/N]"
368
+ end
369
+ result = prompt("#{message} #{default_str}") do |value|
370
+ if value.downcase == 'y' || value.downcase == 'n'
371
+ true
372
+ elsif value.empty?
373
+ true
374
+ else
375
+ puts_error "Invalid input '#{value}'; please enter either 'y' or 'n'."
376
+ false
377
+ end
378
+ end
379
+ if result.empty?
380
+ return default
381
+ else
382
+ return result.downcase == 'y'
383
+ end
384
+ rescue Interrupt
385
+ raise Abort
386
+ end
387
+
388
+ def wait(timeout = nil)
389
+ if interactive?
390
+ if timeout
391
+ require 'timeout' unless defined?(Timeout)
392
+ begin
393
+ Timeout.timeout(timeout) do
394
+ STDIN.readline
395
+ end
396
+ rescue Timeout::Error
397
+ # Do nothing.
398
+ end
399
+ else
400
+ STDIN.readline
401
+ end
402
+ end
403
+ rescue Interrupt
404
+ raise Abort
405
+ end
406
+
407
+ def home_dir
408
+ return PhusionPassenger.home_dir
409
+ end
410
+
411
+
412
+ def sh(*args)
413
+ puts "# #{args.join(' ')}"
414
+ result = system(*args)
415
+ if result
416
+ return true
417
+ elsif $?.signaled? && $?.termsig == Signal.list["INT"]
418
+ raise Interrupt
419
+ else
420
+ return false
421
+ end
422
+ end
423
+
424
+ def sh!(*args)
425
+ if !sh(*args)
426
+ puts_error "*** Command failed: #{args.join(' ')}"
427
+ raise CommandError
428
+ end
429
+ end
430
+
431
+ def rake(*args)
432
+ PhusionPassenger.require_passenger_lib 'platform_info/ruby'
433
+ if !PlatformInfo.rake_command
434
+ puts_error 'Cannot find Rake.'
435
+ raise Abort
436
+ end
437
+ sh("#{PlatformInfo.rake_command} #{args.join(' ')}")
438
+ end
439
+
440
+ def rake!(*args)
441
+ PhusionPassenger.require_passenger_lib 'platform_info/ruby'
442
+ if !PlatformInfo.rake_command
443
+ puts_error 'Cannot find Rake.'
444
+ raise Abort
445
+ end
446
+ sh!("#{PlatformInfo.rake_command} #{args.join(' ')}")
447
+ end
448
+
449
+ def download(url, output, options = {})
450
+ options[:logger] ||= begin
451
+ logger = Logger.new(STDOUT)
452
+ logger.level = Logger::WARN
453
+ logger.formatter = proc { |severity, datetime, progname, msg| "*** #{msg}\n" }
454
+ logger
455
+ end
456
+ return PhusionPassenger::Utils::Download.download(url, output, options)
457
+ end
458
+
459
+ def list_parent_directories(dir)
460
+ dirs = []
461
+ components = File.expand_path(dir).split(File::SEPARATOR)
462
+ components.shift # Remove leading /
463
+ components.size.times do |i|
464
+ dirs << File::SEPARATOR + components[0 .. i].join(File::SEPARATOR)
465
+ end
466
+ return dirs.reverse
467
+ end
468
+
469
+ def world_executable?(dir)
470
+ begin
471
+ stat = File.stat(dir)
472
+ rescue Errno::EACCESS
473
+ return false
474
+ end
475
+ return stat.mode & 0000001 != 0
476
+ end
477
+ end
478
478
 
479
479
  end # module PhusionPassenger