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
@@ -28,181 +28,181 @@ PhusionPassenger.require_passenger_lib 'utils'
28
28
 
29
29
  module PhusionPassenger
30
30
 
31
- # A convenience class for communicating with MessageServer servers,
32
- # for example the ApplicationPool server.
33
- class MessageClient
34
- include Utils
35
-
36
- # Connect to the given server. By default it connects to the current
37
- # generation's helper server.
38
- def initialize(username, password, address)
39
- @socket = connect_to_server(address)
40
- begin
41
- @channel = MessageChannel.new(@socket)
42
-
43
- result = @channel.read
44
- if result.nil?
45
- raise EOFError
46
- elsif result.size != 2 || result[0] != "version"
47
- raise IOError, "The message server didn't sent a valid version identifier"
48
- elsif result[1] != "1"
49
- raise IOError, "Unsupported message server protocol version #{result[1]}"
50
- end
51
-
52
- @channel.write_scalar(username)
53
- @channel.write_scalar(password)
54
-
55
- result = @channel.read
56
- if result.nil?
57
- raise EOFError
58
- elsif result[0] != "ok"
59
- raise SecurityError, result[0]
60
- end
61
- rescue Exception
62
- @socket.close
63
- raise
64
- end
65
- end
66
-
67
- def close
68
- @socket.close if @socket
69
- @channel = @socket = nil
70
- end
71
-
72
- def connected?
73
- return !!@channel
74
- end
75
-
76
- ### HelperAgent methods ###
77
-
78
- def pool_detach_process(pid)
79
- write("detach_process", pid)
80
- check_security_response
81
- result = read
82
- if result.nil?
83
- raise EOFError
84
- else
85
- return result.first == "true"
86
- end
87
- end
88
-
89
- def pool_detach_process_by_key(detach_key)
90
- write("detach_process_by_key", detach_key)
91
- check_security_response
92
- result = read
93
- if result.nil?
94
- raise EOFError
95
- else
96
- return result.first == "true"
97
- end
98
- end
99
-
100
- def pool_status(options = {})
101
- write("inspect", *options.to_a.flatten)
102
- check_security_response
103
- return read_scalar
104
- rescue
105
- auto_disconnect
106
- raise
107
- end
108
-
109
- def pool_xml
110
- write("toXml", true)
111
- check_security_response
112
- return read_scalar
113
- end
114
-
115
- def restart_app_group(app_group_name, options = {})
116
- write("restart_app_group", app_group_name, *options.to_a.flatten)
117
- check_security_response
118
- result = read
119
- if result.nil?
120
- raise EOFError
121
- else
122
- return result.first == "true"
123
- end
124
- end
125
-
126
- def helper_agent_requests
127
- write("requests")
128
- check_security_response
129
- return read_scalar
130
- end
131
-
132
- ### HelperAgent BacktracesServer methods ###
133
-
134
- def helper_agent_backtraces
135
- write("backtraces")
136
- check_security_response
137
- return read_scalar
138
- end
139
-
140
- ### LoggingAgent AdminServer methods ###
141
-
142
- def logging_agent_status
143
- write("status")
144
- check_security_response
145
- return read_scalar
146
- end
147
-
148
- ### Low level I/O methods ###
149
-
150
- def read
151
- return @channel.read
152
- rescue
153
- auto_disconnect
154
- raise
155
- end
156
-
157
- def write(*args)
158
- @channel.write(*args)
159
- rescue
160
- auto_disconnect
161
- raise
162
- end
163
-
164
- def write_scalar(*args)
165
- @channel.write_scalar(*args)
166
- rescue
167
- auto_disconnect
168
- raise
169
- end
170
-
171
- def read_scalar
172
- return @channel.read_scalar
173
- rescue
174
- auto_disconnect
175
- raise
176
- end
177
-
178
- def recv_io(klass = IO, negotiate = true)
179
- return @channel.recv_io(klass, negotiate)
180
- rescue
181
- auto_disconnect
182
- raise
183
- end
184
-
185
- def check_security_response
186
- begin
187
- result = @channel.read
188
- rescue
189
- auto_disconnect
190
- raise
191
- end
192
- if result.nil?
193
- raise EOFError
194
- elsif result[0] != "Passed security"
195
- raise SecurityError, result[0]
196
- end
197
- end
198
-
199
- private
200
- def auto_disconnect
201
- if @channel
202
- @socket.close rescue nil
203
- @socket = @channel = nil
204
- end
205
- end
206
- end
31
+ # A convenience class for communicating with MessageServer servers,
32
+ # for example the ApplicationPool server.
33
+ class MessageClient
34
+ include Utils
35
+
36
+ # Connect to the given server. By default it connects to the current
37
+ # generation's helper server.
38
+ def initialize(username, password, address)
39
+ @socket = connect_to_server(address)
40
+ begin
41
+ @channel = MessageChannel.new(@socket)
42
+
43
+ result = @channel.read
44
+ if result.nil?
45
+ raise EOFError
46
+ elsif result.size != 2 || result[0] != "version"
47
+ raise IOError, "The message server didn't sent a valid version identifier"
48
+ elsif result[1] != "1"
49
+ raise IOError, "Unsupported message server protocol version #{result[1]}"
50
+ end
51
+
52
+ @channel.write_scalar(username)
53
+ @channel.write_scalar(password)
54
+
55
+ result = @channel.read
56
+ if result.nil?
57
+ raise EOFError
58
+ elsif result[0] != "ok"
59
+ raise SecurityError, result[0]
60
+ end
61
+ rescue Exception
62
+ @socket.close
63
+ raise
64
+ end
65
+ end
66
+
67
+ def close
68
+ @socket.close if @socket
69
+ @channel = @socket = nil
70
+ end
71
+
72
+ def connected?
73
+ return !!@channel
74
+ end
75
+
76
+ ### HelperAgent methods ###
77
+
78
+ def pool_detach_process(pid)
79
+ write("detach_process", pid)
80
+ check_security_response
81
+ result = read
82
+ if result.nil?
83
+ raise EOFError
84
+ else
85
+ return result.first == "true"
86
+ end
87
+ end
88
+
89
+ def pool_detach_process_by_key(detach_key)
90
+ write("detach_process_by_key", detach_key)
91
+ check_security_response
92
+ result = read
93
+ if result.nil?
94
+ raise EOFError
95
+ else
96
+ return result.first == "true"
97
+ end
98
+ end
99
+
100
+ def pool_status(options = {})
101
+ write("inspect", *options.to_a.flatten)
102
+ check_security_response
103
+ return read_scalar
104
+ rescue
105
+ auto_disconnect
106
+ raise
107
+ end
108
+
109
+ def pool_xml
110
+ write("toXml", true)
111
+ check_security_response
112
+ return read_scalar
113
+ end
114
+
115
+ def restart_app_group(app_group_name, options = {})
116
+ write("restart_app_group", app_group_name, *options.to_a.flatten)
117
+ check_security_response
118
+ result = read
119
+ if result.nil?
120
+ raise EOFError
121
+ else
122
+ return result.first == "true"
123
+ end
124
+ end
125
+
126
+ def helper_agent_requests
127
+ write("requests")
128
+ check_security_response
129
+ return read_scalar
130
+ end
131
+
132
+ ### HelperAgent BacktracesServer methods ###
133
+
134
+ def helper_agent_backtraces
135
+ write("backtraces")
136
+ check_security_response
137
+ return read_scalar
138
+ end
139
+
140
+ ### LoggingAgent AdminServer methods ###
141
+
142
+ def logging_agent_status
143
+ write("status")
144
+ check_security_response
145
+ return read_scalar
146
+ end
147
+
148
+ ### Low level I/O methods ###
149
+
150
+ def read
151
+ return @channel.read
152
+ rescue
153
+ auto_disconnect
154
+ raise
155
+ end
156
+
157
+ def write(*args)
158
+ @channel.write(*args)
159
+ rescue
160
+ auto_disconnect
161
+ raise
162
+ end
163
+
164
+ def write_scalar(*args)
165
+ @channel.write_scalar(*args)
166
+ rescue
167
+ auto_disconnect
168
+ raise
169
+ end
170
+
171
+ def read_scalar
172
+ return @channel.read_scalar
173
+ rescue
174
+ auto_disconnect
175
+ raise
176
+ end
177
+
178
+ def recv_io(klass = IO, negotiate = true)
179
+ return @channel.recv_io(klass, negotiate)
180
+ rescue
181
+ auto_disconnect
182
+ raise
183
+ end
184
+
185
+ def check_security_response
186
+ begin
187
+ result = @channel.read
188
+ rescue
189
+ auto_disconnect
190
+ raise
191
+ end
192
+ if result.nil?
193
+ raise EOFError
194
+ elsif result[0] != "Passed security"
195
+ raise SecurityError, result[0]
196
+ end
197
+ end
198
+
199
+ private
200
+ def auto_disconnect
201
+ if @channel
202
+ @socket.close rescue nil
203
+ @socket = @channel = nil
204
+ end
205
+ end
206
+ end
207
207
 
208
208
  end # module PhusionPassenger
@@ -25,377 +25,377 @@ PhusionPassenger.require_passenger_lib 'constants'
25
25
 
26
26
  module PhusionPassenger
27
27
 
28
- class NativeSupportLoader
29
- def self.supported?
30
- return !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx"
31
- end
32
-
33
- def try_load
34
- if defined?(NativeSupport)
35
- return true
36
- else
37
- load_from_native_support_output_dir ||
38
- load_from_buildout_dir ||
39
- load_from_load_path ||
40
- load_from_home_dir
41
- end
42
- end
43
-
44
- def start
45
- if ENV['PASSENGER_USE_RUBY_NATIVE_SUPPORT'] == '0'
46
- STDERR.puts " --> Continuing without #{library_name}."
47
- STDERR.puts " Because PASSENGER_USE_RUBY_NATIVE_SUPPORT is set to 0."
48
- return false
49
- elsif try_load
50
- return true
51
- elsif compile_and_load || download_binary_and_load
52
- STDERR.puts " --> #{library_name} successfully loaded."
53
- return true
54
- else
55
- STDERR.puts " --> Continuing without #{library_name}."
56
- return false
57
- end
58
- end
59
-
60
- private
61
- def archdir
62
- @archdir ||= begin
63
- PhusionPassenger.require_passenger_lib 'platform_info/binary_compatibility'
64
- PlatformInfo.ruby_extension_binary_compatibility_id
65
- end
66
- end
67
-
68
- def libext
69
- @libext ||= begin
70
- PhusionPassenger.require_passenger_lib 'platform_info/operating_system'
71
- PlatformInfo.library_extension
72
- end
73
- end
74
-
75
- def library_name
76
- return "passenger_native_support.#{libext}"
77
- end
78
-
79
- def extconf_rb
80
- File.join(PhusionPassenger.ruby_extension_source_dir, "extconf.rb")
81
- end
82
-
83
- def load_from_native_support_output_dir
84
- # Quick workaround for people suffering from
85
- # https://code.google.com/p/phusion-passenger/issues/detail?id=865
86
- output_dir = ENV['PASSENGER_NATIVE_SUPPORT_OUTPUT_DIR']
87
- if output_dir && !output_dir.empty?
88
- begin
89
- return load_native_extension("#{output_dir}/#{VERSION_STRING}/#{archdir}/#{library_name}")
90
- rescue LoadError
91
- return false
92
- end
93
- else
94
- return false
95
- end
96
- end
97
-
98
- def load_from_buildout_dir
99
- if PhusionPassenger.build_system_dir
100
- begin
101
- return load_native_extension("#{PhusionPassenger.build_system_dir}/buildout/ruby/#{archdir}/#{library_name}")
102
- rescue LoadError
103
- return false
104
- end
105
- else
106
- return false
107
- end
108
- end
109
-
110
- def load_from_load_path
111
- return load_native_extension('passenger_native_support')
112
- rescue LoadError
113
- return false
114
- end
115
-
116
- def load_from_home_dir
117
- begin
118
- return load_native_extension("#{PhusionPassenger.home_dir}/#{USER_NAMESPACE_DIRNAME}/native_support/#{VERSION_STRING}/#{archdir}/#{library_name}")
119
- rescue LoadError
120
- return false
121
- end
122
- end
123
-
124
- def download_binary_and_load
125
- if !PhusionPassenger.installed_from_release_package?
126
- return
127
- end
128
- if ENV['PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY'] == '0'
129
- STDERR.puts " --> Skipping downloading of precompiled #{library_name}"
130
- return
131
- end
132
-
133
- STDERR.puts " --> Downloading precompiled #{library_name} for the current Ruby interpreter..."
134
- STDERR.puts " (set PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 to disable)"
135
-
136
- require 'logger'
137
- PhusionPassenger.require_passenger_lib 'platform_info/ruby'
138
- PhusionPassenger.require_passenger_lib 'utils/tmpio'
139
- PhusionPassenger.require_passenger_lib 'utils/download'
140
- PhusionPassenger.require_passenger_lib 'utils/shellwords'
141
-
142
- PhusionPassenger::Utils.mktmpdir("passenger-native-support-") do |dir|
143
- Dir.chdir(dir) do
144
- basename = "rubyext-#{archdir}.tar.gz"
145
- if !download(basename, dir, :total_timeout => 30)
146
- return false
147
- end
148
-
149
- s_basename = Shellwords.escape(basename)
150
- sh "tar xzf #{s_basename}"
151
- sh "rm -f #{s_basename}"
152
- STDERR.puts " Checking whether downloaded binary is usable..."
153
-
154
- File.open("test.rb", "w") do |f|
155
- f.puts(%Q{
156
- require File.expand_path('passenger_native_support')
157
- f = File.open("test.txt", "w")
158
- PhusionPassenger::NativeSupport.writev(f.fileno, ["hello", "\n"])
159
- })
160
- end
161
-
162
- if sh_nonfatal("#{PlatformInfo.ruby_command} -I. test.rb") &&
163
- File.exist?("test.txt") &&
164
- File.read("test.txt") == "hello\n"
165
- STDERR.puts " Binary is usable."
166
- File.unlink("test.rb")
167
- File.unlink("test.txt")
168
- result = try_directories(installation_target_dirs) do |target_dir|
169
- files = Dir["#{dir}/*"]
170
- STDERR.puts " Installing " + files.map{ |n| File.basename(n) }.join(' ')
171
- FileUtils.cp(files, target_dir)
172
- load_result = load_native_extension("#{target_dir}/#{library_name}")
173
- [load_result, false]
174
- end
175
- return result
176
- else
177
- STDERR.puts " Binary is not usable."
178
- return false
179
- end
180
- end
181
- end
182
- end
183
-
184
- def compile_and_load
185
- if ENV['PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY'] == '0'
186
- STDERR.puts " --> Skipping compiling of #{library_name}"
187
- return false
188
- end
189
-
190
- if PhusionPassenger.custom_packaged? && !File.exist?(PhusionPassenger.ruby_extension_source_dir)
191
- PhusionPassenger.require_passenger_lib 'constants'
192
- STDERR.puts " --> No #{library_name} found for current Ruby interpreter."
193
- case PhusionPassenger.packaging_method
194
- when 'deb'
195
- STDERR.puts " This library provides various optimized routines that make"
196
- STDERR.puts " #{PhusionPassenger::PROGRAM_NAME} faster. Please run 'sudo apt-get install #{PhusionPassenger::DEB_DEV_PACKAGE}'"
197
- STDERR.puts " so that #{PhusionPassenger::PROGRAM_NAME} can compile one on the next run."
198
- when 'rpm'
199
- STDERR.puts " This library provides various optimized routines that make"
200
- STDERR.puts " #{PhusionPassenger::PROGRAM_NAME} faster. Please run 'sudo yum install #{PhusionPassenger::RPM_DEV_PACKAGE}-#{PhusionPassenger::VERSION_STRING}'"
201
- STDERR.puts " so that #{PhusionPassenger::PROGRAM_NAME} can compile one on the next run."
202
- else
203
- STDERR.puts " #{PhusionPassenger::PROGRAM_NAME} can compile one, but an extra package must be installed"
204
- STDERR.puts " first. Please ask your packager or operating system vendor for instructions."
205
- end
206
- return false
207
- end
208
-
209
- STDERR.puts " --> Compiling #{library_name} for the current Ruby interpreter..."
210
- STDERR.puts " (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)"
211
-
212
- require 'fileutils'
213
- PhusionPassenger.require_passenger_lib 'utils/shellwords'
214
- PhusionPassenger.require_passenger_lib 'platform_info/ruby'
215
-
216
- target_dir = compile(installation_target_dirs)
217
- if target_dir
218
- return load_native_extension("#{target_dir}/#{library_name}")
219
- else
220
- return false
221
- end
222
- end
223
-
224
- def installation_target_dirs
225
- target_dirs = []
226
- if (output_dir = ENV['PASSENGER_NATIVE_SUPPORT_OUTPUT_DIR']) && !output_dir.empty?
227
- target_dirs << "#{output_dir}/#{VERSION_STRING}/#{archdir}"
228
- end
229
- if PhusionPassenger.build_system_dir
230
- target_dirs << "#{PhusionPassenger.build_system_dir}/buildout/ruby/#{archdir}"
231
- end
232
- target_dirs << "#{PhusionPassenger.home_dir}/#{USER_NAMESPACE_DIRNAME}/native_support/#{VERSION_STRING}/#{archdir}"
233
- return target_dirs
234
- end
235
-
236
- def download(name, output_dir, options = {})
237
- logger = Logger.new(STDERR)
238
- logger.level = Logger::WARN
239
- logger.formatter = proc do |severity, datetime, progname, msg|
240
- msg.gsub(/^/, " ") + "\n"
241
- end
242
- sites = PhusionPassenger.binaries_sites
243
- sites.each_with_index do |site, i|
244
- if real_download(site, name, output_dir, logger, options)
245
- logger.warn "Download OK!" if i > 0
246
- return true
247
- elsif i != sites.size - 1
248
- logger.warn "Trying next mirror..."
249
- end
250
- end
251
- return false
252
- end
253
-
254
- def real_download(site, name, output_dir, logger, options)
255
- url = "#{site[:url]}/#{VERSION_STRING}/#{name}"
256
- filename = "#{output_dir}/#{name}"
257
- real_options = options.merge(
258
- :cacert => site[:cacert],
259
- :use_cache => true,
260
- :logger => logger
261
- )
262
- return PhusionPassenger::Utils::Download.download(url, filename, real_options)
263
- end
264
-
265
- def log(message, options = {})
266
- if logger = options[:logger]
267
- logger.puts(message)
268
- else
269
- STDERR.puts " #{message}"
270
- end
271
- end
272
-
273
- def mkdir(dir, options = {})
274
- begin
275
- log("# mkdir -p #{dir}", options)
276
- FileUtils.mkdir_p(dir)
277
- rescue Errno::EEXIST
278
- end
279
- end
280
-
281
- def sh(command_string)
282
- if !sh_nonfatal(command_string)
283
- raise "Could not compile #{library_name} (\"#{command_string}\" failed)"
284
- end
285
- end
286
-
287
- def sh_nonfatal(command_string, options = {})
288
- log("# #{command_string}", options)
289
- if logger = options[:logger]
290
- s_logpath = Shellwords.escape(logger.path)
291
- return system("(#{command_string}) >>#{s_logpath} 2>&1")
292
- else
293
- Utils.mktmpdir("passenger-native-support-") do |tmpdir|
294
- s_tmpdir = Shellwords.escape(tmpdir)
295
- result = system("(#{command_string}) >#{s_tmpdir}/log 2>&1")
296
- system("cat #{s_tmpdir}/log | sed 's/^/ /' >&2")
297
- return result
298
- end
299
- end
300
- end
301
-
302
- def compile(target_dirs)
303
- logger = Utils::TmpIO.new('passenger_native_support',
304
- :mode => File::WRONLY | File::APPEND,
305
- :binary => false,
306
- :suffix => ".log",
307
- :unlink_immediately => false)
308
- options = { :logger => logger }
309
- begin
310
- try_directories(target_dirs, options) do |target_dir|
311
- result =
312
- sh_nonfatal("#{PlatformInfo.ruby_command} #{Shellwords.escape extconf_rb}",
313
- options) &&
314
- sh_nonfatal("make clean && make", options)
315
- if result
316
- log "Compilation succesful. The logs are here:"
317
- log logger.path
318
- [target_dir, false]
319
- else
320
- log "Warning: compilation didn't succeed. To learn why, read this file:"
321
- log logger.path
322
- [nil, false]
323
- end
324
- end
325
- end
326
- ensure
327
- logger.close if logger
328
- end
329
-
330
- def try_directories(dirs, options = {})
331
- result = nil
332
- dirs.each_with_index do |dir, i|
333
- begin
334
- mkdir(dir, options)
335
- File.open("#{dir}/.permission_test", "w").close
336
- File.unlink("#{dir}/.permission_test")
337
- log("# cd #{dir}", options)
338
- Dir.chdir(dir) do
339
- result, should_retry = yield(dir)
340
- return result if !should_retry
341
- end
342
- rescue Errno::EACCES
343
- # If we encountered a permission error, then try
344
- # the next target directory. If we get a permission
345
- # error on the last one too then propagate the
346
- # exception.
347
- if i == dirs.size - 1
348
- log("Encountered permission error, " +
349
- "but no more directories to try. Giving up.",
350
- options)
351
- log("-------------------------------", options)
352
- return nil
353
- else
354
- log("Encountered permission error, " +
355
- "trying a different directory...",
356
- options)
357
- log("-------------------------------", options)
358
- end
359
- rescue Errno::ENOTDIR
360
- # This can occur when locations.ini set build_system_dir
361
- # to an invalid path. Just ignore this error.
362
- if i == dirs.size - 1
363
- log("Not a valid directory, " +
364
- "but no more directories to try. Giving up.",
365
- options)
366
- log("-------------------------------", options)
367
- return nil
368
- else
369
- log("Not a valid directory. Trying a different one...",
370
- options)
371
- log("-------------------------------", options)
372
- end
373
- end
374
- end
375
- end
376
-
377
- def load_native_extension(name_or_filename)
378
- # If passenger_native_support.so exited because it detected that it was compiled
379
- # for a different Ruby version, then subsequent require("passenger_native_support")
380
- # calls will do nothing. So we remove passenger_native_support from $LOADED_FEATURES
381
- # to force it to be loaded.
382
- $LOADED_FEATURES.reject! { |fn| File.basename(fn) == library_name }
383
- begin
384
- require(name_or_filename)
385
- return defined?(PhusionPassenger::NativeSupport)
386
- rescue LoadError => e
387
- if e.to_s =~ /dlopen/
388
- # Print dlopen failures. We're not interested in any other
389
- # kinds of failures, such as file-not-found.
390
- puts e.to_s.gsub(/^/, " ")
391
- end
392
- return false
393
- end
394
- end
395
- end
28
+ class NativeSupportLoader
29
+ def self.supported?
30
+ return !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx"
31
+ end
32
+
33
+ def try_load
34
+ if defined?(NativeSupport)
35
+ return true
36
+ else
37
+ load_from_native_support_output_dir ||
38
+ load_from_buildout_dir ||
39
+ load_from_load_path ||
40
+ load_from_home_dir
41
+ end
42
+ end
43
+
44
+ def start
45
+ if ENV['PASSENGER_USE_RUBY_NATIVE_SUPPORT'] == '0'
46
+ STDERR.puts " --> Continuing without #{library_name}."
47
+ STDERR.puts " Because PASSENGER_USE_RUBY_NATIVE_SUPPORT is set to 0."
48
+ return false
49
+ elsif try_load
50
+ return true
51
+ elsif compile_and_load || download_binary_and_load
52
+ STDERR.puts " --> #{library_name} successfully loaded."
53
+ return true
54
+ else
55
+ STDERR.puts " --> Continuing without #{library_name}."
56
+ return false
57
+ end
58
+ end
59
+
60
+ private
61
+ def archdir
62
+ @archdir ||= begin
63
+ PhusionPassenger.require_passenger_lib 'platform_info/binary_compatibility'
64
+ PlatformInfo.ruby_extension_binary_compatibility_id
65
+ end
66
+ end
67
+
68
+ def libext
69
+ @libext ||= begin
70
+ PhusionPassenger.require_passenger_lib 'platform_info/operating_system'
71
+ PlatformInfo.library_extension
72
+ end
73
+ end
74
+
75
+ def library_name
76
+ return "passenger_native_support.#{libext}"
77
+ end
78
+
79
+ def extconf_rb
80
+ File.join(PhusionPassenger.ruby_extension_source_dir, "extconf.rb")
81
+ end
82
+
83
+ def load_from_native_support_output_dir
84
+ # Quick workaround for people suffering from
85
+ # https://code.google.com/p/phusion-passenger/issues/detail?id=865
86
+ output_dir = ENV['PASSENGER_NATIVE_SUPPORT_OUTPUT_DIR']
87
+ if output_dir && !output_dir.empty?
88
+ begin
89
+ return load_native_extension("#{output_dir}/#{VERSION_STRING}/#{archdir}/#{library_name}")
90
+ rescue LoadError
91
+ return false
92
+ end
93
+ else
94
+ return false
95
+ end
96
+ end
97
+
98
+ def load_from_buildout_dir
99
+ if PhusionPassenger.build_system_dir
100
+ begin
101
+ return load_native_extension("#{PhusionPassenger.build_system_dir}/buildout/ruby/#{archdir}/#{library_name}")
102
+ rescue LoadError
103
+ return false
104
+ end
105
+ else
106
+ return false
107
+ end
108
+ end
109
+
110
+ def load_from_load_path
111
+ return load_native_extension('passenger_native_support')
112
+ rescue LoadError
113
+ return false
114
+ end
115
+
116
+ def load_from_home_dir
117
+ begin
118
+ return load_native_extension("#{PhusionPassenger.home_dir}/#{USER_NAMESPACE_DIRNAME}/native_support/#{VERSION_STRING}/#{archdir}/#{library_name}")
119
+ rescue LoadError
120
+ return false
121
+ end
122
+ end
123
+
124
+ def download_binary_and_load
125
+ if !PhusionPassenger.installed_from_release_package?
126
+ return
127
+ end
128
+ if ENV['PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY'] == '0'
129
+ STDERR.puts " --> Skipping downloading of precompiled #{library_name}"
130
+ return
131
+ end
132
+
133
+ STDERR.puts " --> Downloading precompiled #{library_name} for the current Ruby interpreter..."
134
+ STDERR.puts " (set PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 to disable)"
135
+
136
+ require 'logger'
137
+ PhusionPassenger.require_passenger_lib 'platform_info/ruby'
138
+ PhusionPassenger.require_passenger_lib 'utils/tmpio'
139
+ PhusionPassenger.require_passenger_lib 'utils/download'
140
+ PhusionPassenger.require_passenger_lib 'utils/shellwords'
141
+
142
+ PhusionPassenger::Utils.mktmpdir("passenger-native-support-") do |dir|
143
+ Dir.chdir(dir) do
144
+ basename = "rubyext-#{archdir}.tar.gz"
145
+ if !download(basename, dir, :total_timeout => 30)
146
+ return false
147
+ end
148
+
149
+ s_basename = Shellwords.escape(basename)
150
+ sh "tar xzf #{s_basename}"
151
+ sh "rm -f #{s_basename}"
152
+ STDERR.puts " Checking whether downloaded binary is usable..."
153
+
154
+ File.open("test.rb", "w") do |f|
155
+ f.puts(%Q{
156
+ require File.expand_path('passenger_native_support')
157
+ f = File.open("test.txt", "w")
158
+ PhusionPassenger::NativeSupport.writev(f.fileno, ["hello", "\n"])
159
+ })
160
+ end
161
+
162
+ if sh_nonfatal("#{PlatformInfo.ruby_command} -I. test.rb") &&
163
+ File.exist?("test.txt") &&
164
+ File.read("test.txt") == "hello\n"
165
+ STDERR.puts " Binary is usable."
166
+ File.unlink("test.rb")
167
+ File.unlink("test.txt")
168
+ result = try_directories(installation_target_dirs) do |target_dir|
169
+ files = Dir["#{dir}/*"]
170
+ STDERR.puts " Installing " + files.map{ |n| File.basename(n) }.join(' ')
171
+ FileUtils.cp(files, target_dir)
172
+ load_result = load_native_extension("#{target_dir}/#{library_name}")
173
+ [load_result, false]
174
+ end
175
+ return result
176
+ else
177
+ STDERR.puts " Binary is not usable."
178
+ return false
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ def compile_and_load
185
+ if ENV['PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY'] == '0'
186
+ STDERR.puts " --> Skipping compiling of #{library_name}"
187
+ return false
188
+ end
189
+
190
+ if PhusionPassenger.custom_packaged? && !File.exist?(PhusionPassenger.ruby_extension_source_dir)
191
+ PhusionPassenger.require_passenger_lib 'constants'
192
+ STDERR.puts " --> No #{library_name} found for current Ruby interpreter."
193
+ case PhusionPassenger.packaging_method
194
+ when 'deb'
195
+ STDERR.puts " This library provides various optimized routines that make"
196
+ STDERR.puts " #{PhusionPassenger::PROGRAM_NAME} faster. Please run 'sudo apt-get install #{PhusionPassenger::DEB_DEV_PACKAGE}'"
197
+ STDERR.puts " so that #{PhusionPassenger::PROGRAM_NAME} can compile one on the next run."
198
+ when 'rpm'
199
+ STDERR.puts " This library provides various optimized routines that make"
200
+ STDERR.puts " #{PhusionPassenger::PROGRAM_NAME} faster. Please run 'sudo yum install #{PhusionPassenger::RPM_DEV_PACKAGE}-#{PhusionPassenger::VERSION_STRING}'"
201
+ STDERR.puts " so that #{PhusionPassenger::PROGRAM_NAME} can compile one on the next run."
202
+ else
203
+ STDERR.puts " #{PhusionPassenger::PROGRAM_NAME} can compile one, but an extra package must be installed"
204
+ STDERR.puts " first. Please ask your packager or operating system vendor for instructions."
205
+ end
206
+ return false
207
+ end
208
+
209
+ STDERR.puts " --> Compiling #{library_name} for the current Ruby interpreter..."
210
+ STDERR.puts " (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)"
211
+
212
+ require 'fileutils'
213
+ PhusionPassenger.require_passenger_lib 'utils/shellwords'
214
+ PhusionPassenger.require_passenger_lib 'platform_info/ruby'
215
+
216
+ target_dir = compile(installation_target_dirs)
217
+ if target_dir
218
+ return load_native_extension("#{target_dir}/#{library_name}")
219
+ else
220
+ return false
221
+ end
222
+ end
223
+
224
+ def installation_target_dirs
225
+ target_dirs = []
226
+ if (output_dir = ENV['PASSENGER_NATIVE_SUPPORT_OUTPUT_DIR']) && !output_dir.empty?
227
+ target_dirs << "#{output_dir}/#{VERSION_STRING}/#{archdir}"
228
+ end
229
+ if PhusionPassenger.build_system_dir
230
+ target_dirs << "#{PhusionPassenger.build_system_dir}/buildout/ruby/#{archdir}"
231
+ end
232
+ target_dirs << "#{PhusionPassenger.home_dir}/#{USER_NAMESPACE_DIRNAME}/native_support/#{VERSION_STRING}/#{archdir}"
233
+ return target_dirs
234
+ end
235
+
236
+ def download(name, output_dir, options = {})
237
+ logger = Logger.new(STDERR)
238
+ logger.level = Logger::WARN
239
+ logger.formatter = proc do |severity, datetime, progname, msg|
240
+ msg.gsub(/^/, " ") + "\n"
241
+ end
242
+ sites = PhusionPassenger.binaries_sites
243
+ sites.each_with_index do |site, i|
244
+ if real_download(site, name, output_dir, logger, options)
245
+ logger.warn "Download OK!" if i > 0
246
+ return true
247
+ elsif i != sites.size - 1
248
+ logger.warn "Trying next mirror..."
249
+ end
250
+ end
251
+ return false
252
+ end
253
+
254
+ def real_download(site, name, output_dir, logger, options)
255
+ url = "#{site[:url]}/#{VERSION_STRING}/#{name}"
256
+ filename = "#{output_dir}/#{name}"
257
+ real_options = options.merge(
258
+ :cacert => site[:cacert],
259
+ :use_cache => true,
260
+ :logger => logger
261
+ )
262
+ return PhusionPassenger::Utils::Download.download(url, filename, real_options)
263
+ end
264
+
265
+ def log(message, options = {})
266
+ if logger = options[:logger]
267
+ logger.puts(message)
268
+ else
269
+ STDERR.puts " #{message}"
270
+ end
271
+ end
272
+
273
+ def mkdir(dir, options = {})
274
+ begin
275
+ log("# mkdir -p #{dir}", options)
276
+ FileUtils.mkdir_p(dir)
277
+ rescue Errno::EEXIST
278
+ end
279
+ end
280
+
281
+ def sh(command_string)
282
+ if !sh_nonfatal(command_string)
283
+ raise "Could not compile #{library_name} (\"#{command_string}\" failed)"
284
+ end
285
+ end
286
+
287
+ def sh_nonfatal(command_string, options = {})
288
+ log("# #{command_string}", options)
289
+ if logger = options[:logger]
290
+ s_logpath = Shellwords.escape(logger.path)
291
+ return system("(#{command_string}) >>#{s_logpath} 2>&1")
292
+ else
293
+ Utils.mktmpdir("passenger-native-support-") do |tmpdir|
294
+ s_tmpdir = Shellwords.escape(tmpdir)
295
+ result = system("(#{command_string}) >#{s_tmpdir}/log 2>&1")
296
+ system("cat #{s_tmpdir}/log | sed 's/^/ /' >&2")
297
+ return result
298
+ end
299
+ end
300
+ end
301
+
302
+ def compile(target_dirs)
303
+ logger = Utils::TmpIO.new('passenger_native_support',
304
+ :mode => File::WRONLY | File::APPEND,
305
+ :binary => false,
306
+ :suffix => ".log",
307
+ :unlink_immediately => false)
308
+ options = { :logger => logger }
309
+ begin
310
+ try_directories(target_dirs, options) do |target_dir|
311
+ result =
312
+ sh_nonfatal("#{PlatformInfo.ruby_command} #{Shellwords.escape extconf_rb}",
313
+ options) &&
314
+ sh_nonfatal("make clean && make", options)
315
+ if result
316
+ log "Compilation succesful. The logs are here:"
317
+ log logger.path
318
+ [target_dir, false]
319
+ else
320
+ log "Warning: compilation didn't succeed. To learn why, read this file:"
321
+ log logger.path
322
+ [nil, false]
323
+ end
324
+ end
325
+ end
326
+ ensure
327
+ logger.close if logger
328
+ end
329
+
330
+ def try_directories(dirs, options = {})
331
+ result = nil
332
+ dirs.each_with_index do |dir, i|
333
+ begin
334
+ mkdir(dir, options)
335
+ File.open("#{dir}/.permission_test", "w").close
336
+ File.unlink("#{dir}/.permission_test")
337
+ log("# cd #{dir}", options)
338
+ Dir.chdir(dir) do
339
+ result, should_retry = yield(dir)
340
+ return result if !should_retry
341
+ end
342
+ rescue Errno::EACCES
343
+ # If we encountered a permission error, then try
344
+ # the next target directory. If we get a permission
345
+ # error on the last one too then propagate the
346
+ # exception.
347
+ if i == dirs.size - 1
348
+ log("Encountered permission error, " +
349
+ "but no more directories to try. Giving up.",
350
+ options)
351
+ log("-------------------------------", options)
352
+ return nil
353
+ else
354
+ log("Encountered permission error, " +
355
+ "trying a different directory...",
356
+ options)
357
+ log("-------------------------------", options)
358
+ end
359
+ rescue Errno::ENOTDIR
360
+ # This can occur when locations.ini set build_system_dir
361
+ # to an invalid path. Just ignore this error.
362
+ if i == dirs.size - 1
363
+ log("Not a valid directory, " +
364
+ "but no more directories to try. Giving up.",
365
+ options)
366
+ log("-------------------------------", options)
367
+ return nil
368
+ else
369
+ log("Not a valid directory. Trying a different one...",
370
+ options)
371
+ log("-------------------------------", options)
372
+ end
373
+ end
374
+ end
375
+ end
376
+
377
+ def load_native_extension(name_or_filename)
378
+ # If passenger_native_support.so exited because it detected that it was compiled
379
+ # for a different Ruby version, then subsequent require("passenger_native_support")
380
+ # calls will do nothing. So we remove passenger_native_support from $LOADED_FEATURES
381
+ # to force it to be loaded.
382
+ $LOADED_FEATURES.reject! { |fn| File.basename(fn) == library_name }
383
+ begin
384
+ require(name_or_filename)
385
+ return defined?(PhusionPassenger::NativeSupport)
386
+ rescue LoadError => e
387
+ if e.to_s =~ /dlopen/
388
+ # Print dlopen failures. We're not interested in any other
389
+ # kinds of failures, such as file-not-found.
390
+ puts e.to_s.gsub(/^/, " ")
391
+ end
392
+ return false
393
+ end
394
+ end
395
+ end
396
396
 
397
397
  end # module PhusionPassenger
398
398
 
399
399
  if PhusionPassenger::NativeSupportLoader.supported?
400
- PhusionPassenger::NativeSupportLoader.new.start
400
+ PhusionPassenger::NativeSupportLoader.new.start
401
401
  end