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
@@ -6,376 +6,376 @@ PhusionPassenger.require_passenger_lib 'platform_info/operating_system'
6
6
  PhusionPassenger.require_passenger_lib 'utils/ansi_colors'
7
7
 
8
8
  module PhusionPassenger
9
- module PlatformInfo
10
-
11
- # Almost all software require other software in order to run. We call those
12
- # other software 'dependencies'. Reliably checking for dependencies can be
13
- # difficult. Helping the user in case a dependency is not installed (or
14
- # doesn't seem to be installed) is more difficult still.
15
- #
16
- # The Depcheck framework seeks to make all this easier. It allows the programmer
17
- # to write "specs" which contain dependency checking code in a structured way.
18
- # The programmer defines a dependency's basic information (name, website, etc),
19
- # defines installation instructions (which may be customized per platform) and
20
- # defines code for checking whether the dependency actually exists. The Depcheck
21
- # framework:
22
- #
23
- # * Provides helpers for checking for the existance of commands, libraries,
24
- # headers, etc.
25
- # * Registers all dependency specs in a way that can be easily accessed
26
- # structurally.
27
- # * Allows user-friendly display of dependency checking progress and user help
28
- # instructions.
29
- #
30
- # Most dependency checking code (e.g. autoconf) is very straightforward: they
31
- # just check for the existance of a command, library, header, etc and either
32
- # report "found" or "not found". In our experience the world is unfortunately
33
- # not that simple. Users can have multiple versions of a dependency installed,
34
- # where some dependencies are suitable while others are not. Therefore specs
35
- # should print as many details about the dependency as possible (location, version,
36
- # etc) so that the user can override any decisions if necessary.
37
- module Depcheck
38
- THIS_DIR = File.expand_path(File.dirname(__FILE__))
39
- @@loaded = {}
40
- @@database = {}
41
-
42
- def self.load(partial_filename)
43
- if !@@loaded[partial_filename]
44
- filename = "#{THIS_DIR}/#{partial_filename}.rb"
45
- content = File.read(filename)
46
- instance_eval(content, filename)
47
- @@loaded[partial_filename] = true
48
- end
49
- end
50
-
51
- def self.define(identifier, &block)
52
- @@database[identifier.to_s] = block
53
- end
54
-
55
- def self.find(identifier)
56
- # We lazy-initialize everything in order to save resources. This also
57
- # allows blocks to perform relatively expensive checks without hindering
58
- # startup time.
59
- identifier = identifier.to_s
60
- result = @@database[identifier]
61
- if result.is_a?(Proc)
62
- result = Dependency.new(&result)
63
- @@database[identifier] = result
64
- end
65
- result
66
- end
67
-
68
- class Dependency
69
- def initialize(&block)
70
- instance_eval(&block)
71
- check_syntax_aspect("Name must be given") { !!@name }
72
- check_syntax_aspect("A checker must be given") { !!@checker }
73
- end
74
-
75
- def check
76
- @install_comments = nil
77
- @check_result ||= @checker.call
78
- end
79
-
80
- ### DSL for specs ###
81
-
82
- def name(value = nil)
83
- value ? @name = value : @name
84
- end
85
-
86
- def website(value = nil)
87
- value ? @website = value : @website
88
- end
89
-
90
- def website_comments(value = nil)
91
- value ? @website_comments = value : @website_comments
92
- end
93
-
94
- def install_instructions(value = nil)
95
- if value
96
- @install_instructions = value
97
- else
98
- if @install_instructions
99
- @install_instructions
100
- elsif @website
101
- result = "Please download it from <b>#{@website}</b>"
102
- result << "\n(#{@website_comments})" if @website_comments
103
- result
104
- else
105
- "Search Google for '#{@name}'."
106
- end
107
- end
108
- end
109
-
110
- def install_comments(value = nil)
111
- value ? @install_comments = value : @install_comments
112
- end
113
-
114
- private
115
- def check_syntax_aspect(description)
116
- if !yield
117
- raise description
118
- end
119
- end
120
-
121
- ### DSL for specs ###
122
-
123
- def define_checker(&block)
124
- @checker = block
125
- end
126
-
127
- def check_for_command(name, *args)
128
- result = find_command(name, *args)
129
- if result
130
- { :found => true,
131
- "Location" => result }
132
- else
133
- false
134
- end
135
- end
136
-
137
- def check_for_ruby_tool(name)
138
- result = locate_ruby_tool(name)
139
- if result
140
- { :found => true,
141
- "Location" => result }
142
- else
143
- false
144
- end
145
- end
146
-
147
- def check_for_header(header_name, language = :c, flags = nil)
148
- if result = PlatformInfo.find_header(header_name, language, flags)
149
- { :found => true,
150
- "Location" => result }
151
- else
152
- false
153
- end
154
- end
155
-
156
- # def check_for_library(name)
157
- # check_by_compiling("int main() { return 0; }", :cxx, nil, "-l#{name}")
158
- # end
159
-
160
- # def check_by_compiling(source, language = :c, cflags = nil, linkflags = nil)
161
- # case language
162
- # when :c
163
- # source_file = "#{PlatformInfo.tmpexedir}/depcheck-#{Process.pid}-#{Thread.current.object_id}.c"
164
- # compiler = "gcc"
165
- # compiler_flags = ENV['CFLAGS']
166
- # when :cxx
167
- # source_file = "#{PlatformInfo.tmpexedir}/depcheck-#{Process.pid}-#{Thread.current.object_id}.cpp"
168
- # compiler = "g++"
169
- # compiler_flags = "#{ENV['CFLAGS']} #{ENV['CXXFLAGS']}".strip
170
- # else
171
- # raise ArgumentError, "Unknown language '#{language}"
172
- # end
173
-
174
- # output_file = "#{PlatformInfo.tmpexedir}/depcheck-#{Process.pid}-#{Thread.current.object_id}"
175
-
176
- # begin
177
- # File.open(source_file, 'w') do |f|
178
- # f.puts(source)
179
- # end
180
-
181
- # if find_command(compiler)
182
- # command = "#{compiler} #{compiler_flags} #{cflags} " +
183
- # "#{source_file} -o #{output_file} #{linkflags}"
184
- # [!!system(command)]
185
- # else
186
- # [:unknown, "Cannot check: compiler '#{compiler}' not found."]
187
- # end
188
- # ensure
189
- # File.unlink(source_file) rescue nil
190
- # File.unlink(output_file) rescue nil
191
- # end
192
- # end
193
-
194
- def check_for_ruby_library(name)
195
- begin
196
- require(name)
197
- { :found => true }
198
- rescue LoadError
199
- if defined?(Gem)
200
- false
201
- else
202
- begin
203
- require 'rubygems'
204
- require(name)
205
- { :found => true }
206
- rescue LoadError
207
- false
208
- end
209
- end
210
- end
211
- end
212
-
213
- def on(platform)
214
- return if @on_invoked
215
- invoke = false
216
- if (linux_distro_tags || []).include?(platform)
217
- invoke = true
218
- else
219
- case platform
220
- when :linux
221
- invoke = true if PlatformInfo.os_name =~ /linux/
222
- when :freebsd
223
- invoke = true if PlatformInfo.os_name =~ /freebsd/
224
- when :macosx
225
- invoke = true if PlatformInfo.os_name == "macosx"
226
- when :solaris
227
- invoke = true if PlatformInfo.os_name =~ /solaris/
228
- when :other_platforms
229
- invoke = true
230
- end
231
- end
232
- if invoke
233
- yield
234
- @on_invoked = true
235
- end
236
- end
237
-
238
- def apt_get_install(package_name)
239
- install_instructions("Please install it with <b>apt-get install #{package_name}</b>")
240
- end
241
-
242
- def urpmi(package_name)
243
- install_instructions("Please install it with <b>urpmi #{package_name}</b>")
244
- end
245
-
246
- def yum_install(package_name, options = {})
247
- if options[:epel]
248
- install_instructions("Please enable <b>EPEL</b>, then install with <b>yum install #{package_name}</b>")
249
- else
250
- install_instructions("Please install it with <b>yum install #{package_name}</b>")
251
- end
252
- end
253
-
254
- def emerge(package_name)
255
- install_instructions("Please install it with <b>emerge -av #{package_name}</b>")
256
- end
257
-
258
- def gem_install(package_name)
259
- install_instructions("Please make sure RubyGems is installed, then run " +
260
- "<b>#{gem_command} install #{package_name}</b>")
261
- end
262
-
263
- def install_osx_command_line_tools
264
- PhusionPassenger.require_passenger_lib 'platform_info/compiler'
265
- if PlatformInfo.xcode_select_version.to_s >= "2333"
266
- install_instructions "Please install the Xcode command line tools: " +
267
- "<b>sudo xcode-select --install</b>"
268
- else
269
- install_instructions "Please install Xcode, then install the command line tools " +
270
- "though the menu <b>Xcode -> Preferences -> Downloads -> Components</b>"
271
- end
272
- end
273
-
274
-
275
- def ruby_command
276
- PlatformInfo.ruby_command
277
- end
278
-
279
- def gem_command
280
- PlatformInfo.gem_command(:sudo => true) || 'gem'
281
- end
282
-
283
- def find_command(command, *args)
284
- PlatformInfo.find_command(command, *args)
285
- end
286
-
287
- def linux_distro_tags
288
- PlatformInfo.linux_distro_tags
289
- end
290
-
291
- def locate_ruby_tool(name)
292
- PlatformInfo.locate_ruby_tool(name)
293
- end
294
- end # class Dependency
295
-
296
- class ConsoleRunner
297
- attr_reader :missing_dependencies
298
-
299
- def initialize
300
- @stdout = STDOUT
301
- @dep_identifiers = []
302
- end
303
-
304
- def add(identifier)
305
- @dep_identifiers << identifier
306
- end
307
-
308
- def check_all
309
- old_log_impl = PlatformInfo.log_implementation
310
- begin
311
- PlatformInfo.log_implementation = lambda do |message|
312
- message = PlatformInfo.send(:reindent, message, 10)
313
- message.sub!(/^ /, '')
314
- STDOUT.puts " -> #{message}"
315
- end
316
- @missing_dependencies = []
317
- @dep_identifiers.each do |identifier|
318
- dep = Depcheck.find(identifier)
319
- raise "Cannot find depcheck spec #{identifier.inspect}" if !dep
320
- puts_header "Checking for #{dep.name}..."
321
- result = dep.check
322
- result = { :found => false } if !result
323
-
324
- if result[:found] && !result[:error]
325
- puts_detail "Found: <green>yes</green>"
326
- else
327
- if result[:error]
328
- puts_detail "Found: #{result[:found] ? "<yellow>yes, but there was an error</yellow>" : "<red>no</red>"}"
329
- puts_detail "Error: <red>#{result[:error]}</red>"
330
- else
331
- puts_detail "Found: #{result[:found] ? "<green>yes</green>" : "<red>no</red>"}"
332
- end
333
- @missing_dependencies << dep
334
- end
335
-
336
- result.each_pair do |key, value|
337
- if key.is_a?(String)
338
- puts_detail "#{key}: #{value}"
339
- end
340
- end
341
- end
342
-
343
- return @missing_dependencies.empty?
344
- ensure
345
- PlatformInfo.log_implementation = old_log_impl
346
- end
347
- end
348
-
349
- def print_installation_instructions_for_missing_dependencies
350
- @missing_dependencies.each do |dep|
351
- puts " * To install <yellow>#{dep.name}</yellow>:"
352
- puts " #{dep.install_instructions}"
353
- if dep.install_comments
354
- puts " #{dep.install_comments}"
355
- end
356
- puts
357
- end
358
- end
359
-
360
- private
361
- def puts(text = nil)
362
- if text
363
- @stdout.puts(Utils::AnsiColors.ansi_colorize(text))
364
- else
365
- @stdout.puts
366
- end
367
- @stdout.flush
368
- end
369
-
370
- def puts_header(text)
371
- puts " <b>* #{text}</b>"
372
- end
373
-
374
- def puts_detail(text)
375
- puts " #{text}"
376
- end
377
- end
378
- end # module Depcheck
379
-
380
- end # module PlatformInfo
9
+ module PlatformInfo
10
+
11
+ # Almost all software require other software in order to run. We call those
12
+ # other software 'dependencies'. Reliably checking for dependencies can be
13
+ # difficult. Helping the user in case a dependency is not installed (or
14
+ # doesn't seem to be installed) is more difficult still.
15
+ #
16
+ # The Depcheck framework seeks to make all this easier. It allows the programmer
17
+ # to write "specs" which contain dependency checking code in a structured way.
18
+ # The programmer defines a dependency's basic information (name, website, etc),
19
+ # defines installation instructions (which may be customized per platform) and
20
+ # defines code for checking whether the dependency actually exists. The Depcheck
21
+ # framework:
22
+ #
23
+ # * Provides helpers for checking for the existance of commands, libraries,
24
+ # headers, etc.
25
+ # * Registers all dependency specs in a way that can be easily accessed
26
+ # structurally.
27
+ # * Allows user-friendly display of dependency checking progress and user help
28
+ # instructions.
29
+ #
30
+ # Most dependency checking code (e.g. autoconf) is very straightforward: they
31
+ # just check for the existance of a command, library, header, etc and either
32
+ # report "found" or "not found". In our experience the world is unfortunately
33
+ # not that simple. Users can have multiple versions of a dependency installed,
34
+ # where some dependencies are suitable while others are not. Therefore specs
35
+ # should print as many details about the dependency as possible (location, version,
36
+ # etc) so that the user can override any decisions if necessary.
37
+ module Depcheck
38
+ THIS_DIR = File.expand_path(File.dirname(__FILE__))
39
+ @@loaded = {}
40
+ @@database = {}
41
+
42
+ def self.load(partial_filename)
43
+ if !@@loaded[partial_filename]
44
+ filename = "#{THIS_DIR}/#{partial_filename}.rb"
45
+ content = File.read(filename)
46
+ instance_eval(content, filename)
47
+ @@loaded[partial_filename] = true
48
+ end
49
+ end
50
+
51
+ def self.define(identifier, &block)
52
+ @@database[identifier.to_s] = block
53
+ end
54
+
55
+ def self.find(identifier)
56
+ # We lazy-initialize everything in order to save resources. This also
57
+ # allows blocks to perform relatively expensive checks without hindering
58
+ # startup time.
59
+ identifier = identifier.to_s
60
+ result = @@database[identifier]
61
+ if result.is_a?(Proc)
62
+ result = Dependency.new(&result)
63
+ @@database[identifier] = result
64
+ end
65
+ result
66
+ end
67
+
68
+ class Dependency
69
+ def initialize(&block)
70
+ instance_eval(&block)
71
+ check_syntax_aspect("Name must be given") { !!@name }
72
+ check_syntax_aspect("A checker must be given") { !!@checker }
73
+ end
74
+
75
+ def check
76
+ @install_comments = nil
77
+ @check_result ||= @checker.call
78
+ end
79
+
80
+ ### DSL for specs ###
81
+
82
+ def name(value = nil)
83
+ value ? @name = value : @name
84
+ end
85
+
86
+ def website(value = nil)
87
+ value ? @website = value : @website
88
+ end
89
+
90
+ def website_comments(value = nil)
91
+ value ? @website_comments = value : @website_comments
92
+ end
93
+
94
+ def install_instructions(value = nil)
95
+ if value
96
+ @install_instructions = value
97
+ else
98
+ if @install_instructions
99
+ @install_instructions
100
+ elsif @website
101
+ result = "Please download it from <b>#{@website}</b>"
102
+ result << "\n(#{@website_comments})" if @website_comments
103
+ result
104
+ else
105
+ "Search Google for '#{@name}'."
106
+ end
107
+ end
108
+ end
109
+
110
+ def install_comments(value = nil)
111
+ value ? @install_comments = value : @install_comments
112
+ end
113
+
114
+ private
115
+ def check_syntax_aspect(description)
116
+ if !yield
117
+ raise description
118
+ end
119
+ end
120
+
121
+ ### DSL for specs ###
122
+
123
+ def define_checker(&block)
124
+ @checker = block
125
+ end
126
+
127
+ def check_for_command(name, *args)
128
+ result = find_command(name, *args)
129
+ if result
130
+ { :found => true,
131
+ "Location" => result }
132
+ else
133
+ false
134
+ end
135
+ end
136
+
137
+ def check_for_ruby_tool(name)
138
+ result = locate_ruby_tool(name)
139
+ if result
140
+ { :found => true,
141
+ "Location" => result }
142
+ else
143
+ false
144
+ end
145
+ end
146
+
147
+ def check_for_header(header_name, language = :c, flags = nil)
148
+ if result = PlatformInfo.find_header(header_name, language, flags)
149
+ { :found => true,
150
+ "Location" => result }
151
+ else
152
+ false
153
+ end
154
+ end
155
+
156
+ # def check_for_library(name)
157
+ # check_by_compiling("int main() { return 0; }", :cxx, nil, "-l#{name}")
158
+ # end
159
+
160
+ # def check_by_compiling(source, language = :c, cflags = nil, linkflags = nil)
161
+ # case language
162
+ # when :c
163
+ # source_file = "#{PlatformInfo.tmpexedir}/depcheck-#{Process.pid}-#{Thread.current.object_id}.c"
164
+ # compiler = "gcc"
165
+ # compiler_flags = ENV['CFLAGS']
166
+ # when :cxx
167
+ # source_file = "#{PlatformInfo.tmpexedir}/depcheck-#{Process.pid}-#{Thread.current.object_id}.cpp"
168
+ # compiler = "g++"
169
+ # compiler_flags = "#{ENV['CFLAGS']} #{ENV['CXXFLAGS']}".strip
170
+ # else
171
+ # raise ArgumentError, "Unknown language '#{language}"
172
+ # end
173
+
174
+ # output_file = "#{PlatformInfo.tmpexedir}/depcheck-#{Process.pid}-#{Thread.current.object_id}"
175
+
176
+ # begin
177
+ # File.open(source_file, 'w') do |f|
178
+ # f.puts(source)
179
+ # end
180
+
181
+ # if find_command(compiler)
182
+ # command = "#{compiler} #{compiler_flags} #{cflags} " +
183
+ # "#{source_file} -o #{output_file} #{linkflags}"
184
+ # [!!system(command)]
185
+ # else
186
+ # [:unknown, "Cannot check: compiler '#{compiler}' not found."]
187
+ # end
188
+ # ensure
189
+ # File.unlink(source_file) rescue nil
190
+ # File.unlink(output_file) rescue nil
191
+ # end
192
+ # end
193
+
194
+ def check_for_ruby_library(name)
195
+ begin
196
+ require(name)
197
+ { :found => true }
198
+ rescue LoadError
199
+ if defined?(Gem)
200
+ false
201
+ else
202
+ begin
203
+ require 'rubygems'
204
+ require(name)
205
+ { :found => true }
206
+ rescue LoadError
207
+ false
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ def on(platform)
214
+ return if @on_invoked
215
+ invoke = false
216
+ if (linux_distro_tags || []).include?(platform)
217
+ invoke = true
218
+ else
219
+ case platform
220
+ when :linux
221
+ invoke = true if PlatformInfo.os_name =~ /linux/
222
+ when :freebsd
223
+ invoke = true if PlatformInfo.os_name =~ /freebsd/
224
+ when :macosx
225
+ invoke = true if PlatformInfo.os_name == "macosx"
226
+ when :solaris
227
+ invoke = true if PlatformInfo.os_name =~ /solaris/
228
+ when :other_platforms
229
+ invoke = true
230
+ end
231
+ end
232
+ if invoke
233
+ yield
234
+ @on_invoked = true
235
+ end
236
+ end
237
+
238
+ def apt_get_install(package_name)
239
+ install_instructions("Please install it with <b>apt-get install #{package_name}</b>")
240
+ end
241
+
242
+ def urpmi(package_name)
243
+ install_instructions("Please install it with <b>urpmi #{package_name}</b>")
244
+ end
245
+
246
+ def yum_install(package_name, options = {})
247
+ if options[:epel]
248
+ install_instructions("Please enable <b>EPEL</b>, then install with <b>yum install #{package_name}</b>")
249
+ else
250
+ install_instructions("Please install it with <b>yum install #{package_name}</b>")
251
+ end
252
+ end
253
+
254
+ def emerge(package_name)
255
+ install_instructions("Please install it with <b>emerge -av #{package_name}</b>")
256
+ end
257
+
258
+ def gem_install(package_name)
259
+ install_instructions("Please make sure RubyGems is installed, then run " +
260
+ "<b>#{gem_command} install #{package_name}</b>")
261
+ end
262
+
263
+ def install_osx_command_line_tools
264
+ PhusionPassenger.require_passenger_lib 'platform_info/compiler'
265
+ if PlatformInfo.xcode_select_version.to_s >= "2333"
266
+ install_instructions "Please install the Xcode command line tools: " +
267
+ "<b>sudo xcode-select --install</b>"
268
+ else
269
+ install_instructions "Please install Xcode, then install the command line tools " +
270
+ "though the menu <b>Xcode -> Preferences -> Downloads -> Components</b>"
271
+ end
272
+ end
273
+
274
+
275
+ def ruby_command
276
+ PlatformInfo.ruby_command
277
+ end
278
+
279
+ def gem_command
280
+ PlatformInfo.gem_command(:sudo => true) || 'gem'
281
+ end
282
+
283
+ def find_command(command, *args)
284
+ PlatformInfo.find_command(command, *args)
285
+ end
286
+
287
+ def linux_distro_tags
288
+ PlatformInfo.linux_distro_tags
289
+ end
290
+
291
+ def locate_ruby_tool(name)
292
+ PlatformInfo.locate_ruby_tool(name)
293
+ end
294
+ end # class Dependency
295
+
296
+ class ConsoleRunner
297
+ attr_reader :missing_dependencies
298
+
299
+ def initialize
300
+ @stdout = STDOUT
301
+ @dep_identifiers = []
302
+ end
303
+
304
+ def add(identifier)
305
+ @dep_identifiers << identifier
306
+ end
307
+
308
+ def check_all
309
+ old_log_impl = PlatformInfo.log_implementation
310
+ begin
311
+ PlatformInfo.log_implementation = lambda do |message|
312
+ message = PlatformInfo.send(:reindent, message, 10)
313
+ message.sub!(/^ /, '')
314
+ STDOUT.puts " -> #{message}"
315
+ end
316
+ @missing_dependencies = []
317
+ @dep_identifiers.each do |identifier|
318
+ dep = Depcheck.find(identifier)
319
+ raise "Cannot find depcheck spec #{identifier.inspect}" if !dep
320
+ puts_header "Checking for #{dep.name}..."
321
+ result = dep.check
322
+ result = { :found => false } if !result
323
+
324
+ if result[:found] && !result[:error]
325
+ puts_detail "Found: <green>yes</green>"
326
+ else
327
+ if result[:error]
328
+ puts_detail "Found: #{result[:found] ? "<yellow>yes, but there was an error</yellow>" : "<red>no</red>"}"
329
+ puts_detail "Error: <red>#{result[:error]}</red>"
330
+ else
331
+ puts_detail "Found: #{result[:found] ? "<green>yes</green>" : "<red>no</red>"}"
332
+ end
333
+ @missing_dependencies << dep
334
+ end
335
+
336
+ result.each_pair do |key, value|
337
+ if key.is_a?(String)
338
+ puts_detail "#{key}: #{value}"
339
+ end
340
+ end
341
+ end
342
+
343
+ return @missing_dependencies.empty?
344
+ ensure
345
+ PlatformInfo.log_implementation = old_log_impl
346
+ end
347
+ end
348
+
349
+ def print_installation_instructions_for_missing_dependencies
350
+ @missing_dependencies.each do |dep|
351
+ puts " * To install <yellow>#{dep.name}</yellow>:"
352
+ puts " #{dep.install_instructions}"
353
+ if dep.install_comments
354
+ puts " #{dep.install_comments}"
355
+ end
356
+ puts
357
+ end
358
+ end
359
+
360
+ private
361
+ def puts(text = nil)
362
+ if text
363
+ @stdout.puts(Utils::AnsiColors.ansi_colorize(text))
364
+ else
365
+ @stdout.puts
366
+ end
367
+ @stdout.flush
368
+ end
369
+
370
+ def puts_header(text)
371
+ puts " <b>* #{text}</b>"
372
+ end
373
+
374
+ def puts_detail(text)
375
+ puts " #{text}"
376
+ end
377
+ end
378
+ end # module Depcheck
379
+
380
+ end # module PlatformInfo
381
381
  end # module PhusionPassenger