daemon-kit 0.1.7 → 0.1.7.4

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.
Files changed (80) hide show
  1. data/Configuration.txt +58 -0
  2. data/History.txt +24 -0
  3. data/Manifest.txt +50 -2
  4. data/PostInstall.txt +1 -1
  5. data/README.rdoc +7 -9
  6. data/Rakefile +2 -4
  7. data/TODO.txt +6 -5
  8. data/app_generators/daemon_kit/daemon_kit_generator.rb +5 -0
  9. data/app_generators/daemon_kit/templates/Rakefile +3 -1
  10. data/app_generators/daemon_kit/templates/bin/daemon.erb +1 -1
  11. data/app_generators/daemon_kit/templates/config/arguments.rb +12 -0
  12. data/app_generators/daemon_kit/templates/config/boot.rb +2 -2
  13. data/app_generators/daemon_kit/templates/script/console +3 -0
  14. data/app_generators/daemon_kit/templates/script/destroy +14 -0
  15. data/app_generators/daemon_kit/templates/script/generate +14 -0
  16. data/daemon_generators/amqp/templates/config/amqp.yml +5 -5
  17. data/daemon_generators/deploy_capistrano/deploy_capistrano_generator.rb +4 -23
  18. data/daemon_generators/deploy_capistrano/templates/USAGE +10 -0
  19. data/daemon_generators/deploy_capistrano/templates/config/deploy.rb +3 -1
  20. data/lib/daemon_kit.rb +33 -5
  21. data/lib/daemon_kit/amqp.rb +2 -1
  22. data/lib/daemon_kit/application.rb +136 -11
  23. data/lib/daemon_kit/arguments.rb +151 -0
  24. data/lib/daemon_kit/commands/console.rb +38 -0
  25. data/lib/daemon_kit/config.rb +1 -0
  26. data/lib/daemon_kit/console_daemon.rb +2 -0
  27. data/lib/daemon_kit/core_ext.rb +1 -0
  28. data/lib/daemon_kit/core_ext/string.rb +22 -0
  29. data/lib/daemon_kit/deployment/capistrano.rb +6 -9
  30. data/lib/daemon_kit/error_handlers/mail.rb +52 -15
  31. data/lib/daemon_kit/initializer.rb +95 -41
  32. data/lib/daemon_kit/pid_file.rb +61 -0
  33. data/lib/daemon_kit/tasks/environment.rake +5 -4
  34. data/lib/daemon_kit/tasks/framework.rake +15 -1
  35. data/lib/daemon_kit/tasks/god.rake +62 -0
  36. data/lib/daemon_kit/tasks/log.rake +8 -0
  37. data/lib/daemon_kit/tasks/monit.rake +29 -0
  38. data/spec/argument_spec.rb +51 -0
  39. data/spec/config_spec.rb +77 -0
  40. data/spec/daemon_kit_spec.rb +2 -2
  41. data/spec/error_handlers_spec.rb +23 -0
  42. data/spec/fixtures/env.yml +15 -0
  43. data/spec/fixtures/noenv.yml +4 -0
  44. data/spec/initializer_spec.rb +4 -3
  45. data/spec/spec_helper.rb +8 -11
  46. data/templates/god/god.erb +69 -0
  47. data/templates/monit/monit.erb +14 -0
  48. data/test/test_daemon-kit_generator.rb +6 -1
  49. data/test/test_deploy_capistrano_generator.rb +1 -2
  50. data/vendor/tmail-1.2.3/tmail.rb +5 -0
  51. data/vendor/tmail-1.2.3/tmail/address.rb +426 -0
  52. data/vendor/tmail-1.2.3/tmail/attachments.rb +46 -0
  53. data/vendor/tmail-1.2.3/tmail/base64.rb +46 -0
  54. data/vendor/tmail-1.2.3/tmail/compat.rb +41 -0
  55. data/vendor/tmail-1.2.3/tmail/config.rb +67 -0
  56. data/vendor/tmail-1.2.3/tmail/core_extensions.rb +63 -0
  57. data/vendor/tmail-1.2.3/tmail/encode.rb +581 -0
  58. data/vendor/tmail-1.2.3/tmail/header.rb +960 -0
  59. data/vendor/tmail-1.2.3/tmail/index.rb +9 -0
  60. data/vendor/tmail-1.2.3/tmail/interface.rb +1130 -0
  61. data/vendor/tmail-1.2.3/tmail/loader.rb +3 -0
  62. data/vendor/tmail-1.2.3/tmail/mail.rb +578 -0
  63. data/vendor/tmail-1.2.3/tmail/mailbox.rb +495 -0
  64. data/vendor/tmail-1.2.3/tmail/main.rb +6 -0
  65. data/vendor/tmail-1.2.3/tmail/mbox.rb +3 -0
  66. data/vendor/tmail-1.2.3/tmail/net.rb +248 -0
  67. data/vendor/tmail-1.2.3/tmail/obsolete.rb +132 -0
  68. data/vendor/tmail-1.2.3/tmail/parser.rb +1476 -0
  69. data/vendor/tmail-1.2.3/tmail/port.rb +379 -0
  70. data/vendor/tmail-1.2.3/tmail/quoting.rb +118 -0
  71. data/vendor/tmail-1.2.3/tmail/require_arch.rb +58 -0
  72. data/vendor/tmail-1.2.3/tmail/scanner.rb +49 -0
  73. data/vendor/tmail-1.2.3/tmail/scanner_r.rb +261 -0
  74. data/vendor/tmail-1.2.3/tmail/stringio.rb +280 -0
  75. data/vendor/tmail-1.2.3/tmail/utils.rb +337 -0
  76. data/vendor/tmail-1.2.3/tmail/version.rb +39 -0
  77. data/vendor/tmail.rb +13 -0
  78. metadata +57 -18
  79. data/daemon_generators/deploy_capistrano/USAGE +0 -5
  80. data/lib/daemon_kit/patches/force_kill_wait.rb +0 -120
@@ -0,0 +1,10 @@
1
+
2
+ Capistrano deployment configuration generator completed
3
+
4
+ Usage:
5
+ Review the configuration files in config/deploy.rb and
6
+ config/deploy/*.rb
7
+
8
+ Once you're happy with the configurations, you can review
9
+ a list of available capistrano commands by running `cap -T'
10
+
@@ -34,7 +34,9 @@ set :config_files, %w{}
34
34
  set :shared_children, %w{log tmp}
35
35
 
36
36
  # Record our dependencies
37
- depend :remote, :gem, "daemon-kit", ">=0.0.0"
37
+ unless File.directory?( "#{DaemonKit.root}/vendor/daemon_kit" )
38
+ depend :remote, :gem, "daemon-kit", ">=#{DaemonKit::VERSION}"
39
+ end
38
40
 
39
41
  # Hook into capistrano's events
40
42
  before "deploy:update_code", "deploy:check"
data/lib/daemon_kit.rb CHANGED
@@ -1,17 +1,45 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
-
1
+ # TODO: Strip this out eventually so we can run without rubygems
4
2
  require 'rubygems'
5
3
 
4
+ require File.dirname(__FILE__) + '/daemon_kit/core_ext'
5
+
6
+ $:.unshift( File.dirname(__FILE__).to_absolute_path ) unless
7
+ $:.include?( File.dirname(__FILE__).to_absolute_path )
8
+
6
9
  module DaemonKit
7
- VERSION = '0.1.7'
10
+ VERSION = '0.1.7.4'
8
11
 
9
12
  autoload :Initializer, 'daemon_kit/initializer'
10
13
  autoload :Application, 'daemon_kit/application'
14
+ autoload :Arguments, 'daemon_kit/arguments'
11
15
  autoload :Config, 'daemon_kit/config'
16
+ autoload :Safety, 'daemon_kit/safety'
17
+ autoload :PidFile, 'daemon_kit/pid_file'
18
+
12
19
  autoload :Cron, 'daemon_kit/cron'
13
20
  autoload :Jabber, 'daemon_kit/jabber'
14
21
  autoload :AMQP, 'daemon_kit/amqp'
15
22
  autoload :Nanite, 'daemon_kit/nanite'
16
- autoload :Safety, 'daemon_kit/safety'
23
+
24
+ class << self
25
+ def logger
26
+ @logger
27
+ end
28
+
29
+ def logger=( logger )
30
+ @logger = logger
31
+ end
32
+
33
+ def root
34
+ DAEMON_ROOT
35
+ end
36
+
37
+ def env
38
+ DAEMON_ENV
39
+ end
40
+
41
+ def framework_root
42
+ @framework_root ||= File.join( File.dirname(__FILE__), '..' ).to_absolute_path
43
+ end
44
+ end
17
45
  end
@@ -30,7 +30,8 @@ module DaemonKit
30
30
  DaemonKit.trap('INT') { ::AMQP.stop { ::EM.stop } }
31
31
  DaemonKit.trap('TERM') { ::AMQP.stop { ::EM.stop } }
32
32
 
33
- # Start our event loop
33
+ # Start our event loop and AMQP client
34
+ DaemonKit.logger.debug("AMQP.start(#{@config.inspect})")
34
35
  ::AMQP.start(@config, &block)
35
36
  end
36
37
  end
@@ -1,4 +1,4 @@
1
- require 'daemons'
1
+ require 'timeout'
2
2
 
3
3
  module DaemonKit
4
4
 
@@ -7,29 +7,154 @@ module DaemonKit
7
7
 
8
8
  class << self
9
9
 
10
- # Run the file as a daemon
11
- def run( file )
10
+ # Run the specified file as a daemon process.
11
+ def exec( file )
12
12
  raise DaemonNotFound.new( file ) unless File.exist?( file )
13
13
 
14
- app_name = DaemonKit.configuration.daemon_name || File.basename( file )
15
- options = { :backtrace => true, :log_output => true, :app_name => app_name }
14
+ DaemonKit.configuration.daemon_name ||= File.basename( file )
15
+
16
+ command, configs, args = Arguments.parse( ARGV )
17
+
18
+ case command
19
+ when :run
20
+ parse_arguments( args )
21
+ run( file )
22
+ when :start
23
+ parse_arguments( args )
24
+ start( file )
25
+ when :stop
26
+ stop
27
+ end
28
+ end
29
+
30
+ # Run the daemon in the foreground without daemonizing
31
+ def run( file )
32
+ self.chroot
33
+ self.clean_fd
34
+ self.redirect_io( true )
35
+
36
+ require file
37
+ end
38
+
39
+ # Run our file properly
40
+ def start( file )
41
+ self.daemonize
42
+ self.chroot
43
+ self.clean_fd
44
+ self.redirect_io
45
+
46
+ require file
47
+ end
48
+
49
+ def stop
50
+ @pid_file = PidFile.new( DaemonKit.configuration.pid_file )
51
+
52
+ unless @pid_file.running?
53
+ @pid_file.cleanup
54
+ puts "Nothing to stop"
55
+ exit
56
+ end
57
+
58
+ target_pid = @pid_file.pid
59
+
60
+ puts "Sending TERM to #{target_pid}"
61
+ Process.kill( 'TERM', target_pid )
62
+
63
+ if seconds = DaemonKit.configuration.force_kill_wait
64
+ begin
65
+ Timeout::timeout( seconds ) do
66
+ loop do
67
+ puts "Waiting #{seconds} seconds for #{target_pid} before sending KILL"
68
+
69
+ break unless @pid_file.running?
16
70
 
17
- options[:dir_mode] = DaemonKit.configuration.dir_mode
18
- options[:dir] = DaemonKit.configuration.dir
19
- options[:multiple] = DaemonKit.configuration.multiple
20
- options[:force_kill_wait] = DaemonKit.configuration.force_kill_wait if DaemonKit.configuration.force_kill_wait
71
+ seconds -= 1
72
+ sleep 1
73
+ end
74
+ end
75
+ rescue Timeout::Error
76
+ Process.kill( 'KILL', target_pid )
77
+ end
78
+ end
21
79
 
22
- Daemons.run( file, options )
80
+ @pid_file.cleanup
23
81
  end
24
82
 
25
83
  # Call this from inside a daemonized process to complete the
26
84
  # initialization process
27
85
  def running!
28
- DaemonKit::Initializer.continue!
86
+ Initializer.continue!
29
87
 
30
88
  yield DaemonKit.configuration if block_given?
31
89
  end
32
90
 
91
+ # Exit the daemon
92
+ # TODO: Make configurable callback chain
93
+ # TODO: Hook into at_exit()
94
+ def exit!( code = 0 )
95
+ end
96
+
97
+ protected
98
+
99
+ def parse_arguments( args )
100
+ DaemonKit.arguments = Arguments.new
101
+ DaemonKit.arguments.parse( args )
102
+ end
103
+
104
+ # Daemonize the process
105
+ def daemonize
106
+ @pid_file = PidFile.new( DaemonKit.configuration.pid_file )
107
+ @pid_file.ensure_stopped!
108
+
109
+ if RUBY_VERSION < "1.9"
110
+ exit if fork
111
+ Process.setsid
112
+ exit if fork
113
+ else
114
+ Process.daemon( true, true )
115
+ end
116
+
117
+ @pid_file.write!
118
+
119
+ # TODO: Convert into shutdown hook
120
+ at_exit { @pid_file.cleanup }
121
+ end
122
+
123
+ # Release the old working directory and insure a sensible umask
124
+ # TODO: Make chroot directory configurable
125
+ def chroot
126
+ Dir.chdir '/'
127
+ File.umask 0000
128
+ end
129
+
130
+ # Make sure all file descriptors are closed (with the exception
131
+ # of STDIN, STDOUT & STDERR)
132
+ def clean_fd
133
+ ObjectSpace.each_object(IO) do |io|
134
+ unless [STDIN, STDOUT, STDERR].include?(io)
135
+ begin
136
+ unless io.closed?
137
+ io.close
138
+ end
139
+ rescue ::Exception
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ # Redirect our IO
146
+ # TODO: make this configurable
147
+ def redirect_io( simulate = false )
148
+ begin
149
+ STDIN.reopen '/dev/null'
150
+ rescue ::Exception
151
+ end
152
+
153
+ unless simulate
154
+ STDOUT.reopen '/dev/null', 'a'
155
+ STDERR.reopen '/dev/null', 'a'
156
+ end
157
+ end
33
158
  end
34
159
 
35
160
  end
@@ -0,0 +1,151 @@
1
+ require 'optparse'
2
+
3
+ module DaemonKit
4
+
5
+ # A wrapper around OptParse for setting up arguments to the daemon
6
+ # process.
7
+ #
8
+ # TODO: Set rules for basic options that go for all daemons
9
+ # TODO: Load options from config/arguments.rb
10
+ class Arguments
11
+
12
+ # Default command
13
+ @default_command = 'run'
14
+
15
+ # Valid commands
16
+ @commands = [
17
+ 'start',
18
+ 'stop',
19
+ 'run'
20
+ ]
21
+
22
+ class << self
23
+
24
+ attr_reader :default_command, :commands
25
+
26
+ # Parse the argument values and return an array with the command
27
+ # name, config values and argument values
28
+ def parse( argv )
29
+ cmd, argv = self.command( argv )
30
+
31
+ return cmd, *self.configuration( argv )
32
+ end
33
+
34
+ # Parse the provided argument array for a given command, or
35
+ # return the default command and the remaining arguments
36
+ def command( argv )
37
+ # extract command or set default
38
+ cmd = self.commands.include?( argv[0] ) ? argv.shift : self.default_command
39
+
40
+ return cmd.to_sym, argv
41
+ end
42
+
43
+ # Extracts any values for arguments matching '--config' as well
44
+ # as some implication arguments like '-e'. Returns an array with
45
+ # the configs as the first value and the remaing args as the
46
+ # last value.
47
+ #
48
+ # To set a value on the default #Configuration instance, use the
49
+ # following notation:
50
+ #
51
+ # --config attribute=value
52
+ #
53
+ # The above notation can be used several times to set different
54
+ # values.
55
+ #
56
+ # Special, or 'normal' arguments that are mapped to the default
57
+ # #Configuration instance are listed below:
58
+ #
59
+ # -e value or --env value => environment
60
+ # --pid pidfile => pid_file
61
+ #
62
+ def configuration( argv )
63
+ configs = []
64
+
65
+ i = 0
66
+ while i < argv.size
67
+ if argv[i] == "--config"
68
+ argv.delete_at( i )
69
+ configs << argv.delete_at(i)
70
+ end
71
+
72
+ if argv[i] == "-e" || argv[i] == "--env"
73
+ argv.delete_at( i )
74
+ configs << "environment=#{argv.delete_at(i)}"
75
+ end
76
+
77
+ if argv[i] == "--pid"
78
+ argv.delete_at( i )
79
+ configs << "pid_file=#{argv.delete_at(i)}"
80
+ end
81
+
82
+ i += 1
83
+ end
84
+
85
+ return configs, argv
86
+ end
87
+
88
+ # Return the arguments remaining after running through #configuration
89
+ def arguments( argv )
90
+ self.configuration( argv ).last
91
+ end
92
+ end
93
+
94
+ attr_reader :options
95
+
96
+ def initialize
97
+ @options = {}
98
+
99
+ @parser = OptionParser.new do |opts|
100
+ opts.banner = "Usage: #{File.basename($0)} [command] [options]"
101
+
102
+ opts.separator ""
103
+
104
+ opts.separator "Command is one of the following:"
105
+ opts.separator " run - Run the daemon without forking (default)"
106
+ opts.separator " start - Run the daemon"
107
+ opts.separator " stop - Stop the running daemon"
108
+
109
+ opts.separator ""
110
+
111
+ opts.separator "Options can be:"
112
+
113
+ arg_file = File.join( DaemonKit.root, 'config', 'arguments.rb' )
114
+ eval(IO.read(arg_file), binding, arg_file) if File.exists?( arg_file )
115
+
116
+ opts.on("-e", "--env ENVIRONMENT", "Environment for the process", "Defaults to development") do
117
+ # Nothing, just here for show
118
+ end
119
+
120
+ opts.on("--pidfile PATH", "Path to the pidfile", "Defaults to log/#{DaemonKit.configuration.daemon_name}.pid") do
121
+ # Nothing, just here for show
122
+ end
123
+
124
+ opts.separator ""
125
+ opts.separator "Advanced configurations:"
126
+ opts.on("--config ATTRIBUTE=VALUE",
127
+ "Change values of the daemon-kit Configuration instance",
128
+ "Example: log_dir=/path/to/log-directory") do
129
+ # Nothing, just here for show
130
+ end
131
+
132
+ opts.separator ""
133
+
134
+ opts.separator "Common options:"
135
+ opts.on("-v", "--version", "Show version information and exit") do
136
+ puts "daemon-kit #{DaemonKit::VERSION} (http://github.com/kennethkalmer/daemon-kit)"
137
+ exit
138
+ end
139
+
140
+ opts.on_tail("-h", "--help", "Show this message") do
141
+ puts opts
142
+ exit
143
+ end
144
+ end
145
+ end
146
+
147
+ def parse( argv )
148
+ @parser.parse!( argv )
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,38 @@
1
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
2
+
3
+ require 'optparse'
4
+
5
+ options = { :irb => irb }
6
+ OptionParser.new do |opt|
7
+ opt.banner = "Usage: console [environment] [options]"
8
+ opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |v| options[:irb] = v }
9
+ opt.on("--debugger", 'Enable ruby-debugging for the console.') { |v| options[:debugger] = v }
10
+ opt.parse!(ARGV)
11
+ end
12
+
13
+ libs = " -r irb/completion"
14
+ libs << %( -r "#{DAEMON_ROOT}/config/environment")
15
+ libs << " -r daemon_kit/console_daemon"
16
+
17
+ if options[:debugger]
18
+ begin
19
+ require 'ruby-debug'
20
+ libs << " -r ruby-debug"
21
+ puts "=> Debugger enabled"
22
+ rescue Exception
23
+ puts "You need to install ruby-debug to run the console in debugging mode. With gems, use 'gem install ruby-debug'"
24
+ exit
25
+ end
26
+ end
27
+
28
+ ENV['DAEMON_ENV'] = case ARGV.first
29
+ when "p"; "production"
30
+ when "d"; "development"
31
+ when "t"; "test"
32
+ else
33
+ ARGV.first || ENV['DAEMON_ENV'] || 'development'
34
+ end
35
+
36
+ puts "Loading #{ENV['DAEMON_ENV']} environment (daemon-kit #{DaemonKit::VERSION})"
37
+
38
+ exec "#{options[:irb]} #{libs} --simple-prompt"