textgoeshere-daemon-kit 0.1.8rc3
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/.gitignore +5 -0
- data/Configuration.txt +110 -0
- data/Deployment.txt +113 -0
- data/History.txt +124 -0
- data/Logging.txt +96 -0
- data/PostInstall.txt +6 -0
- data/README.rdoc +128 -0
- data/Rakefile +29 -0
- data/RuoteParticipants.txt +113 -0
- data/TODO.txt +27 -0
- data/bin/daemon-kit +18 -0
- data/config/website.yml +2 -0
- data/daemon-kit.gemspec +265 -0
- data/lib/daemon_kit/abstract_logger.rb +249 -0
- data/lib/daemon_kit/amqp.rb +39 -0
- data/lib/daemon_kit/application.rb +230 -0
- data/lib/daemon_kit/arguments.rb +165 -0
- data/lib/daemon_kit/commands/console.rb +38 -0
- data/lib/daemon_kit/commands/destroy.rb +10 -0
- data/lib/daemon_kit/commands/generate.rb +10 -0
- data/lib/daemon_kit/config.rb +113 -0
- data/lib/daemon_kit/console_daemon.rb +2 -0
- data/lib/daemon_kit/core_ext/configurable.rb +96 -0
- data/lib/daemon_kit/core_ext/string.rb +22 -0
- data/lib/daemon_kit/core_ext.rb +1 -0
- data/lib/daemon_kit/cron.rb +48 -0
- data/lib/daemon_kit/cucumber/world.rb +38 -0
- data/lib/daemon_kit/deployment/capistrano.rb +516 -0
- data/lib/daemon_kit/em.rb +43 -0
- data/lib/daemon_kit/error_handlers/base.rb +32 -0
- data/lib/daemon_kit/error_handlers/hoptoad.rb +180 -0
- data/lib/daemon_kit/exceptions.rb +15 -0
- data/lib/daemon_kit/generators/base.rb +60 -0
- data/lib/daemon_kit/generators.rb +67 -0
- data/lib/daemon_kit/initializer.rb +453 -0
- data/lib/daemon_kit/jabber.rb +171 -0
- data/lib/daemon_kit/nanite/agent.rb +77 -0
- data/lib/daemon_kit/nanite.rb +7 -0
- data/lib/daemon_kit/pid_file.rb +61 -0
- data/lib/daemon_kit/ruote_participants.rb +125 -0
- data/lib/daemon_kit/ruote_pseudo_participant.rb +68 -0
- data/lib/daemon_kit/ruote_workitem.rb +187 -0
- data/lib/daemon_kit/safety.rb +84 -0
- data/lib/daemon_kit/tasks/environment.rake +10 -0
- data/lib/daemon_kit/tasks/framework.rake +123 -0
- data/lib/daemon_kit/tasks/god.rake +62 -0
- data/lib/daemon_kit/tasks/log.rake +8 -0
- data/lib/daemon_kit/tasks/monit.rake +29 -0
- data/lib/daemon_kit/tasks.rb +2 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/CHANGELOG.rdoc +89 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/LICENSE +20 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/README.rdoc +297 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/Thorfile +69 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/create_file.rb +103 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/directory.rb +91 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/empty_directory.rb +134 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/file_manipulation.rb +223 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/inject_into_file.rb +104 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions.rb +296 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/base.rb +540 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/core_ext/ordered_hash.rb +100 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/error.rb +30 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/group.rb +271 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/invocation.rb +180 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser/argument.rb +67 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser/arguments.rb +150 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser/option.rb +128 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser/options.rb +169 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser.rb +4 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/rake_compat.rb +66 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/runner.rb +314 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/shell/basic.rb +239 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/shell/color.rb +108 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/shell.rb +83 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/task.rb +102 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/util.rb +224 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/version.rb +3 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor.rb +244 -0
- data/lib/daemon_kit/xmpp.rb +100 -0
- data/lib/daemon_kit.rb +59 -0
- data/lib/generators/daemon_kit/amqp/USAGE +5 -0
- data/lib/generators/daemon_kit/amqp/amqp_generator.rb +24 -0
- data/lib/generators/daemon_kit/amqp/templates/config/amqp.yml +28 -0
- data/lib/generators/daemon_kit/amqp/templates/config/pre-daemonize/amqp.rb +7 -0
- data/lib/generators/daemon_kit/amqp/templates/libexec/%app_name%-daemon.rb +37 -0
- data/lib/generators/daemon_kit/app/USAGE +7 -0
- data/lib/generators/daemon_kit/app/app_generator.rb +140 -0
- data/lib/generators/daemon_kit/app/templates/Gemfile +8 -0
- data/lib/generators/daemon_kit/app/templates/README.tt +58 -0
- data/lib/generators/daemon_kit/app/templates/Rakefile +6 -0
- data/lib/generators/daemon_kit/app/templates/bin/daemon.tt +7 -0
- data/lib/generators/daemon_kit/app/templates/config/arguments.rb +12 -0
- data/lib/generators/daemon_kit/app/templates/config/boot.rb +70 -0
- data/lib/generators/daemon_kit/app/templates/config/environment.rb.tt +26 -0
- data/lib/generators/daemon_kit/app/templates/config/environments/development.rb +2 -0
- data/lib/generators/daemon_kit/app/templates/config/environments/production.rb +5 -0
- data/lib/generators/daemon_kit/app/templates/config/environments/test.rb +2 -0
- data/lib/generators/daemon_kit/app/templates/config/post-daemonize/readme +5 -0
- data/lib/generators/daemon_kit/app/templates/config/pre-daemonize/readme +12 -0
- data/lib/generators/daemon_kit/app/templates/lib/%app_name%.rb +2 -0
- data/lib/generators/daemon_kit/app/templates/libexec/%app_name%-daemon.rb +18 -0
- data/lib/generators/daemon_kit/app/templates/script/console +3 -0
- data/lib/generators/daemon_kit/app/templates/script/destroy +3 -0
- data/lib/generators/daemon_kit/app/templates/script/generate +3 -0
- data/lib/generators/daemon_kit/capistrano/capistrano_generator.rb +26 -0
- data/lib/generators/daemon_kit/capistrano/templates/Capfile +10 -0
- data/lib/generators/daemon_kit/capistrano/templates/USAGE +10 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/deploy/logrotate.erb +13 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/deploy/production.rb.tt +6 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/deploy/staging.rb.tt +6 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/deploy.rb.tt +67 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/environments/staging.rb +0 -0
- data/lib/generators/daemon_kit/cron/USAGE +5 -0
- data/lib/generators/daemon_kit/cron/cron_generator.rb +24 -0
- data/lib/generators/daemon_kit/cron/templates/config/pre-daemonize/cron.rb +11 -0
- data/lib/generators/daemon_kit/cron/templates/libexec/%app_name%-daemon.rb +43 -0
- data/lib/generators/daemon_kit/cucumber/USAGE +11 -0
- data/lib/generators/daemon_kit/cucumber/cucumber_generator.rb +45 -0
- data/lib/generators/daemon_kit/cucumber/templates/config/environments/cucumber.rb +2 -0
- data/lib/generators/daemon_kit/cucumber/templates/features/step_definitions/.empty_directory +0 -0
- data/lib/generators/daemon_kit/cucumber/templates/features/support/env.rb +7 -0
- data/lib/generators/daemon_kit/cucumber/templates/script/cucumber +7 -0
- data/lib/generators/daemon_kit/cucumber/templates/tasks/cucumber.rake +13 -0
- data/lib/generators/daemon_kit/nanite_agent/USAGE +5 -0
- data/lib/generators/daemon_kit/nanite_agent/nanite_agent_generator.rb +29 -0
- data/lib/generators/daemon_kit/nanite_agent/templates/config/nanite.yml +35 -0
- data/lib/generators/daemon_kit/nanite_agent/templates/config/pre-daemonize/nanite_agent.rb +6 -0
- data/lib/generators/daemon_kit/nanite_agent/templates/lib/actors/sample.rb +11 -0
- data/lib/generators/daemon_kit/nanite_agent/templates/libexec/%app_name%-daemon.rb +31 -0
- data/lib/generators/daemon_kit/rspec/USAGE +5 -0
- data/lib/generators/daemon_kit/rspec/rspec_generator.rb +20 -0
- data/lib/generators/daemon_kit/rspec/templates/spec/%app_name%_spec.rb +11 -0
- data/lib/generators/daemon_kit/rspec/templates/spec/spec.opts +1 -0
- data/lib/generators/daemon_kit/rspec/templates/spec/spec_helper.rb +23 -0
- data/lib/generators/daemon_kit/rspec/templates/tasks/rspec.rake +19 -0
- data/lib/generators/daemon_kit/ruote/USAGE +5 -0
- data/lib/generators/daemon_kit/ruote/ruote_generator.rb +29 -0
- data/lib/generators/daemon_kit/ruote/templates/config/amqp.yml +30 -0
- data/lib/generators/daemon_kit/ruote/templates/config/pre-daemonize/ruote.rb +13 -0
- data/lib/generators/daemon_kit/ruote/templates/config/ruote.yml +23 -0
- data/lib/generators/daemon_kit/ruote/templates/lib/%app_name%.rb +4 -0
- data/lib/generators/daemon_kit/ruote/templates/lib/sample.rb +26 -0
- data/lib/generators/daemon_kit/ruote/templates/libexec/%app_name%-daemon.rb +33 -0
- data/lib/generators/daemon_kit/test_unit/USAGE +5 -0
- data/lib/generators/daemon_kit/test_unit/templates/tasks/test_unit.rake +7 -0
- data/lib/generators/daemon_kit/test_unit/templates/test/%app_name%_test.rb.tt +9 -0
- data/lib/generators/daemon_kit/test_unit/templates/test/test_helper.rb +6 -0
- data/lib/generators/daemon_kit/test_unit/test_unit_generator.rb +20 -0
- data/lib/generators/daemon_kit/xmpp/templates/config/pre-daemonize/xmpp.rb +6 -0
- data/lib/generators/daemon_kit/xmpp/templates/config/xmpp.yml +29 -0
- data/lib/generators/daemon_kit/xmpp/templates/libexec/%app_name%-daemon.rb +27 -0
- data/lib/generators/daemon_kit/xmpp/xmpp_generator.rb +24 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +71 -0
- data/spec/abstract_logger_spec.rb +126 -0
- data/spec/argument_spec.rb +70 -0
- data/spec/config_spec.rb +83 -0
- data/spec/configurable_spec.rb +56 -0
- data/spec/daemon_kit_spec.rb +7 -0
- data/spec/error_handlers_spec.rb +23 -0
- data/spec/fixtures/env.yml +15 -0
- data/spec/fixtures/noenv.yml +4 -0
- data/spec/initializer_spec.rb +26 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +27 -0
- data/tasks/cucumber.rake +13 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/tests.rake +6 -0
- data/templates/god/god.erb +69 -0
- data/templates/monit/monit.erb +14 -0
- data/test/test_amqp_generator.rb +48 -0
- data/test/test_cron_generator.rb +45 -0
- data/test/test_daemon-kit_generator.rb +84 -0
- data/test/test_daemon_kit_config.rb +28 -0
- data/test/test_deploy_capistrano_generator.rb +48 -0
- data/test/test_generator_helper.rb +29 -0
- data/test/test_helper.rb +7 -0
- data/test/test_nanite_agent_generator.rb +49 -0
- data/test/test_ruote_generator.rb +51 -0
- data/test/test_test_unit_generator.rb +46 -0
- metadata +325 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module DaemonKit
|
|
2
|
+
|
|
3
|
+
# EventMachine forms a critical part of the daemon-kit toolset, and
|
|
4
|
+
# especially of daemon process developers.
|
|
5
|
+
#
|
|
6
|
+
# This class abstracts away the difficulties of managing multiple
|
|
7
|
+
# libraries that all utilize the event reactor.
|
|
8
|
+
class EM
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
|
|
12
|
+
# Start a reactor, just like classical EM.run. If the block is
|
|
13
|
+
# provided, the method will block and call the provided block
|
|
14
|
+
# argument inside the running reactor. If the block argument is
|
|
15
|
+
# not provided the reactor will be started in a separate thread
|
|
16
|
+
# and the program will continue to run after the method. All the
|
|
17
|
+
# signal traps are configured to shutdown the reactor when the
|
|
18
|
+
# daemon exists.
|
|
19
|
+
def run(&block)
|
|
20
|
+
if ::EM.reactor_running?
|
|
21
|
+
DaemonKit.logger.warn "EventMachine reactor already running"
|
|
22
|
+
block.call if block_given?
|
|
23
|
+
|
|
24
|
+
else
|
|
25
|
+
if block_given?
|
|
26
|
+
::EM.run { block.call }
|
|
27
|
+
else
|
|
28
|
+
Thread.main[:_dk_reactor] = Thread.new { EM.run {} }
|
|
29
|
+
DaemonKit.trap( 'INT' ) { DaemonKit::EM.stop }
|
|
30
|
+
DaemonKit.trap( 'TERM' ) { DaemonKit::EM.stop }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Stop the reactor
|
|
36
|
+
def stop
|
|
37
|
+
::EM.stop_event_loop if ::EM.reactor_running?
|
|
38
|
+
Thread.main[:_dk_reactor].join
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module DaemonKit
|
|
2
|
+
module ErrorHandlers
|
|
3
|
+
# Error handlers in DaemonKit are used by the #Safety class. Any
|
|
4
|
+
# error handler has to support the interface provided by this
|
|
5
|
+
# class. It's also required that safety handlers implement a
|
|
6
|
+
# singleton approach (handled by default by #Base).
|
|
7
|
+
class Base
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
|
|
11
|
+
@instance = nil
|
|
12
|
+
|
|
13
|
+
def instance
|
|
14
|
+
@instance ||= new
|
|
15
|
+
end
|
|
16
|
+
private :new
|
|
17
|
+
|
|
18
|
+
# When we're inherited, immediately register the handler with
|
|
19
|
+
# the safety net
|
|
20
|
+
def inherited( child ) #:nodoc:
|
|
21
|
+
Safety.register_error_handler( child )
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Error handlers should overwrite this method and implement
|
|
26
|
+
# their own reporting method.
|
|
27
|
+
def handle_exception( exception )
|
|
28
|
+
raise NoMethodError, "Error handler doesn't support #handle_exception"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
|
|
3
|
+
module DaemonKit
|
|
4
|
+
module ErrorHandlers
|
|
5
|
+
# Error reporting via Hoptoad.
|
|
6
|
+
class Hoptoad < Base
|
|
7
|
+
|
|
8
|
+
# Front end to parsing the backtrace for each notice
|
|
9
|
+
# (Graciously borrowed from http://github.com/thoughtbot/hoptoad_notifier)
|
|
10
|
+
class Backtrace
|
|
11
|
+
|
|
12
|
+
# Handles backtrace parsing line by line
|
|
13
|
+
# (Graciously borrowed from http://github.com/thoughtbot/hoptoad_notifier)
|
|
14
|
+
class Line
|
|
15
|
+
|
|
16
|
+
INPUT_FORMAT = %r{^([^:]+):(\d+)(?::in `([^']+)')?$}.freeze
|
|
17
|
+
|
|
18
|
+
# The file portion of the line (such as app/models/user.rb)
|
|
19
|
+
attr_reader :file
|
|
20
|
+
|
|
21
|
+
# The line number portion of the line
|
|
22
|
+
attr_reader :number
|
|
23
|
+
|
|
24
|
+
# The method of the line (such as index)
|
|
25
|
+
attr_reader :method
|
|
26
|
+
|
|
27
|
+
# Parses a single line of a given backtrace
|
|
28
|
+
# @param [String] unparsed_line The raw line from +caller+ or some backtrace
|
|
29
|
+
# @return [Line] The parsed backtrace line
|
|
30
|
+
def self.parse(unparsed_line)
|
|
31
|
+
_, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a
|
|
32
|
+
new(file, number, method)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def initialize(file, number, method)
|
|
36
|
+
self.file = file
|
|
37
|
+
self.number = number
|
|
38
|
+
self.method = method
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Reconstructs the line in a readable fashion
|
|
42
|
+
def to_s
|
|
43
|
+
"#{file}:#{number}:in `#{method}'"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def ==(other)
|
|
47
|
+
to_s == other.to_s
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def inspect
|
|
51
|
+
"<Line:#{to_s}>"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def to_xml
|
|
55
|
+
data = [ method, file, number ].map { |s| URI.escape( s || 'unknown', %q{"'<>&} ) }
|
|
56
|
+
%q{<line method="%s" file="%s" number="%s" />} % data
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
attr_writer :file, :number, :method
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# holder for an Array of Backtrace::Line instances
|
|
65
|
+
attr_reader :lines
|
|
66
|
+
|
|
67
|
+
def self.parse(ruby_backtrace, opts = {})
|
|
68
|
+
ruby_lines = split_multiline_backtrace(ruby_backtrace)
|
|
69
|
+
|
|
70
|
+
filters = opts[:filters] || []
|
|
71
|
+
filtered_lines = ruby_lines.to_a.map do |line|
|
|
72
|
+
filters.inject(line) do |line, proc|
|
|
73
|
+
proc.call(line)
|
|
74
|
+
end
|
|
75
|
+
end.compact
|
|
76
|
+
|
|
77
|
+
lines = filtered_lines.collect do |unparsed_line|
|
|
78
|
+
Line.parse(unparsed_line)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
instance = new(lines)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def initialize(lines)
|
|
85
|
+
self.lines = lines
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def inspect
|
|
89
|
+
"<Backtrace: " + lines.collect { |line| line.inspect }.join(", ") + ">"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def ==(other)
|
|
93
|
+
if other.respond_to?(:lines)
|
|
94
|
+
lines == other.lines
|
|
95
|
+
else
|
|
96
|
+
false
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
attr_writer :lines
|
|
103
|
+
|
|
104
|
+
def self.split_multiline_backtrace(backtrace)
|
|
105
|
+
if backtrace.to_a.size == 1
|
|
106
|
+
backtrace.to_a.first.split(/\n\s*/)
|
|
107
|
+
else
|
|
108
|
+
backtrace
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Your hoptoad API key
|
|
114
|
+
@api_key = nil
|
|
115
|
+
attr_accessor :api_key
|
|
116
|
+
|
|
117
|
+
def handle_exception( exception )
|
|
118
|
+
headers = {
|
|
119
|
+
'Content-type' => 'text/xml',
|
|
120
|
+
'Accept' => 'text/xml, application/xml'
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
http = Net::HTTP.new( url.host, url.port )
|
|
124
|
+
data = format_exception( exception )
|
|
125
|
+
DaemonKit.logger.debug("Sending to Hoptoad: #{data}")
|
|
126
|
+
|
|
127
|
+
response = begin
|
|
128
|
+
http.post( url.path, data, headers )
|
|
129
|
+
rescue TimeoutError => e
|
|
130
|
+
DaemonKit.logger.error("Timeout while contacting the Hoptoad server.")
|
|
131
|
+
nil
|
|
132
|
+
end
|
|
133
|
+
case response
|
|
134
|
+
when Net::HTTPSuccess then
|
|
135
|
+
DaemonKit.logger.info "Hoptoad Success: #{response.class}"
|
|
136
|
+
else
|
|
137
|
+
DaemonKit.logger.error "Hoptoad Failure: #{response.class}\n#{response.body if response.respond_to? :body}"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def url
|
|
142
|
+
URI.parse("http://hoptoadapp.com/notifier_api/v2/notices")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def format_exception( exception )
|
|
146
|
+
lines = Backtrace.parse( exception.backtrace )
|
|
147
|
+
exception_message= exception.message
|
|
148
|
+
exception_message.gsub!("\"",""")
|
|
149
|
+
exception_message.gsub!("'","'")
|
|
150
|
+
exception_message.gsub!("&","&")
|
|
151
|
+
exception_message.gsub!("<","<")
|
|
152
|
+
exception_message.gsub!(">",">")
|
|
153
|
+
|
|
154
|
+
<<-EOF
|
|
155
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
156
|
+
<notice version="2.0">
|
|
157
|
+
<api-key>#{self.api_key}</api-key>
|
|
158
|
+
<notifier>
|
|
159
|
+
<name>daemon-kit</name>
|
|
160
|
+
<version>#{DaemonKit::VERSION}</version>
|
|
161
|
+
<url>http://github.com/kennethkalmer/daemon-kit</url>
|
|
162
|
+
</notifier>
|
|
163
|
+
<error>
|
|
164
|
+
<class>#{exception.class.name}</class>
|
|
165
|
+
<message>#{exception_message}</message>
|
|
166
|
+
<backtrace>
|
|
167
|
+
#{Backtrace.parse( exception.backtrace ).lines.inject('') { |string,line| string << line.to_xml }}
|
|
168
|
+
</backtrace>
|
|
169
|
+
</error>
|
|
170
|
+
<server-environment>
|
|
171
|
+
<project-root>#{DaemonKit.root}</project-root>
|
|
172
|
+
<environment-name>#{DaemonKit.env}</environment-name>
|
|
173
|
+
</server-environment>
|
|
174
|
+
</notice>
|
|
175
|
+
EOF
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module DaemonKit
|
|
2
|
+
# The core of daemon-kit exceptions
|
|
3
|
+
class Exception < ::StandardError
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
# Raised when no class is registered to process a ruote workitem
|
|
7
|
+
class MissingParticipant < Exception; end
|
|
8
|
+
|
|
9
|
+
# Raised when the daemon itself cannot be found.
|
|
10
|
+
class DaemonNotFound < Exception
|
|
11
|
+
def initialize( file )
|
|
12
|
+
super "No daemon found at the path '#{file}'"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'thor/group'
|
|
2
|
+
|
|
3
|
+
module DaemonKit
|
|
4
|
+
module Generators
|
|
5
|
+
class Error < Thor::Error
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class Base < Thor::Group
|
|
9
|
+
include Thor::Actions
|
|
10
|
+
|
|
11
|
+
add_runtime_options!
|
|
12
|
+
|
|
13
|
+
# Tries to get the description from a USAGE file one folder above the source
|
|
14
|
+
# root otherwise uses a default description.
|
|
15
|
+
def self.desc(description=nil)
|
|
16
|
+
return super if description
|
|
17
|
+
usage = File.expand_path(File.join(source_root, "..", "USAGE"))
|
|
18
|
+
|
|
19
|
+
@desc ||= if File.exist?(usage)
|
|
20
|
+
File.read(usage)
|
|
21
|
+
else
|
|
22
|
+
"Description:\n Create #{base_name.humanize.downcase} files for #{generator_name} generator."
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
def app_name
|
|
29
|
+
@app_name = File.basename( destination_root )
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Small macro to add ruby as an option to the generator with proper
|
|
33
|
+
# default value plus an instance helper method called shebang.
|
|
34
|
+
#
|
|
35
|
+
def self.add_shebang_option!
|
|
36
|
+
class_option :ruby, :type => :string, :aliases => "-r", :default => Thor::Util.ruby_command,
|
|
37
|
+
:desc => "Path to the Ruby binary of your choice", :banner => "PATH"
|
|
38
|
+
|
|
39
|
+
no_tasks {
|
|
40
|
+
define_method :shebang do
|
|
41
|
+
@shebang ||= begin
|
|
42
|
+
command = if options[:ruby] == Thor::Util.ruby_command
|
|
43
|
+
"/usr/bin/env #{File.basename(Thor::Util.ruby_command)}"
|
|
44
|
+
else
|
|
45
|
+
options[:ruby]
|
|
46
|
+
end
|
|
47
|
+
"#!#{command}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.namespace(name = nil)
|
|
54
|
+
return super if name
|
|
55
|
+
@namespace ||= super.sub(/_generator$/, '').sub(/:generators:/, ':').sub(/^daemon_kit:/, '')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# TODO: Don't always depend on bundled thor
|
|
2
|
+
$:.unshift File.dirname(__FILE__) + '/vendor/thor-0.13.6/lib'
|
|
3
|
+
|
|
4
|
+
require 'daemon_kit/generators/base'
|
|
5
|
+
|
|
6
|
+
module DaemonKit
|
|
7
|
+
module Generators
|
|
8
|
+
autoload :AppGenerator, 'generators/daemon_kit/app/app_generator'
|
|
9
|
+
autoload :CucumberGenerator, 'generators/daemon_kit/cucumber/cucumber_generator'
|
|
10
|
+
autoload :AmqpGenerator, 'generators/daemon_kit/amqp/amqp_generator'
|
|
11
|
+
autoload :CronGenerator, 'generators/daemon_kit/cron/cron_generator'
|
|
12
|
+
autoload :CapistranoGenerator, 'generators/daemon_kit/capistrano/capistrano_generator'
|
|
13
|
+
autoload :NaniteAgentGenerator, 'generators/daemon_kit/nanite_agent/nanite_agent_generator'
|
|
14
|
+
autoload :SpecGenerator, 'generators/daemon_kit/rspec/rspec_generator'
|
|
15
|
+
autoload :TestUnitGenerator, 'generators/daemon_kit/test_unit/test_unit_generator'
|
|
16
|
+
autoload :RuoteGenerator, 'generators/daemon_kit/ruote/ruote_generator'
|
|
17
|
+
autoload :XmppGenerator, 'generators/daemon_kit/xmpp/xmpp_generator'
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
|
|
21
|
+
def configure!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def invoke( namespace, args = ARGV, config = {} )
|
|
25
|
+
klass_name = constants.detect do |sym|
|
|
26
|
+
klass = const_get( sym )
|
|
27
|
+
klass.respond_to?( :namespace ) && klass.namespace == namespace
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if klass_name.nil?
|
|
31
|
+
raise Error, "Could not find generator #{namespace}."
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
klass = const_get( klass_name )
|
|
35
|
+
|
|
36
|
+
args << '--help' if args.empty? && klass.arguments.any? { |a| a.required? }
|
|
37
|
+
klass.start( args, config )
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def help
|
|
41
|
+
namespaces = constants.inject([]) do |list, sym|
|
|
42
|
+
unless sym == :Base || sym == :AppGenerator
|
|
43
|
+
klass = const_get( sym )
|
|
44
|
+
list << klass.namespace if klass.respond_to?( :namespace )
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
list
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
puts "Usage:"
|
|
51
|
+
puts " script/generate GENERATOR [args] [options]"
|
|
52
|
+
puts
|
|
53
|
+
puts "General options:"
|
|
54
|
+
puts " -h, [--help] # Print generators options and usage"
|
|
55
|
+
puts " -p, [--pretend] # Run but do not make any changes"
|
|
56
|
+
puts " -f, [--force] # Overwrite files that already exist"
|
|
57
|
+
puts " -s, [--skip] # Skip files that already exist"
|
|
58
|
+
puts " -q, [--quiet] # Supress status output"
|
|
59
|
+
puts
|
|
60
|
+
puts "Available generators:"
|
|
61
|
+
|
|
62
|
+
namespaces.each { |ns| puts " " + ns }
|
|
63
|
+
puts
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
DAEMON_ENV = (ENV['DAEMON_ENV'] || 'development').dup unless defined?(DAEMON_ENV)
|
|
4
|
+
|
|
5
|
+
# Absolute paths to the daemon_kit libraries added to $:
|
|
6
|
+
incdir = ( File.dirname(__FILE__) + '/..' )
|
|
7
|
+
absincdir = if RUBY_PLATFORM =~ /(:?mswin|mingw)/
|
|
8
|
+
File.expand_path( incdir )
|
|
9
|
+
else
|
|
10
|
+
File.expand_path( Pathname.new( incdir ).realpath.to_s )
|
|
11
|
+
end
|
|
12
|
+
$:.unshift absincdir unless $:.include?( absincdir )
|
|
13
|
+
|
|
14
|
+
require 'daemon_kit'
|
|
15
|
+
|
|
16
|
+
module DaemonKit
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
|
|
20
|
+
def configuration
|
|
21
|
+
@configuration
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def configuration=( configuration )
|
|
25
|
+
@configuration = configuration
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def arguments
|
|
29
|
+
@arguments
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def arguments=( args )
|
|
33
|
+
@arguments = args
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def trap( *args, &block )
|
|
37
|
+
self.configuration.trap( *args, &block )
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def at_shutdown( &block )
|
|
41
|
+
self.configuration.at_shutdown( &block )
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# This class does all the nightmare work of setting up a working
|
|
48
|
+
# environment for your daemon.
|
|
49
|
+
class Initializer
|
|
50
|
+
|
|
51
|
+
attr_reader :configuration
|
|
52
|
+
|
|
53
|
+
def self.run
|
|
54
|
+
configuration = DaemonKit.configuration || Configuration.new
|
|
55
|
+
|
|
56
|
+
yield configuration if block_given?
|
|
57
|
+
initializer = new configuration
|
|
58
|
+
initializer.before_daemonize
|
|
59
|
+
initializer
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.continue!
|
|
63
|
+
initializer = new DaemonKit.configuration
|
|
64
|
+
initializer.after_daemonize
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.shutdown( clean = false, do_exit = false )
|
|
68
|
+
return unless $daemon_kit_shutdown_hooks_ran.nil?
|
|
69
|
+
$daemon_kit_shutdown_hooks_ran = true
|
|
70
|
+
|
|
71
|
+
DaemonKit.logger.info "Running shutdown hooks"
|
|
72
|
+
|
|
73
|
+
DaemonKit.configuration.shutdown_hooks.each do |hook|
|
|
74
|
+
begin
|
|
75
|
+
hook.call
|
|
76
|
+
rescue => e
|
|
77
|
+
DaemonKit.logger.exception( e )
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
log_exceptions if DaemonKit.configuration.backtraces && !clean
|
|
82
|
+
|
|
83
|
+
DaemonKit.logger.warn "Shutting down #{DaemonKit.configuration.daemon_name}"
|
|
84
|
+
|
|
85
|
+
exit if do_exit
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def initialize( configuration )
|
|
89
|
+
@configuration = configuration
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def before_daemonize
|
|
93
|
+
DaemonKit.configuration = @configuration
|
|
94
|
+
|
|
95
|
+
set_load_path
|
|
96
|
+
load_gems
|
|
97
|
+
load_patches
|
|
98
|
+
load_environment
|
|
99
|
+
load_predaemonize_configs
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def after_daemonize
|
|
103
|
+
set_umask
|
|
104
|
+
|
|
105
|
+
initialize_logger
|
|
106
|
+
initialize_signal_traps
|
|
107
|
+
|
|
108
|
+
include_core_lib
|
|
109
|
+
load_postdaemonize_configs
|
|
110
|
+
configure_backtraces
|
|
111
|
+
|
|
112
|
+
set_process_name
|
|
113
|
+
|
|
114
|
+
DaemonKit.logger.info( "DaemonKit (#{DaemonKit::VERSION}) booted, now running #{DaemonKit.configuration.daemon_name}" )
|
|
115
|
+
|
|
116
|
+
if DaemonKit.configuration.user || DaemonKit.configuration.group
|
|
117
|
+
euid = Process.euid
|
|
118
|
+
egid = Process.egid
|
|
119
|
+
uid = Process.uid
|
|
120
|
+
gid = Process.gid
|
|
121
|
+
DaemonKit.logger.info( "DaemonKit dropped privileges to: #{euid} (EUID), #{egid} (EGID), #{uid} (UID), #{gid} (GID)" )
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def set_load_path
|
|
126
|
+
configuration.load_paths.each do |d|
|
|
127
|
+
$:.unshift( "#{DAEMON_ROOT}/#{d}" ) if File.directory?( "#{DAEMON_ROOT}/#{d}" )
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def load_gems
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def load_patches
|
|
136
|
+
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def load_environment
|
|
140
|
+
# Needs to be global to prevent loading the files twice
|
|
141
|
+
return if $_daemon_environment_loaded
|
|
142
|
+
$_daemon_environment_loaded = true
|
|
143
|
+
|
|
144
|
+
config = configuration
|
|
145
|
+
|
|
146
|
+
eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
|
|
147
|
+
|
|
148
|
+
eval(IO.read(configuration.daemon_initializer), binding, configuration.daemon_initializer) if File.exist?( configuration.daemon_initializer )
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def load_predaemonize_configs
|
|
152
|
+
Dir[ File.join( DAEMON_ROOT, 'config', 'pre-daemonize', '*.rb' ) ].each do |f|
|
|
153
|
+
next if File.basename( f ) == File.basename( configuration.daemon_initializer )
|
|
154
|
+
|
|
155
|
+
require f
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def load_postdaemonize_configs
|
|
160
|
+
Dir[ File.join( DAEMON_ROOT, 'config', 'post-daemonize', '*.rb' ) ].each do |f|
|
|
161
|
+
require f
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def set_umask
|
|
166
|
+
File.umask configuration.umask
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def initialize_logger
|
|
170
|
+
return if DaemonKit.logger
|
|
171
|
+
|
|
172
|
+
unless logger = configuration.logger
|
|
173
|
+
logger = AbstractLogger.new( configuration.log_path )
|
|
174
|
+
logger.level = configuration.log_level
|
|
175
|
+
logger.copy_to_stdout = configuration.log_stdout
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
DaemonKit.logger = logger
|
|
179
|
+
|
|
180
|
+
DaemonKit.logger.info "DaemonKit (#{DaemonKit::VERSION}) booting in #{DAEMON_ENV} mode"
|
|
181
|
+
|
|
182
|
+
configuration.trap("USR1") {
|
|
183
|
+
DaemonKit.logger.level = DaemonKit.logger.debug? ? :info : :debug
|
|
184
|
+
DaemonKit.logger.info "Log level changed to #{DaemonKit.logger.debug? ? 'DEBUG' : 'INFO' }"
|
|
185
|
+
}
|
|
186
|
+
configuration.trap("USR2") {
|
|
187
|
+
DaemonKit.logger.level = :debug
|
|
188
|
+
DaemonKit.logger.info "Log level changed to DEBUG"
|
|
189
|
+
}
|
|
190
|
+
configuration.trap("HUP") {
|
|
191
|
+
DaemonKit::Application.reopen_logs
|
|
192
|
+
}
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def initialize_signal_traps
|
|
196
|
+
# Only exit the process if we're not in the 'test' environment
|
|
197
|
+
term_proc = Proc.new { DaemonKit::Initializer.shutdown( true, DAEMON_ENV != 'test' ) }
|
|
198
|
+
configuration.trap( 'INT', term_proc )
|
|
199
|
+
configuration.trap( 'TERM', term_proc )
|
|
200
|
+
at_exit { DaemonKit::Initializer.shutdown }
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def include_core_lib
|
|
204
|
+
if File.exists?( core_lib = File.join( DAEMON_ROOT, 'lib', configuration.daemon_name + '.rb' ) )
|
|
205
|
+
require core_lib
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def configure_backtraces
|
|
210
|
+
Thread.abort_on_exception = configuration.backtraces
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def set_process_name
|
|
214
|
+
$0 = configuration.daemon_name
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def self.log_exceptions
|
|
218
|
+
trace_file = File.join( DaemonKit.root, 'log', "backtrace-#{Time.now.strftime('%Y%m%d%H%M%S')}-#{Process.pid}.log" )
|
|
219
|
+
trace_log = Logger.new( trace_file )
|
|
220
|
+
|
|
221
|
+
# Find the last exception
|
|
222
|
+
e = nil
|
|
223
|
+
ObjectSpace.each_object {|o|
|
|
224
|
+
if ::Exception === o
|
|
225
|
+
e = o
|
|
226
|
+
end
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
trace_log.info "*** Below you'll find the most recent exception thrown, this will likely (but not certainly) be the exception that made #{DaemonKit.configuration.daemon_name} exit abnormally ***"
|
|
230
|
+
trace_log.error e
|
|
231
|
+
|
|
232
|
+
trace_log.info "*** Below you'll find all the exception objects in memory, some of them may have been thrown in your application, others may just be in memory because they are standard exceptions ***"
|
|
233
|
+
ObjectSpace.each_object {|o|
|
|
234
|
+
if ::Exception === o
|
|
235
|
+
trace_log.error o
|
|
236
|
+
end
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
trace_log.close
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Holds our various configuration values
|
|
244
|
+
class Configuration
|
|
245
|
+
|
|
246
|
+
include Configurable
|
|
247
|
+
|
|
248
|
+
# Root to the daemon
|
|
249
|
+
attr_reader :root_path
|
|
250
|
+
|
|
251
|
+
# List of load paths
|
|
252
|
+
attr_accessor :load_paths
|
|
253
|
+
|
|
254
|
+
# Custom logger instance to use
|
|
255
|
+
attr_accessor :logger
|
|
256
|
+
|
|
257
|
+
# The log level to use, defaults to DEBUG
|
|
258
|
+
attr_reader :log_level
|
|
259
|
+
|
|
260
|
+
# Path to the log file, defaults to 'log/<environment>.log'
|
|
261
|
+
configurable :log_path
|
|
262
|
+
|
|
263
|
+
# Duplicate log data to stdout
|
|
264
|
+
attr_accessor :log_stdout
|
|
265
|
+
|
|
266
|
+
# Path to the pid file, defaults to 'log/<daemon_name>.pid'
|
|
267
|
+
attr_accessor :pid_file
|
|
268
|
+
|
|
269
|
+
# The application name
|
|
270
|
+
configurable :daemon_name, :locked => true
|
|
271
|
+
|
|
272
|
+
# Use the force kill patch? Give the number of seconds
|
|
273
|
+
configurable :force_kill_wait
|
|
274
|
+
|
|
275
|
+
# Should be log backtraces
|
|
276
|
+
configurable :backtraces, false
|
|
277
|
+
|
|
278
|
+
# Configurable umask
|
|
279
|
+
configurable :umask, 0022
|
|
280
|
+
|
|
281
|
+
# Configurable user
|
|
282
|
+
configurable :user, :locked => true
|
|
283
|
+
|
|
284
|
+
# Confgiruable group
|
|
285
|
+
configurable :group, :locked => true
|
|
286
|
+
|
|
287
|
+
# Collection of signal traps
|
|
288
|
+
attr_reader :signal_traps
|
|
289
|
+
|
|
290
|
+
# Our safety net (#Safety) instance
|
|
291
|
+
attr_accessor :safety_net
|
|
292
|
+
|
|
293
|
+
# :nodoc: Shutdown hooks
|
|
294
|
+
attr_reader :shutdown_hooks
|
|
295
|
+
|
|
296
|
+
def initialize
|
|
297
|
+
parse_arguments!
|
|
298
|
+
|
|
299
|
+
set_root_path!
|
|
300
|
+
set_daemon_defaults!
|
|
301
|
+
|
|
302
|
+
self.load_paths = default_load_paths
|
|
303
|
+
self.log_level ||= default_log_level
|
|
304
|
+
self.log_path ||= default_log_path
|
|
305
|
+
|
|
306
|
+
self.force_kill_wait = false
|
|
307
|
+
|
|
308
|
+
self.safety_net = DaemonKit::Safety.instance
|
|
309
|
+
|
|
310
|
+
@signal_traps = {}
|
|
311
|
+
@shutdown_hooks = []
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def environment
|
|
315
|
+
::DAEMON_ENV
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# The path to the current environment's file (<tt>development.rb</tt>, etc.). By
|
|
319
|
+
# default the file is at <tt>config/environments/#{environment}.rb</tt>.
|
|
320
|
+
def environment_path
|
|
321
|
+
"#{root_path}/config/environments/#{environment}.rb"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def daemon_initializer
|
|
325
|
+
"#{root_path}/config/initializers/#{self.daemon_name}.rb"
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Add a trap for the specified signal, can be code block or a proc
|
|
329
|
+
def trap( signal, proc = nil, &block )
|
|
330
|
+
return if proc.nil? && !block_given?
|
|
331
|
+
|
|
332
|
+
# One step towards running on windows, not enough though
|
|
333
|
+
unless Signal.list.include?( signal )
|
|
334
|
+
DaemonKit.logger.warn( "Trapping #{signal} signals not supported on this platform" )
|
|
335
|
+
return
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
unless @signal_traps.has_key?( signal )
|
|
339
|
+
set_trap( signal )
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
@signal_traps[signal].unshift( proc || block )
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# Add a block or proc to be called during shutdown
|
|
346
|
+
def at_shutdown( proc = nil, &block )
|
|
347
|
+
return if proc.nil? && !block_given?
|
|
348
|
+
|
|
349
|
+
@shutdown_hooks << ( proc || block )
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def pid_file
|
|
353
|
+
@pid_file ||= "#{File.dirname(self.log_path)}/#{self.daemon_name}.pid"
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Set the log level
|
|
357
|
+
def log_level=( level )
|
|
358
|
+
@log_level = level
|
|
359
|
+
DaemonKit.logger.level = @log_level if DaemonKit.logger
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
protected
|
|
363
|
+
|
|
364
|
+
def run_traps( signal )
|
|
365
|
+
DaemonKit.logger.info "Running signal traps for #{signal}"
|
|
366
|
+
self.signal_traps[ signal ].each { |trap| trap.call }
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
private
|
|
370
|
+
|
|
371
|
+
def set_trap( signal )
|
|
372
|
+
DaemonKit.logger.info "Setting up trap for #{signal}"
|
|
373
|
+
@signal_traps[ signal ] = []
|
|
374
|
+
Signal.trap( signal, Proc.new { self.run_traps( signal ) } )
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def parse_arguments!
|
|
378
|
+
return unless own_args?
|
|
379
|
+
|
|
380
|
+
configs = Arguments.configuration( ARGV ).first
|
|
381
|
+
@unused_arguments = {}
|
|
382
|
+
|
|
383
|
+
configs.each do |c|
|
|
384
|
+
k,v = c.split('=')
|
|
385
|
+
|
|
386
|
+
if v.nil?
|
|
387
|
+
error( "#{k} has no value" )
|
|
388
|
+
next
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
begin
|
|
392
|
+
if self.respond_to?( k )
|
|
393
|
+
self.send( "#{k}=", v ) # pid_file = /var/run/foo.pid
|
|
394
|
+
else
|
|
395
|
+
@unused_arguments[ k ] = v
|
|
396
|
+
end
|
|
397
|
+
rescue => e
|
|
398
|
+
error( "Couldn't set `#{k}' to `#{v}': #{e.message}" )
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# DANGEROUS: Change the value of DAEMON_ENV
|
|
404
|
+
def environment=( env )
|
|
405
|
+
::DAEMON_ENV.replace( env )
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def set_root_path!
|
|
409
|
+
raise "DAEMON_ROOT is not set" unless defined?(::DAEMON_ROOT)
|
|
410
|
+
raise "DAEMON_ROOT is not a directory" unless File.directory?(::DAEMON_ROOT)
|
|
411
|
+
|
|
412
|
+
@root_path = ::DAEMON_ROOT.to_absolute_path
|
|
413
|
+
|
|
414
|
+
Object.const_set(:RELATIVE_DAEMON_ROOT, ::DAEMON_ROOT.dup) unless defined?(::RELATIVE_DAEMON_ROOT)
|
|
415
|
+
::DAEMON_ROOT.replace @root_path
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def set_daemon_defaults!
|
|
419
|
+
self.log_stdout = false
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def default_load_paths
|
|
423
|
+
[ 'lib' ]
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
def default_log_path
|
|
427
|
+
File.join(root_path, 'log', "#{environment}.log")
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def default_log_level
|
|
431
|
+
environment == 'production' ? :info : :debug
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def error( msg )
|
|
435
|
+
msg = "[E] Configuration: #{msg}"
|
|
436
|
+
|
|
437
|
+
if DaemonKit.logger
|
|
438
|
+
DaemonKit.logger.error( msg )
|
|
439
|
+
else
|
|
440
|
+
STDERR.puts msg
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# If we are executed with any of these commands, don't allow
|
|
445
|
+
# arguments to be parsed cause they will interfere with the
|
|
446
|
+
# script encapsulating DaemonKit, like capistrano
|
|
447
|
+
def own_args?
|
|
448
|
+
!%w( rake cap spec cucumber ).include?( File.basename( $0 ) )
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
end
|