merb-core 0.9.8 → 0.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CONTRIBUTORS +33 -0
- data/README +7 -3
- data/Rakefile +3 -3
- data/lib/merb-core.rb +165 -94
- data/lib/merb-core/bootloader.rb +469 -100
- data/lib/merb-core/config.rb +79 -3
- data/lib/merb-core/constants.rb +24 -2
- data/lib/merb-core/controller/abstract_controller.rb +172 -67
- data/lib/merb-core/controller/exceptions.rb +50 -6
- data/lib/merb-core/controller/merb_controller.rb +215 -108
- data/lib/merb-core/controller/mime.rb +36 -12
- data/lib/merb-core/controller/mixins/authentication.rb +52 -7
- data/lib/merb-core/controller/mixins/conditional_get.rb +14 -0
- data/lib/merb-core/controller/mixins/controller.rb +90 -58
- data/lib/merb-core/controller/mixins/render.rb +34 -10
- data/lib/merb-core/controller/mixins/responder.rb +40 -16
- data/lib/merb-core/controller/template.rb +37 -16
- data/lib/merb-core/core_ext/hash.rb +9 -0
- data/lib/merb-core/core_ext/kernel.rb +92 -41
- data/lib/merb-core/dispatch/dispatcher.rb +29 -45
- data/lib/merb-core/dispatch/request.rb +186 -82
- data/lib/merb-core/dispatch/router.rb +141 -53
- data/lib/merb-core/dispatch/router/behavior.rb +296 -139
- data/lib/merb-core/dispatch/router/resources.rb +51 -19
- data/lib/merb-core/dispatch/router/route.rb +76 -23
- data/lib/merb-core/dispatch/session.rb +80 -36
- data/lib/merb-core/dispatch/session/container.rb +31 -15
- data/lib/merb-core/dispatch/session/cookie.rb +51 -22
- data/lib/merb-core/dispatch/session/memcached.rb +10 -6
- data/lib/merb-core/dispatch/session/memory.rb +17 -5
- data/lib/merb-core/dispatch/session/store_container.rb +21 -9
- data/lib/merb-core/dispatch/worker.rb +16 -2
- data/lib/merb-core/gem_ext/erubis.rb +4 -0
- data/lib/merb-core/plugins.rb +13 -0
- data/lib/merb-core/rack.rb +1 -0
- data/lib/merb-core/rack/adapter.rb +1 -0
- data/lib/merb-core/rack/adapter/abstract.rb +95 -17
- data/lib/merb-core/rack/adapter/irb.rb +50 -5
- data/lib/merb-core/rack/application.rb +27 -5
- data/lib/merb-core/rack/handler/mongrel.rb +6 -6
- data/lib/merb-core/rack/helpers.rb +33 -0
- data/lib/merb-core/rack/middleware/conditional_get.rb +1 -1
- data/lib/merb-core/rack/middleware/path_prefix.rb +3 -3
- data/lib/merb-core/rack/middleware/static.rb +11 -7
- data/lib/merb-core/server.rb +134 -69
- data/lib/merb-core/tasks/gem_management.rb +153 -80
- data/lib/merb-core/tasks/merb_rake_helper.rb +12 -4
- data/lib/merb-core/tasks/stats.rake +1 -1
- data/lib/merb-core/test/helpers/mock_request_helper.rb +29 -22
- data/lib/merb-core/test/helpers/request_helper.rb +1 -1
- data/lib/merb-core/test/helpers/route_helper.rb +50 -4
- data/lib/merb-core/test/matchers/request_matchers.rb +2 -36
- data/lib/merb-core/test/matchers/view_matchers.rb +32 -22
- data/lib/merb-core/test/run_specs.rb +6 -5
- data/lib/merb-core/test/test_ext/rspec.rb +6 -19
- data/lib/merb-core/version.rb +1 -1
- metadata +5 -4
@@ -0,0 +1,33 @@
|
|
1
|
+
module Merb
|
2
|
+
module Rack
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
# A helper to build a rack response which implements a redirect. The status will be set to
|
6
|
+
# the passed in status if passed. If you pass in permanent it will be a 301, permanent redirect,
|
7
|
+
# otherwise it defaults to a temporary 302 redirect.
|
8
|
+
#
|
9
|
+
# ==== Parameters
|
10
|
+
# url<~to_s>:: The url to redirect to.
|
11
|
+
# options<Hash>:: A hash of options for the redirect
|
12
|
+
# status: The status code to use for the redirect
|
13
|
+
# permanent: True if this is a permanent redirect (301)
|
14
|
+
#
|
15
|
+
# ==== Returns
|
16
|
+
# <Array>:: A rack response to redirect to the specified url.
|
17
|
+
#
|
18
|
+
# @api plugin
|
19
|
+
def self.redirect(url, options = {})
|
20
|
+
# Build the rack array
|
21
|
+
status = options.delete(:status)
|
22
|
+
status ||= options[:permanent] ? 301 : 302
|
23
|
+
|
24
|
+
Merb.logger.info("Dispatcher redirecting to: #{url} (#{status})")
|
25
|
+
Merb.logger.flush
|
26
|
+
|
27
|
+
[status, { Merb::Const::LOCATION => url },
|
28
|
+
Merb::Rack::StreamWrapper.new("<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>")]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -20,12 +20,12 @@ module Merb
|
|
20
20
|
def strip_path_prefix(env)
|
21
21
|
['PATH_INFO', 'REQUEST_URI'].each do |path_key|
|
22
22
|
if env[path_key] =~ @path_prefix
|
23
|
-
env[path_key].sub!(@path_prefix,
|
24
|
-
env[path_key] =
|
23
|
+
env[path_key].sub!(@path_prefix, Merb::Const::EMPTY_STRING)
|
24
|
+
env[path_key] = Merb::Const::SLASH if env[path_key].empty?
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
end
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
@@ -8,16 +8,20 @@ module Merb
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def call(env)
|
11
|
-
path =
|
11
|
+
path = if env[Merb::Const::PATH_INFO]
|
12
|
+
env[Merb::Const::PATH_INFO].chomp(Merb::Const::SLASH)
|
13
|
+
else
|
14
|
+
Merb::Const::EMPTY_STRING
|
15
|
+
end
|
12
16
|
cached_path = (path.empty? ? 'index' : path) + '.html'
|
13
17
|
|
14
|
-
if file_exist?(path) && env[
|
18
|
+
if file_exist?(path) && env[Merb::Const::REQUEST_METHOD] =~ /GET|HEAD/ # Serve the file if it's there and the request method is GET or HEAD
|
15
19
|
serve_static(env)
|
16
|
-
elsif file_exist?(cached_path) && env[
|
17
|
-
env[
|
20
|
+
elsif file_exist?(cached_path) && env[Merb::Const::REQUEST_METHOD] =~ /GET|HEAD/ # Serve the page cache if it's there and the request method is GET or HEAD
|
21
|
+
env[Merb::Const::PATH_INFO] = cached_path
|
18
22
|
serve_static(env)
|
19
23
|
elsif path =~ /favicon\.ico/
|
20
|
-
return [404, {
|
24
|
+
return [404, { Merb::Const::CONTENT_TYPE => Merb::Const::TEXT_SLASH_HTML }, "404 Not Found."]
|
21
25
|
else
|
22
26
|
@app.call(env)
|
23
27
|
end
|
@@ -36,10 +40,10 @@ module Merb
|
|
36
40
|
# ==== Parameters
|
37
41
|
# env<Hash>:: Environment variables to pass on to the server.
|
38
42
|
def serve_static(env)
|
39
|
-
env[
|
43
|
+
env[Merb::Const::PATH_INFO] = ::Merb::Request.unescape(env[Merb::Const::PATH_INFO])
|
40
44
|
@static_server.call(env)
|
41
45
|
end
|
42
46
|
|
43
47
|
end
|
44
48
|
end
|
45
|
-
end
|
49
|
+
end
|
data/lib/merb-core/server.rb
CHANGED
@@ -18,10 +18,12 @@ module Merb
|
|
18
18
|
# ==== Alternatives
|
19
19
|
# If cluster is left out, then one process will be started. This process
|
20
20
|
# will be daemonized if Merb::Config[:daemonize] is true.
|
21
|
+
#
|
22
|
+
# @api private
|
21
23
|
def start(port, cluster=nil)
|
22
|
-
|
24
|
+
|
23
25
|
@port = port
|
24
|
-
@cluster = cluster
|
26
|
+
@cluster = cluster
|
25
27
|
|
26
28
|
if Merb::Config[:daemonize]
|
27
29
|
pidfile = pid_file(port)
|
@@ -29,7 +31,7 @@ module Merb
|
|
29
31
|
|
30
32
|
unless alive?(@port)
|
31
33
|
remove_pid_file(@port)
|
32
|
-
|
34
|
+
Merb.logger.warn! "Daemonizing..." if Merb::Config[:verbose]
|
33
35
|
daemonize(@port)
|
34
36
|
else
|
35
37
|
Merb.fatal! "Merb is already running on port #{port}.\n" \
|
@@ -47,79 +49,96 @@ module Merb
|
|
47
49
|
# ==== Returns
|
48
50
|
# Boolean::
|
49
51
|
# True if Merb is running on the specified port.
|
52
|
+
#
|
53
|
+
# @api private
|
50
54
|
def alive?(port)
|
51
|
-
puts "About to check if port #{port} is alive..." if Merb::Config[:verbose]
|
52
55
|
pidfile = pid_file(port)
|
53
|
-
|
54
|
-
pid = File.read(pidfile).chomp.to_i
|
55
|
-
puts "Process id is #{pid}" if Merb::Config[:verbose]
|
56
|
+
pid = pid_in_file(pidfile)
|
56
57
|
Process.kill(0, pid)
|
57
58
|
true
|
58
59
|
rescue Errno::ESRCH, Errno::ENOENT
|
59
60
|
false
|
60
61
|
rescue Errno::EACCES => e
|
61
|
-
Merb.fatal!("You don't have access to the PID file at #{pidfile}."
|
62
|
+
Merb.fatal!("You don't have access to the PID file at #{pidfile}: #{e.message}")
|
63
|
+
end
|
64
|
+
|
65
|
+
def pid_in_file(pidfile)
|
66
|
+
File.read(pidfile).chomp.to_i
|
62
67
|
end
|
63
68
|
|
64
69
|
# ==== Parameters
|
65
70
|
# port<~to_s>:: The port of the Merb process to kill.
|
66
|
-
# sig<~to_s>:: The signal to send to the process
|
71
|
+
# sig<~to_s>:: The signal to send to the process, the default is 9 - SIGKILL.
|
72
|
+
#
|
73
|
+
# No Name Default Action Description
|
74
|
+
# 1 SIGHUP terminate process terminal line hangup
|
75
|
+
# 2 SIGINT terminate process interrupt program
|
76
|
+
# 3 SIGQUIT create core image quit program
|
77
|
+
# 4 SIGILL create core image illegal instruction
|
78
|
+
# 9 SIGKILL terminate process kill program
|
79
|
+
# 15 SIGTERM terminate process software termination signal
|
80
|
+
# 30 SIGUSR1 terminate process User defined signal 1
|
81
|
+
# 31 SIGUSR2 terminate process User defined signal 2
|
67
82
|
#
|
68
83
|
# ==== Alternatives
|
69
|
-
# If you pass "all" as the port, the signal will be sent to all Merb
|
70
|
-
#
|
71
|
-
|
72
|
-
|
73
|
-
if sig == 9 && port == "main"
|
74
|
-
kill_pid("INT", pid_file("main"))
|
75
|
-
Dir["#{Merb.log_path}" / "*.pid"].each do |file|
|
76
|
-
kill_pid(9, file)
|
77
|
-
end
|
78
|
-
else
|
79
|
-
kill_pid(sig, pid_file(port))
|
80
|
-
end
|
81
|
-
|
84
|
+
# If you pass "all" as the port, the signal will be sent to all Merb processes.
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
def kill(port, sig = "INT")
|
82
88
|
if sig.is_a?(Integer)
|
83
89
|
sig = Signal.list.invert[sig]
|
84
90
|
end
|
91
|
+
|
92
|
+
Merb::BootLoader::BuildFramework.run
|
85
93
|
|
86
|
-
|
87
|
-
|
94
|
+
# If we kill the master, then the workers should be reaped also.
|
95
|
+
if %w(main master all).include?(port)
|
96
|
+
# If a graceful exit is requested then send INT to the master process.
|
97
|
+
#
|
98
|
+
# Otherwise read pids from pid files and try to kill each process in turn.
|
99
|
+
kill_pid(sig, pid_file("main")) if sig == "INT"
|
88
100
|
else
|
89
|
-
|
101
|
+
kill_pid(sig, pid_file(port))
|
90
102
|
end
|
91
103
|
end
|
92
|
-
|
104
|
+
|
105
|
+
# Sends the provided signal to the process pointed at by the provided pid file.
|
106
|
+
# @api private
|
93
107
|
def kill_pid(sig, file)
|
94
108
|
begin
|
95
|
-
pid =
|
96
|
-
Merb.logger.
|
109
|
+
pid = pid_in_file(file)
|
110
|
+
Merb.logger.fatal! "Killing pid #{pid} with #{sig}"
|
97
111
|
Process.kill(sig, pid)
|
98
112
|
FileUtils.rm(file) if File.exist?(file)
|
99
113
|
rescue Errno::EINVAL
|
100
|
-
Merb.fatal! "Failed to kill PID #{pid}: '#{sig}' is an invalid " \
|
114
|
+
Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: '#{sig}' is an invalid " \
|
101
115
|
"or unsupported signal number."
|
102
116
|
rescue Errno::EPERM
|
103
|
-
Merb.fatal! "Failed to kill PID #{pid}: Insufficient permissions."
|
117
|
+
Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Insufficient permissions."
|
104
118
|
rescue Errno::ESRCH
|
105
119
|
FileUtils.rm file
|
106
|
-
Merb.fatal! "Failed to kill PID #{pid}: Process is " \
|
120
|
+
Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Process is " \
|
107
121
|
"deceased or zombie."
|
108
122
|
rescue Errno::EACCES => e
|
109
|
-
Merb.fatal! e.message
|
123
|
+
Merb.logger.fatal! e.message
|
110
124
|
rescue Errno::ENOENT => e
|
111
|
-
|
125
|
+
# This should not cause abnormal exit, which is why
|
126
|
+
# we do not use Merb.fatal but instead just log with max level.
|
127
|
+
Merb.logger.fatal! "Could not find a PID file at #{file}. " \
|
128
|
+
"Most likely the process is no longer running and the pid file was not cleaned up."
|
112
129
|
rescue Exception => e
|
113
130
|
if !e.is_a?(SystemExit)
|
114
|
-
Merb.fatal! "Failed to kill PID #{pid}
|
131
|
+
Merb.logger.fatal! "Failed to kill PID #{pid.inspect} with #{sig.inspect}: #{e.message}"
|
115
132
|
end
|
116
133
|
end
|
117
134
|
end
|
118
135
|
|
119
136
|
# ==== Parameters
|
120
137
|
# port<~to_s>:: The port of the Merb process to daemonize.
|
138
|
+
#
|
139
|
+
# @api private
|
121
140
|
def daemonize(port)
|
122
|
-
|
141
|
+
Merb.logger.warn! "About to fork..." if Merb::Config[:verbose]
|
123
142
|
fork do
|
124
143
|
Process.setsid
|
125
144
|
exit if fork
|
@@ -131,26 +150,42 @@ module Merb
|
|
131
150
|
begin
|
132
151
|
Dir.chdir Merb::Config[:merb_root]
|
133
152
|
rescue Errno::EACCES => e
|
134
|
-
Merb.fatal! "You specified #{Merb::Config[:merb_root]} " \
|
135
|
-
"
|
153
|
+
Merb.fatal! "You specified Merb root as #{Merb::Config[:merb_root]}, " \
|
154
|
+
"yet the current user does not have access to it. ", e
|
136
155
|
end
|
137
156
|
at_exit { remove_pid_file(port) }
|
138
157
|
Merb::Config[:port] = port
|
139
158
|
bootup
|
140
159
|
end
|
141
160
|
rescue NotImplementedError => e
|
142
|
-
Merb.fatal! "Daemonized mode is not supported on your platform", e
|
161
|
+
Merb.fatal! "Daemonized mode is not supported on your platform. ", e
|
143
162
|
end
|
144
163
|
|
164
|
+
# Starts up Merb by running the bootloader and starting the adapter.
|
165
|
+
#
|
166
|
+
# @api private
|
145
167
|
def bootup
|
146
|
-
Merb.trap(
|
168
|
+
Merb.trap("TERM") { shutdown }
|
147
169
|
|
148
|
-
|
170
|
+
Merb.logger.warn! "Running bootloaders..." if Merb::Config[:verbose]
|
149
171
|
BootLoader.run
|
150
|
-
|
172
|
+
Merb.logger.warn! "Starting Rack adapter..." if Merb::Config[:verbose]
|
151
173
|
Merb.adapter.start(Merb::Config.to_hash)
|
152
174
|
end
|
153
175
|
|
176
|
+
# Shut down Merb, reap any workers if necessary.
|
177
|
+
#
|
178
|
+
# @api private
|
179
|
+
def shutdown(status = 0)
|
180
|
+
# reap_workers does exit but may not be called...
|
181
|
+
Merb::BootLoader::LoadClasses.reap_workers(status) if Merb::Config[:fork_for_class_load]
|
182
|
+
# which is why we exit explicitly here
|
183
|
+
exit(status)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Change process user/group to those specified in Merb::Config.
|
187
|
+
#
|
188
|
+
# @api private
|
154
189
|
def change_privilege
|
155
190
|
if Merb::Config[:user] && Merb::Config[:group]
|
156
191
|
Merb.logger.verbose! "About to change privilege to group " \
|
@@ -167,7 +202,7 @@ module Merb
|
|
167
202
|
|
168
203
|
# Removes a PID file used by the server from the filesystem.
|
169
204
|
# This uses :pid_file options from configuration when provided
|
170
|
-
# or merb.<port>.pid in log directory by default.
|
205
|
+
# or merb.<port/socket>.pid in log directory by default.
|
171
206
|
#
|
172
207
|
# ==== Parameters
|
173
208
|
# port<~to_s>::
|
@@ -175,11 +210,13 @@ module Merb
|
|
175
210
|
#
|
176
211
|
# ==== Alternatives
|
177
212
|
# If Merb::Config[:pid_file] has been specified, that will be used
|
178
|
-
# instead of the port based PID file.
|
213
|
+
# instead of the port/socket based PID file.
|
214
|
+
#
|
215
|
+
# @api private
|
179
216
|
def remove_pid_file(port)
|
180
217
|
pidfile = pid_file(port)
|
181
218
|
if File.exist?(pidfile)
|
182
|
-
|
219
|
+
Merb.logger.warn! "Removing pid file #{pidfile} (port/socket: #{port})..."
|
183
220
|
FileUtils.rm(pidfile)
|
184
221
|
end
|
185
222
|
end
|
@@ -194,37 +231,61 @@ module Merb
|
|
194
231
|
#
|
195
232
|
# ==== Alternatives
|
196
233
|
# If Merb::Config[:pid_file] has been specified, that will be used
|
197
|
-
# instead of the port based PID file.
|
234
|
+
# instead of the port/socket based PID file.
|
235
|
+
#
|
236
|
+
# @api private
|
198
237
|
def store_pid(port)
|
199
238
|
store_details(port)
|
200
239
|
end
|
201
240
|
|
241
|
+
# Delete the pidfile for the specified port/socket.
|
242
|
+
#
|
243
|
+
# @api private
|
202
244
|
def remove_pid(port)
|
203
245
|
FileUtils.rm(pid_file(port)) if File.file?(pid_file(port))
|
204
246
|
end
|
205
247
|
|
248
|
+
# Stores a PID file on the filesystem.
|
249
|
+
# This uses :pid_file options from configuration when provided
|
250
|
+
# or merb.<port/socket>.pid in log directory by default.
|
251
|
+
#
|
252
|
+
# ==== Parameters
|
253
|
+
# port<~to_s>::
|
254
|
+
# The port of the Merb process to whom the the PID file belongs to.
|
255
|
+
#
|
256
|
+
# ==== Alternatives
|
257
|
+
# If Merb::Config[:pid_file] has been specified, that will be used
|
258
|
+
# instead of the port/socket based PID file.
|
259
|
+
#
|
260
|
+
# @api private
|
206
261
|
def store_details(port = nil)
|
207
262
|
file = pid_file(port)
|
208
263
|
begin
|
209
264
|
FileUtils.mkdir_p(File.dirname(file))
|
210
265
|
rescue Errno::EACCES => e
|
211
|
-
Merb.fatal! "
|
212
|
-
"
|
266
|
+
Merb.fatal! "Failed to store Merb logs in #{File.dirname(file)}, " \
|
267
|
+
"permission denied. ", e
|
213
268
|
end
|
214
269
|
Merb.logger.warn! "Storing #{type} file to #{file}..." if Merb::Config[:verbose]
|
215
|
-
|
270
|
+
begin
|
271
|
+
File.open(file, 'w'){ |f| f.write(Process.pid.to_s) }
|
272
|
+
rescue Errno::EACCES => e
|
273
|
+
Merb.fatal! "Failed to access #{file}, permission denied.", e
|
274
|
+
end
|
216
275
|
end
|
217
276
|
|
218
|
-
# Gets the pid file for the specified port.
|
277
|
+
# Gets the pid file for the specified port/socket.
|
219
278
|
#
|
220
279
|
# ==== Parameters
|
221
280
|
# port<~to_s>::
|
222
|
-
# The port of the Merb process to whom the the PID file belongs to.
|
281
|
+
# The port/socket of the Merb process to whom the the PID file belongs to.
|
223
282
|
#
|
224
283
|
# ==== Returns
|
225
284
|
# String::
|
226
285
|
# Location of pid file for specified port. If clustered and pid_file option
|
227
|
-
# is specified, it adds the port value to the path.
|
286
|
+
# is specified, it adds the port/socket value to the path.
|
287
|
+
#
|
288
|
+
# @api private
|
228
289
|
def pid_file(port)
|
229
290
|
pidfile = Merb::Config[:pid_file] || (Merb.log_path / "merb.%s.pid")
|
230
291
|
pidfile % port
|
@@ -234,7 +295,9 @@ module Merb
|
|
234
295
|
#
|
235
296
|
# ==== Returns
|
236
297
|
# Array::
|
237
|
-
# List of pid file paths. If not clustered, array contains a single path.
|
298
|
+
# List of pid file paths. If not running clustered, the array contains a single path.
|
299
|
+
#
|
300
|
+
# @api private
|
238
301
|
def pid_files
|
239
302
|
if Merb::Config[:pid_file]
|
240
303
|
if Merb::Config[:cluster]
|
@@ -250,34 +313,33 @@ module Merb
|
|
250
313
|
# Change privileges of the process to the specified user and group.
|
251
314
|
#
|
252
315
|
# ==== Parameters
|
253
|
-
# user<String>:: The user
|
254
|
-
# group<String>:: The group
|
316
|
+
# user<String>:: The user to change the process to.
|
317
|
+
# group<String>:: The group to change the process to.
|
255
318
|
#
|
256
319
|
# ==== Alternatives
|
257
320
|
# If group is left out, the user will be used as the group.
|
321
|
+
#
|
322
|
+
# @api private
|
258
323
|
def _change_privilege(user, group=user)
|
259
|
-
|
260
324
|
Merb.logger.warn! "Changing privileges to #{user}:#{group}"
|
261
325
|
|
262
326
|
uid, gid = Process.euid, Process.egid
|
263
|
-
|
327
|
+
|
264
328
|
begin
|
265
329
|
target_uid = Etc.getpwnam(user).uid
|
266
330
|
rescue ArgumentError => e
|
267
|
-
Merb.fatal!(
|
268
|
-
"You tried to use user #{user}, but no such user was found", e)
|
331
|
+
Merb.fatal!("Failed to change to user #{user}, does the user exist?", e)
|
269
332
|
return false
|
270
333
|
end
|
271
|
-
|
334
|
+
|
272
335
|
begin
|
273
336
|
target_gid = Etc.getgrnam(group).gid
|
274
337
|
rescue ArgumentError => e
|
275
|
-
Merb.fatal!(
|
276
|
-
"You tried to use group #{group}, but no such group was found", e)
|
338
|
+
Merb.fatal!("Failed to change to group #{group}, does the group exist?", e)
|
277
339
|
return false
|
278
340
|
end
|
279
341
|
|
280
|
-
if uid != target_uid || gid != target_gid
|
342
|
+
if (uid != target_uid) || (gid != target_gid)
|
281
343
|
# Change process ownership
|
282
344
|
Process.initgroups(user, target_gid)
|
283
345
|
Process::GID.change_privilege(target_gid)
|
@@ -285,24 +347,27 @@ module Merb
|
|
285
347
|
end
|
286
348
|
true
|
287
349
|
rescue Errno::EPERM => e
|
288
|
-
Merb.fatal! "
|
350
|
+
Merb.fatal! "Permission denied for changing user:group to #{user}:#{group}.", e
|
289
351
|
false
|
290
352
|
end
|
291
|
-
|
353
|
+
|
354
|
+
# Add trap to enter IRB on SIGINT. Process exit if second SIGINT is received.
|
355
|
+
#
|
356
|
+
# @api private
|
292
357
|
def add_irb_trap
|
293
|
-
Merb.trap(
|
358
|
+
Merb.trap("INT") do
|
294
359
|
if @interrupted
|
295
|
-
|
360
|
+
Merb.logger.warn! "Interrupt received a second time, exiting!\n"
|
296
361
|
exit
|
297
362
|
end
|
298
363
|
|
299
364
|
@interrupted = true
|
300
|
-
|
365
|
+
Merb.logger.warn! "Interrupt a second time to quit."
|
301
366
|
Kernel.sleep 1.5
|
302
367
|
ARGV.clear # Avoid passing args to IRB
|
303
368
|
|
304
369
|
if @irb.nil?
|
305
|
-
require
|
370
|
+
require "irb"
|
306
371
|
IRB.setup(nil)
|
307
372
|
@irb = IRB::Irb.new(nil)
|
308
373
|
IRB.conf[:MAIN_CONTEXT] = @irb.context
|
@@ -311,7 +376,7 @@ module Merb
|
|
311
376
|
Merb.trap(:INT) { @irb.signal_handle }
|
312
377
|
catch(:IRB_EXIT) { @irb.eval_input }
|
313
378
|
|
314
|
-
|
379
|
+
Merb.logger.warn! "Exiting from IRB mode back into server mode."
|
315
380
|
@interrupted = false
|
316
381
|
add_irb_trap
|
317
382
|
end
|