wycats-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/CHANGELOG +136 -2
- data/CONTRIBUTORS +6 -0
- data/PUBLIC_CHANGELOG +15 -0
- data/Rakefile +12 -14
- data/lib/merb-core.rb +82 -43
- data/lib/merb-core/bootloader.rb +268 -60
- data/lib/merb-core/config.rb +119 -34
- data/lib/merb-core/controller/abstract_controller.rb +58 -18
- data/lib/merb-core/controller/exceptions.rb +2 -15
- data/lib/merb-core/controller/merb_controller.rb +28 -1
- data/lib/merb-core/controller/mime.rb +4 -0
- data/lib/merb-core/controller/mixins/controller.rb +14 -17
- data/lib/merb-core/controller/mixins/render.rb +23 -28
- data/lib/merb-core/controller/mixins/responder.rb +0 -1
- data/lib/merb-core/controller/template.rb +44 -20
- data/lib/merb-core/core_ext/kernel.rb +8 -3
- data/lib/merb-core/dispatch/default_exception/default_exception.rb +1 -1
- data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +3 -1
- data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +71 -67
- data/lib/merb-core/dispatch/default_exception/views/index.html.erb +6 -2
- data/lib/merb-core/dispatch/dispatcher.rb +5 -9
- data/lib/merb-core/dispatch/request.rb +46 -57
- data/lib/merb-core/dispatch/router.rb +83 -6
- data/lib/merb-core/dispatch/router/behavior.rb +87 -27
- data/lib/merb-core/dispatch/router/resources.rb +281 -167
- data/lib/merb-core/dispatch/router/route.rb +141 -27
- data/lib/merb-core/logger.rb +213 -202
- data/lib/merb-core/rack.rb +3 -1
- data/lib/merb-core/rack/adapter.rb +7 -4
- data/lib/merb-core/rack/adapter/ebb.rb +12 -13
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +2 -15
- data/lib/merb-core/rack/adapter/irb.rb +3 -2
- data/lib/merb-core/rack/adapter/mongrel.rb +22 -15
- data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +4 -16
- data/lib/merb-core/rack/adapter/thin.rb +21 -22
- data/lib/merb-core/rack/adapter/thin_turbo.rb +4 -11
- data/lib/merb-core/rack/adapter/webrick.rb +54 -18
- data/lib/merb-core/rack/handler/mongrel.rb +12 -13
- data/lib/merb-core/rack/middleware/csrf.rb +1 -1
- data/lib/merb-core/server.rb +135 -98
- data/lib/merb-core/tasks/gem_management.rb +50 -12
- data/lib/merb-core/tasks/merb.rb +1 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +9 -38
- data/lib/merb-core/tasks/stats.rake +2 -2
- data/lib/merb-core/test.rb +9 -3
- data/lib/merb-core/test/helpers.rb +1 -0
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +3 -2
- data/lib/merb-core/test/helpers/request_helper.rb +40 -372
- data/lib/merb-core/test/helpers/route_helper.rb +15 -7
- data/lib/merb-core/test/matchers.rb +1 -0
- data/lib/merb-core/test/matchers/controller_matchers.rb +4 -247
- data/lib/merb-core/test/matchers/view_matchers.rb +22 -4
- data/lib/merb-core/test/run_specs.rb +117 -25
- data/lib/merb-core/version.rb +1 -1
- metadata +1 -1
- data/lib/merb-core/vendor/facets.rb +0 -2
- data/lib/merb-core/vendor/facets/dictionary.rb +0 -433
- data/lib/merb-core/vendor/facets/inflect.rb +0 -342
data/lib/merb-core/rack.rb
CHANGED
@@ -3,6 +3,7 @@ module Merb
|
|
3
3
|
module Rack
|
4
4
|
autoload :Application, 'merb-core/rack/application'
|
5
5
|
autoload :Adapter, 'merb-core/rack/adapter'
|
6
|
+
autoload :AbstractAdapter, 'merb-core/rack/adapter/abstract'
|
6
7
|
autoload :Ebb, 'merb-core/rack/adapter/ebb'
|
7
8
|
autoload :EventedMongrel, 'merb-core/rack/adapter/evented_mongrel'
|
8
9
|
autoload :FastCGI, 'merb-core/rack/adapter/fcgi'
|
@@ -21,5 +22,6 @@ module Merb
|
|
21
22
|
autoload :ContentLength, 'merb-core/rack/middleware/content_length'
|
22
23
|
autoload :ConditionalGet, 'merb-core/rack/middleware/conditional_get'
|
23
24
|
autoload :Csrf, 'merb-core/rack/middleware/csrf'
|
25
|
+
autoload :StreamWrapper, 'merb-core/rack/stream_wrapper'
|
24
26
|
end # Rack
|
25
|
-
end # Merb
|
27
|
+
end # Merb
|
@@ -11,7 +11,11 @@ module Merb
|
|
11
11
|
# ==== Returns.
|
12
12
|
# Class:: The adapter class.
|
13
13
|
def get(id)
|
14
|
-
|
14
|
+
if @adapters[id.to_s]
|
15
|
+
Object.full_const_get(@adapters[id.to_s])
|
16
|
+
else
|
17
|
+
Merb.fatal! "The adapter #{id} did not exist"
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
# Registers a new Rack adapter.
|
@@ -36,9 +40,8 @@ module Merb
|
|
36
40
|
Adapter.register %w{runner}, :Runner
|
37
41
|
Adapter.register %w{smongrel swift}, :SwiftipliedMongrel
|
38
42
|
Adapter.register %w{thin}, :Thin
|
39
|
-
Adapter.register %w{thin-turbo},
|
43
|
+
Adapter.register %w{thin-turbo tt}, :ThinTurbo
|
40
44
|
Adapter.register %w{webrick}, :WEBrick
|
41
45
|
|
42
46
|
end # Rack
|
43
|
-
end # Merb
|
44
|
-
|
47
|
+
end # Merb
|
@@ -3,22 +3,21 @@ module Merb
|
|
3
3
|
|
4
4
|
module Rack
|
5
5
|
|
6
|
-
class Ebb
|
6
|
+
class Ebb < Merb::Rack::AbstractAdapter
|
7
7
|
# start an Ebb server on given host and port.
|
8
8
|
|
9
|
-
|
10
|
-
# opts<Hash>:: Options for Ebb (see below).
|
11
|
-
#
|
12
|
-
# ==== Options (opts)
|
13
|
-
# :host<String>:: The hostname that Ebb should serve.
|
14
|
-
# :port<Fixnum>:: The port Ebb should bind to.
|
15
|
-
# :app:: The application
|
16
|
-
def self.start(opts={})
|
17
|
-
Merb.logger.warn!("Using Ebb adapter")
|
9
|
+
def self.new_server(port)
|
18
10
|
Merb::Dispatcher.use_mutex = false
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
opts = @opts.merge(:port => port)
|
12
|
+
@th = Thread.new { Thread.current[:server] = ::Ebb.start_server(opts[:app], opts) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.start_server
|
16
|
+
@th.join
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.stop(status = 0)
|
20
|
+
::Ebb.stop_server
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
@@ -4,22 +4,9 @@ module Merb
|
|
4
4
|
module Rack
|
5
5
|
|
6
6
|
class EventedMongrel < Mongrel
|
7
|
-
|
8
|
-
#
|
9
|
-
# ==== Parameters
|
10
|
-
# opts<Hash>:: Options for Mongrel (see below).
|
11
|
-
#
|
12
|
-
# ==== Options (opts)
|
13
|
-
# :host<String>:: The hostname that Mongrel should serve.
|
14
|
-
# :port<Fixnum>:: The port Mongrel should bind to.
|
15
|
-
# :app<String>>:: The application name.
|
16
|
-
def self.start(opts={})
|
17
|
-
Merb.logger.warn!("Using EventedMongrel adapter")
|
7
|
+
def self.new_server(port)
|
18
8
|
Merb::Dispatcher.use_mutex = false
|
19
|
-
|
20
|
-
Merb::Server.change_privilege
|
21
|
-
server.register('/', ::Merb::Rack::Handler::Mongrel.new(opts[:app]))
|
22
|
-
server.run.join
|
9
|
+
super
|
23
10
|
end
|
24
11
|
end
|
25
12
|
end
|
@@ -10,8 +10,9 @@ module Merb
|
|
10
10
|
#
|
11
11
|
# ==== Alternatives
|
12
12
|
# If name is a hash, it will be merged with params.
|
13
|
-
def url(name,
|
14
|
-
|
13
|
+
def url(name, *args)
|
14
|
+
args << {}
|
15
|
+
Merb::Router.url(name, *args)
|
15
16
|
end
|
16
17
|
|
17
18
|
# Reloads classes using Merb::BootLoader::ReloadClasses.
|
@@ -4,23 +4,30 @@ module Merb
|
|
4
4
|
|
5
5
|
module Rack
|
6
6
|
|
7
|
-
class Mongrel
|
8
|
-
|
7
|
+
class Mongrel < Merb::Rack::AbstractAdapter
|
8
|
+
|
9
|
+
def self.stop(status = 0)
|
10
|
+
if @server
|
11
|
+
begin
|
12
|
+
@server.stop(true)
|
13
|
+
rescue Mongrel::TimeoutError
|
14
|
+
Merb.logger.fatal! "Your process took too long to shut " \
|
15
|
+
"down, so mongrel killed it."
|
16
|
+
end
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
9
20
|
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
# ==== Options (opts)
|
14
|
-
# :host<String>:: The hostname that Mongrel should serve.
|
15
|
-
# :port<Fixnum>:: The port Mongrel should bind to.
|
16
|
-
# :app<String>>:: The application name.
|
17
|
-
def self.start(opts={})
|
18
|
-
Merb.logger.warn!("Using Mongrel adapter")
|
19
|
-
server = ::Mongrel::HttpServer.new(opts[:host], opts[:port].to_i)
|
20
|
-
Merb::Server.change_privilege
|
21
|
-
server.register('/', ::Merb::Rack::Handler::Mongrel.new(opts[:app]))
|
22
|
-
server.run.join
|
21
|
+
def self.new_server(port)
|
22
|
+
@server = ::Mongrel::HttpServer.new(@opts[:host], port)
|
23
23
|
end
|
24
|
+
|
25
|
+
def self.start_server
|
26
|
+
@server.register('/', ::Merb::Rack::Handler::Mongrel.new(@opts[:app]))
|
27
|
+
@server.run.join
|
28
|
+
end
|
29
|
+
|
24
30
|
end
|
31
|
+
|
25
32
|
end
|
26
33
|
end
|
@@ -4,23 +4,11 @@ module Merb
|
|
4
4
|
module Rack
|
5
5
|
|
6
6
|
class SwiftipliedMongrel < Mongrel
|
7
|
-
|
8
|
-
#
|
9
|
-
# ==== Parameters
|
10
|
-
# opts<Hash>:: Options for Mongrel (see below).
|
11
|
-
#
|
12
|
-
# ==== Options (opts)
|
13
|
-
# :host<String>:: The hostname that Mongrel should serve.
|
14
|
-
# :port<Fixnum>:: The port Mongrel should bind to.
|
15
|
-
# :app<String>>:: The application name.
|
16
|
-
def self.start(opts={})
|
17
|
-
Merb.logger.warn!("Using SwiftipliedMongrel adapter")
|
7
|
+
def self.new_server(port)
|
18
8
|
Merb::Dispatcher.use_mutex = false
|
19
|
-
|
20
|
-
|
21
|
-
server.register('/', ::Merb::Rack::Handler::Mongrel.new(opts[:app]))
|
22
|
-
server.run.join
|
23
|
-
end
|
9
|
+
super
|
10
|
+
end
|
24
11
|
end
|
12
|
+
|
25
13
|
end
|
26
14
|
end
|
@@ -4,35 +4,34 @@ module Merb
|
|
4
4
|
|
5
5
|
module Rack
|
6
6
|
|
7
|
-
class Thin
|
7
|
+
class Thin < Merb::Rack::AbstractAdapter
|
8
8
|
# start a Thin server on given host and port.
|
9
9
|
|
10
|
-
|
11
|
-
# opts<Hash>:: Options for Thin (see below).
|
12
|
-
#
|
13
|
-
# ==== Options (opts)
|
14
|
-
# :host<String>:: The hostname that Thin should serve.
|
15
|
-
# :port<Fixnum>:: The port Thin should bind to.
|
16
|
-
# :socket<Fixnum>>:: The socket number that thin should bind to.
|
17
|
-
# :socket_file<String>>:: The socket file that thin should attach to.
|
18
|
-
# :app<String>>:: The application name.
|
19
|
-
def self.start(opts={})
|
10
|
+
def self.new_server(port)
|
20
11
|
Merb::Dispatcher.use_mutex = false
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
|
13
|
+
if (@opts[:socket] || @opts[:socket_file])
|
14
|
+
socket = port.to_s
|
15
|
+
socket_file = @opts[:socket_file] || "#{Merb.log_path}/#{Merb::Config[:name]}.#{socket}.sock"
|
24
16
|
Merb.logger.warn!("Using Thin adapter with socket file #{socket_file}.")
|
25
|
-
server = ::Thin::Server.new(socket_file, opts[:app], opts)
|
17
|
+
@server = ::Thin::Server.new(socket_file, @opts[:app], @opts)
|
26
18
|
else
|
27
|
-
Merb.logger.warn!("Using Thin adapter on host #{opts[:host]} and port #{
|
28
|
-
if opts[:host].include?('/')
|
29
|
-
|
30
|
-
end
|
31
|
-
server = ::Thin::Server.new(opts[:host], opts[:port].to_i, opts[:app], opts)
|
19
|
+
Merb.logger.warn!("Using Thin adapter on host #{@opts[:host]} and port #{port}.")
|
20
|
+
@opts[:host] = "#{@opts[:host]}-#{port}" if @opts[:host].include?('/')
|
21
|
+
@server = ::Thin::Server.new(@opts[:host], port, @opts[:app], @opts)
|
32
22
|
end
|
33
|
-
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.start_server
|
34
26
|
::Thin::Logging.silent = true
|
35
|
-
server.start
|
27
|
+
@server.start
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.stop(status = 0)
|
31
|
+
if @server
|
32
|
+
@server.stop
|
33
|
+
true
|
34
|
+
end
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
@@ -7,18 +7,11 @@ module Merb
|
|
7
7
|
class ThinTurbo < Thin
|
8
8
|
# start a Thin Turbo server on given host and port.
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# ==== Options (opts)
|
14
|
-
# :host<String>:: The hostname that Thin Turbo should serve.
|
15
|
-
# :port<Fixnum>:: The port Thin Turbo should bind to.
|
16
|
-
# :socket<Fixnum>>:: The socket number that thin should bind to.
|
17
|
-
# :socket_file<String>>:: The socket file that thin should attach to.
|
18
|
-
# :app<String>>:: The application name.
|
19
|
-
def self.start(opts={})
|
20
|
-
super(opts.merge(:backend => ::Thin::Backends::Turbo))
|
10
|
+
def self.new_server(port)
|
11
|
+
@opts.merge!(:backend => ::Thin::Backends::Turbo)
|
12
|
+
super
|
21
13
|
end
|
14
|
+
|
22
15
|
end
|
23
16
|
end
|
24
17
|
end
|
@@ -1,36 +1,72 @@
|
|
1
1
|
require 'webrick'
|
2
|
+
require 'webrick/utils'
|
2
3
|
require 'rack/handler/webrick'
|
3
4
|
module Merb
|
4
5
|
module Rack
|
5
6
|
|
6
|
-
class WEBrick
|
7
|
-
# start WEBrick server on given host and port.
|
7
|
+
class WEBrick < Merb::Rack::AbstractAdapter
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# ==== Options (opts)
|
13
|
-
# :host<String>:: The hostname that WEBrick should serve.
|
14
|
-
# :port<Fixnum>:: The port WEBrick should bind to.
|
15
|
-
# :app<String>>:: The application name.
|
16
|
-
def self.start(opts={})
|
17
|
-
Merb.logger.warn!("Using Webrick adapter")
|
9
|
+
class << self
|
10
|
+
attr_accessor :server
|
11
|
+
end
|
18
12
|
|
13
|
+
def self.new_server(port)
|
19
14
|
options = {
|
20
|
-
:Port =>
|
21
|
-
:BindAddress => opts[:host],
|
15
|
+
:Port => port,
|
16
|
+
:BindAddress => @opts[:host],
|
22
17
|
:Logger => Merb.logger,
|
23
18
|
:AccessLog => [
|
24
19
|
[Merb.logger, ::WEBrick::AccessLog::COMMON_LOG_FORMAT],
|
25
20
|
[Merb.logger, ::WEBrick::AccessLog::REFERER_LOG_FORMAT]
|
26
21
|
]
|
27
22
|
}
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
server.
|
32
|
-
server.start
|
23
|
+
|
24
|
+
sockets = ::WEBrick::Utils.create_listeners nil, port
|
25
|
+
@server = ::WEBrick::HTTPServer.new(options.merge(:DoNotListen => true))
|
26
|
+
@server.listeners.replace sockets
|
33
27
|
end
|
28
|
+
|
29
|
+
def self.start_server
|
30
|
+
@server.mount("/", ::Rack::Handler::WEBrick, @opts[:app])
|
31
|
+
@server.start
|
32
|
+
exit(@status)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.stop(status = 0)
|
36
|
+
@status = status
|
37
|
+
@server.shutdown
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.exit_process(status = 0)
|
41
|
+
end
|
42
|
+
|
43
|
+
# start WEBrick server on given host and port.
|
44
|
+
|
45
|
+
# ==== Parameters
|
46
|
+
# opts<Hash>:: Options for WEBrick (see below).
|
47
|
+
#
|
48
|
+
# ==== Options (opts)
|
49
|
+
# :host<String>:: The hostname that WEBrick should serve.
|
50
|
+
# :port<Fixnum>:: The port WEBrick should bind to.
|
51
|
+
# :app<String>>:: The application name.
|
52
|
+
# def self.start(opts={})
|
53
|
+
# Merb.logger.warn!("Using Webrick adapter")
|
54
|
+
#
|
55
|
+
# options = {
|
56
|
+
# :Port => opts[:port],
|
57
|
+
# :BindAddress => opts[:host],
|
58
|
+
# :Logger => Merb.logger,
|
59
|
+
# :AccessLog => [
|
60
|
+
# [Merb.logger, ::WEBrick::AccessLog::COMMON_LOG_FORMAT],
|
61
|
+
# [Merb.logger, ::WEBrick::AccessLog::REFERER_LOG_FORMAT]
|
62
|
+
# ]
|
63
|
+
# }
|
64
|
+
#
|
65
|
+
# server = ::WEBrick::HTTPServer.new(options)
|
66
|
+
# Merb::Server.change_privilege
|
67
|
+
# server.mount("/", ::Rack::Handler::WEBrick, opts[:app])
|
68
|
+
# server.start
|
69
|
+
# end
|
34
70
|
end
|
35
71
|
end
|
36
72
|
end
|
@@ -32,11 +32,15 @@ module Merb
|
|
32
32
|
# The hostname on which the app should run. Defaults to "0.0.0.0"
|
33
33
|
# :Port<Fixnum>:: The port for the app. Defaults to 8080.
|
34
34
|
def self.run(app, options={})
|
35
|
-
server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0',
|
35
|
+
@server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0',
|
36
36
|
options[:Port] || 8080)
|
37
|
-
server.register('/', ::Merb::Rack::Handler::Mongrel.new(app))
|
38
|
-
yield server if block_given?
|
39
|
-
server.run.join
|
37
|
+
@server.register('/', ::Merb::Rack::Handler::Mongrel.new(app))
|
38
|
+
yield @server if block_given?
|
39
|
+
@server.run.join
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.stop(block = true)
|
43
|
+
@server.stop
|
40
44
|
end
|
41
45
|
|
42
46
|
# ==== Parameters
|
@@ -63,8 +67,7 @@ module Merb
|
|
63
67
|
"rack.multiprocess" => false, # ???
|
64
68
|
"rack.run_once" => false,
|
65
69
|
|
66
|
-
"rack.url_scheme" => "http"
|
67
|
-
"rack.streaming" => true
|
70
|
+
"rack.url_scheme" => "http"
|
68
71
|
})
|
69
72
|
env["QUERY_STRING"] ||= ""
|
70
73
|
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
@@ -79,13 +82,9 @@ module Merb
|
|
79
82
|
}
|
80
83
|
}
|
81
84
|
|
82
|
-
|
83
|
-
body
|
84
|
-
|
85
|
-
body.each { |part|
|
86
|
-
response.body << part
|
87
|
-
}
|
88
|
-
end
|
85
|
+
body.each { |part|
|
86
|
+
response.body << part
|
87
|
+
}
|
89
88
|
response.finished
|
90
89
|
ensure
|
91
90
|
body.close if body.respond_to? :close
|
@@ -10,7 +10,7 @@ module Merb
|
|
10
10
|
|
11
11
|
def call(env)
|
12
12
|
status, header, body = @app.call(env)
|
13
|
-
|
13
|
+
body = body.to_s
|
14
14
|
if env[Merb::Const::REQUEST_METHOD] == Merb::Const::GET
|
15
15
|
body = process_response(body) if valid_content_type?(header[Merb::Const::CONTENT_TYPE])
|
16
16
|
elsif env[Merb::Const::REQUEST_METHOD] == Merb::Const::POST
|
data/lib/merb-core/server.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'etc'
|
2
|
+
|
2
3
|
module Merb
|
3
4
|
|
4
5
|
# Server encapsulates the management of Merb daemons.
|
@@ -18,46 +19,25 @@ module Merb
|
|
18
19
|
# If cluster is left out, then one process will be started. This process
|
19
20
|
# will be daemonized if Merb::Config[:daemonize] is true.
|
20
21
|
def start(port, cluster=nil)
|
22
|
+
|
21
23
|
@port = port
|
22
|
-
@cluster = cluster
|
23
|
-
if @cluster
|
24
|
-
@port.to_i.upto(@port.to_i + @cluster.to_i-1) do |port|
|
25
|
-
pidfile = pid_file(port)
|
26
|
-
pid = IO.read(pidfile).chomp.to_i if File.exist?(pidfile)
|
24
|
+
@cluster = cluster
|
27
25
|
|
28
|
-
|
29
|
-
remove_pid_file(port)
|
30
|
-
puts "Starting merb server on port #{port}, pid file: #{pidfile} and process id is #{pid}" if Merb::Config[:verbose]
|
31
|
-
daemonize(port)
|
32
|
-
else
|
33
|
-
raise "Merb is already running: port is #{port}, pid file: #{pidfile}, process id is #{pid}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
elsif Merb::Config[:daemonize]
|
26
|
+
if Merb::Config[:daemonize]
|
37
27
|
pidfile = pid_file(port)
|
38
|
-
pid =
|
28
|
+
pid = File.read(pidfile).chomp.to_i if File.exist?(pidfile)
|
39
29
|
|
40
30
|
unless alive?(@port)
|
41
31
|
remove_pid_file(@port)
|
42
32
|
puts "Daemonizing..." if Merb::Config[:verbose]
|
43
33
|
daemonize(@port)
|
44
34
|
else
|
45
|
-
|
35
|
+
Merb.fatal! "Merb is already running on port #{port}.\n" \
|
36
|
+
"\e[0m \e[1;31;47mpid file: \e[34;47m#{pidfile}" \
|
37
|
+
"\e[1;31;47m, process id is \e[34;47m#{pid}."
|
46
38
|
end
|
47
39
|
else
|
48
|
-
|
49
|
-
|
50
|
-
if Merb::Config[:console_trap]
|
51
|
-
add_irb_trap
|
52
|
-
else
|
53
|
-
trap('INT') { puts "\nExiting"; exit }
|
54
|
-
end
|
55
|
-
|
56
|
-
puts "Running bootloaders..." if Merb::Config[:verbose]
|
57
|
-
BootLoader.run
|
58
|
-
puts "Starting Rack adapter..." if Merb::Config[:verbose]
|
59
|
-
Merb.logger.info! "Starting Merb server listening at #{Merb::Config[:host]}:#{port}"
|
60
|
-
Merb.adapter.start(Merb::Config.to_hash)
|
40
|
+
bootup
|
61
41
|
end
|
62
42
|
end
|
63
43
|
|
@@ -71,12 +51,14 @@ module Merb
|
|
71
51
|
puts "About to check if port #{port} is alive..." if Merb::Config[:verbose]
|
72
52
|
pidfile = pid_file(port)
|
73
53
|
puts "Pidfile is #{pidfile}..." if Merb::Config[:verbose]
|
74
|
-
pid =
|
54
|
+
pid = File.read(pidfile).chomp.to_i
|
75
55
|
puts "Process id is #{pid}" if Merb::Config[:verbose]
|
76
56
|
Process.kill(0, pid)
|
77
57
|
true
|
78
|
-
rescue
|
58
|
+
rescue Errno::ESRCH, Errno::ENOENT
|
79
59
|
false
|
60
|
+
rescue Errno::EACCES => e
|
61
|
+
Merb.fatal!("You don't have access to the PID file at #{pidfile}.", e)
|
80
62
|
end
|
81
63
|
|
82
64
|
# ==== Parameters
|
@@ -86,32 +68,51 @@ module Merb
|
|
86
68
|
# ==== Alternatives
|
87
69
|
# If you pass "all" as the port, the signal will be sent to all Merb
|
88
70
|
# processes.
|
89
|
-
def kill(port, sig=
|
71
|
+
def kill(port, sig="INT")
|
90
72
|
Merb::BootLoader::BuildFramework.run
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
+
|
82
|
+
if sig.is_a?(Integer)
|
83
|
+
sig = Signal.list.invert[sig]
|
84
|
+
end
|
94
85
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
86
|
+
if sig == "KILL" && port == "main"
|
87
|
+
Merb.fatal! "Killed all PIDs with signal KILL"
|
88
|
+
else
|
89
|
+
Merb.fatal! "Killed #{port} with signal #{sig}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def kill_pid(sig, file)
|
94
|
+
begin
|
95
|
+
pid = File.read(file).chomp.to_i
|
96
|
+
Merb.logger.warn! "Killing pid #{pid}"
|
97
|
+
Process.kill(sig, pid)
|
98
|
+
FileUtils.rm(file) if File.exist?(file)
|
99
|
+
rescue Errno::EINVAL
|
100
|
+
Merb.fatal! "Failed to kill PID #{pid}: '#{sig}' is an invalid " \
|
101
|
+
"or unsupported signal number."
|
102
|
+
rescue Errno::EPERM
|
103
|
+
Merb.fatal! "Failed to kill PID #{pid}: Insufficient permissions."
|
104
|
+
rescue Errno::ESRCH
|
105
|
+
FileUtils.rm file
|
106
|
+
Merb.fatal! "Failed to kill PID #{pid}: Process is " \
|
107
|
+
"deceased or zombie."
|
108
|
+
rescue Errno::EACCES => e
|
109
|
+
Merb.fatal! e.message, e
|
110
|
+
rescue Errno::ENOENT => e
|
111
|
+
Merb.fatal! "Could not find a PID file at #{file}", e
|
112
|
+
rescue Exception => e
|
113
|
+
if !e.is_a?(SystemExit)
|
114
|
+
Merb.fatal! "Failed to kill PID #{pid}", e
|
111
115
|
end
|
112
|
-
ensure
|
113
|
-
Merb.started = false
|
114
|
-
exit
|
115
116
|
end
|
116
117
|
end
|
117
118
|
|
@@ -122,28 +123,45 @@ module Merb
|
|
122
123
|
fork do
|
123
124
|
Process.setsid
|
124
125
|
exit if fork
|
126
|
+
Merb.logger.warn! "In #{Process.pid}" if Merb.logger
|
125
127
|
File.umask 0000
|
126
128
|
STDIN.reopen "/dev/null"
|
127
129
|
STDOUT.reopen "/dev/null", "a"
|
128
130
|
STDERR.reopen STDOUT
|
129
|
-
|
130
|
-
|
131
|
+
begin
|
132
|
+
Dir.chdir Merb::Config[:merb_root]
|
133
|
+
rescue Errno::EACCES => e
|
134
|
+
Merb.fatal! "You specified #{Merb::Config[:merb_root]} " \
|
135
|
+
"as the Merb root, but you did not have access to it.", e
|
136
|
+
end
|
131
137
|
at_exit { remove_pid_file(port) }
|
132
138
|
Merb::Config[:port] = port
|
133
|
-
|
134
|
-
Merb.adapter.start(Merb::Config.to_hash)
|
139
|
+
bootup
|
135
140
|
end
|
141
|
+
rescue NotImplementedError => e
|
142
|
+
Merb.fatal! "Daemonized mode is not supported on your platform", e
|
143
|
+
end
|
144
|
+
|
145
|
+
def bootup
|
146
|
+
Merb.trap('TERM') { exit }
|
147
|
+
|
148
|
+
puts "Running bootloaders..." if Merb::Config[:verbose]
|
149
|
+
BootLoader.run
|
150
|
+
puts "Starting Rack adapter..." if Merb::Config[:verbose]
|
151
|
+
Merb.adapter.start(Merb::Config.to_hash)
|
136
152
|
end
|
137
153
|
|
138
154
|
def change_privilege
|
139
|
-
if Merb::Config[:user]
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
155
|
+
if Merb::Config[:user] && Merb::Config[:group]
|
156
|
+
Merb.logger.verbose! "About to change privilege to group " \
|
157
|
+
"#{Merb::Config[:group]} and user #{Merb::Config[:user]}"
|
158
|
+
_change_privilege(Merb::Config[:user], Merb::Config[:group])
|
159
|
+
elsif Merb::Config[:user]
|
160
|
+
Merb.logger.verbose! "About to change privilege to user " \
|
161
|
+
"#{Merb::Config[:user]}"
|
162
|
+
_change_privilege(Merb::Config[:user])
|
163
|
+
else
|
164
|
+
return true
|
147
165
|
end
|
148
166
|
end
|
149
167
|
|
@@ -160,8 +178,10 @@ module Merb
|
|
160
178
|
# instead of the port based PID file.
|
161
179
|
def remove_pid_file(port)
|
162
180
|
pidfile = pid_file(port)
|
163
|
-
|
164
|
-
|
181
|
+
if File.exist?(pidfile)
|
182
|
+
puts "Removing pid file #{pidfile} (port is #{port})..."
|
183
|
+
FileUtils.rm(pidfile)
|
184
|
+
end
|
165
185
|
end
|
166
186
|
|
167
187
|
# Stores a PID file on the filesystem.
|
@@ -176,11 +196,23 @@ module Merb
|
|
176
196
|
# If Merb::Config[:pid_file] has been specified, that will be used
|
177
197
|
# instead of the port based PID file.
|
178
198
|
def store_pid(port)
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
199
|
+
store_details(port)
|
200
|
+
end
|
201
|
+
|
202
|
+
def remove_pid(port)
|
203
|
+
FileUtils.rm(pid_file(port)) if File.file?(pid_file(port))
|
204
|
+
end
|
205
|
+
|
206
|
+
def store_details(port = nil)
|
207
|
+
file = pid_file(port)
|
208
|
+
begin
|
209
|
+
FileUtils.mkdir_p(File.dirname(file))
|
210
|
+
rescue Errno::EACCES => e
|
211
|
+
Merb.fatal! "You tried to store Merb logs in #{File.dirname(file)}, " \
|
212
|
+
"but you did not have access.", e
|
213
|
+
end
|
214
|
+
Merb.logger.warn! "Storing #{type} file to #{file}..." if Merb::Config[:verbose]
|
215
|
+
File.open(file, 'w'){ |f| f.write(Process.pid.to_s) }
|
184
216
|
end
|
185
217
|
|
186
218
|
# Gets the pid file for the specified port.
|
@@ -194,20 +226,8 @@ module Merb
|
|
194
226
|
# Location of pid file for specified port. If clustered and pid_file option
|
195
227
|
# is specified, it adds the port value to the path.
|
196
228
|
def pid_file(port)
|
197
|
-
|
198
|
-
|
199
|
-
if Merb::Config[:cluster]
|
200
|
-
ext = File.extname(Merb::Config[:pid_file])
|
201
|
-
base = File.basename(Merb::Config[:pid_file], ext)
|
202
|
-
dir = File.dirname(Merb::Config[:pid_file])
|
203
|
-
File.join(dir, "#{base}.#{port}#{ext}")
|
204
|
-
else
|
205
|
-
Merb::Config[:pid_file]
|
206
|
-
end
|
207
|
-
else
|
208
|
-
pidfile = Merb.log_path / "merb.#{port}.pid"
|
209
|
-
Merb.log_path / "merb.#{port}.pid"
|
210
|
-
end
|
229
|
+
pidfile = Merb::Config[:pid_file] || (Merb.log_path / "merb.%s.pid")
|
230
|
+
pidfile % port
|
211
231
|
end
|
212
232
|
|
213
233
|
# Get a list of the pid files.
|
@@ -218,10 +238,7 @@ module Merb
|
|
218
238
|
def pid_files
|
219
239
|
if Merb::Config[:pid_file]
|
220
240
|
if Merb::Config[:cluster]
|
221
|
-
|
222
|
-
base = File.basename(Merb::Config[:pid_file], ext)
|
223
|
-
dir = File.dirname(Merb::Config[:pid_file])
|
224
|
-
Dir[dir / "#{base}.*#{ext}"]
|
241
|
+
Dir[Merb::Config[:pid_file] % "*"]
|
225
242
|
else
|
226
243
|
[ Merb::Config[:pid_file] ]
|
227
244
|
end
|
@@ -240,11 +257,25 @@ module Merb
|
|
240
257
|
# If group is left out, the user will be used as the group.
|
241
258
|
def _change_privilege(user, group=user)
|
242
259
|
|
243
|
-
|
260
|
+
Merb.logger.warn! "Changing privileges to #{user}:#{group}"
|
244
261
|
|
245
262
|
uid, gid = Process.euid, Process.egid
|
246
|
-
|
247
|
-
|
263
|
+
|
264
|
+
begin
|
265
|
+
target_uid = Etc.getpwnam(user).uid
|
266
|
+
rescue ArgumentError => e
|
267
|
+
Merb.fatal!(
|
268
|
+
"You tried to use user #{user}, but no such user was found", e)
|
269
|
+
return false
|
270
|
+
end
|
271
|
+
|
272
|
+
begin
|
273
|
+
target_gid = Etc.getgrnam(group).gid
|
274
|
+
rescue ArgumentError => e
|
275
|
+
Merb.fatal!(
|
276
|
+
"You tried to use group #{group}, but no such group was found", e)
|
277
|
+
return false
|
278
|
+
end
|
248
279
|
|
249
280
|
if uid != target_uid || gid != target_gid
|
250
281
|
# Change process ownership
|
@@ -252,13 +283,19 @@ module Merb
|
|
252
283
|
Process::GID.change_privilege(target_gid)
|
253
284
|
Process::UID.change_privilege(target_uid)
|
254
285
|
end
|
286
|
+
true
|
255
287
|
rescue Errno::EPERM => e
|
256
|
-
|
288
|
+
Merb.fatal! "Couldn't change user and group to #{user}:#{group}", e
|
289
|
+
false
|
257
290
|
end
|
258
291
|
|
259
292
|
def add_irb_trap
|
260
|
-
trap('INT') do
|
261
|
-
|
293
|
+
Merb.trap('INT') do
|
294
|
+
if @interrupted
|
295
|
+
puts "Exiting\n"
|
296
|
+
exit
|
297
|
+
end
|
298
|
+
|
262
299
|
@interrupted = true
|
263
300
|
puts "Interrupt a second time to quit"
|
264
301
|
Kernel.sleep 1.5
|
@@ -271,7 +308,7 @@ module Merb
|
|
271
308
|
IRB.conf[:MAIN_CONTEXT] = @irb.context
|
272
309
|
end
|
273
310
|
|
274
|
-
trap(:INT) { @irb.signal_handle }
|
311
|
+
Merb.trap(:INT) { @irb.signal_handle }
|
275
312
|
catch(:IRB_EXIT) { @irb.eval_input }
|
276
313
|
|
277
314
|
puts "Exiting IRB mode, back in server mode"
|