dante 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,12 +1,11 @@
1
1
  # Dante
2
2
 
3
- Turn any process into a daemon with ease.
3
+ Turn any ruby into a daemon.
4
4
 
5
- ## Why Dante?
5
+ ## Description
6
6
 
7
- Dante is the simplest possible thing that can work to turn arbitrary ruby code into a 'robust' binary that
8
- can be started normally or as a daemon, and will store a pid file automatically. Dante also allows a process
9
- to be stopped just as easily using a standardized set of command line options.
7
+ Dante is the simplest possible thing that will work to turn arbitrary ruby code into an executable that
8
+ can be started via command line or start/stop a daemon, and will store a pid file for you.
10
9
 
11
10
  If you need to create a ruby executable and you want standard daemon start/stop with pid files
12
11
  and no hassle, this gem will be a great way to get started.
@@ -15,23 +14,34 @@ and no hassle, this gem will be a great way to get started.
15
14
 
16
15
  Add to your Gemfile:
17
16
 
18
- ```
17
+ ```ruby
19
18
  # Gemfile
20
19
 
21
20
  gem "dante"
22
21
  ```
23
22
 
23
+ or to your gemspec:
24
+
25
+ ```ruby
26
+ # mygem.gemspec
27
+
28
+ Gem::Specification.new do |s|
29
+ s.add_dependency "dante"
30
+ end
31
+ ```
32
+
24
33
  ## Usage
25
34
 
26
- Dante is meant to be used from any "bin" executable. For instance, to create a binary for a web server, create a file in `bin/mysite`:
35
+ Dante is meant to be used from any "bin" executable. For instance, to create a binary for a web server, create a file in `bin/myapp`:
27
36
 
28
37
  ```ruby
29
38
  #!/usr/bin/env ruby
30
39
 
31
40
  require File.expand_path("../../myapp.rb", __FILE__)
32
41
 
33
- Dante.run('myapp') do
34
- Thin::Server.start('0.0.0.0', port) do
42
+ Dante.run('myapp') do |opts|
43
+ # opts: host, pid_path, port, daemonize, user, group
44
+ Thin::Server.start('0.0.0.0', opts[:port]) do
35
45
  use Rack::CommonLogger
36
46
  use Rack::ShowExceptions
37
47
  run MyApp
@@ -39,6 +49,12 @@ Dante.run('myapp') do
39
49
  end
40
50
  ```
41
51
 
52
+ Be sure to properly make your bin executable:
53
+
54
+ ```
55
+ chmod +x bin/myapp
56
+ ```
57
+
42
58
  This gives your binary several useful things for free:
43
59
 
44
60
  ```
@@ -48,7 +64,7 @@ This gives your binary several useful things for free:
48
64
  will start the app undaemonized in the terminal, handling trapping and stopping the process.
49
65
 
50
66
  ```
51
- ./bin/myapp -d -P /var/run/myapp.pid
67
+ ./bin/myapp -p 8080 -d -P /var/run/myapp.pid
52
68
  ```
53
69
 
54
70
  will daemonize and start the process, storing the pid in the specified pid file.
@@ -65,6 +81,46 @@ will stop all daemonized processes for the specified pid file.
65
81
 
66
82
  Will return a useful help banner message explaining the simple usage.
67
83
 
84
+ ## Customization
85
+
86
+ In many cases, you will need to add custom flags/options or a custom description to your executable. You can do this
87
+ easily by using the `Dante::Runner` directly:
88
+
89
+ ```ruby
90
+ #!/usr/bin/env ruby
91
+
92
+ require File.expand_path("../../myapp.rb", __FILE__)
93
+
94
+ # Set default port to 8080
95
+ runner = Dante::Runner.new('myapp', :port => 8080)
96
+ # Sets the description in 'help'
97
+ runner.description = "This is myapp"
98
+ runner.with_options do |opts|
99
+ opts.on("-t", "--test TEST", String, "Test this thing") do |test|
100
+ options[:test] = test
101
+ end
102
+ end
103
+ # Parse command-line options and execute the process
104
+ runner.execute do |opts|
105
+ # opts: host, pid_path, port, daemonize, user, group
106
+ Thin::Server.start('0.0.0.0', opts[:port]) do
107
+ puts opts[:test] # Referencing my custom option
108
+ use Rack::CommonLogger
109
+ use Rack::ShowExceptions
110
+ run MyApp
111
+ end
112
+ end
113
+ ```
114
+
115
+ Now you would be able to do:
116
+
117
+ ```
118
+ ./bin/myapp -t custom
119
+ ```
120
+
121
+ and the `opts` would contain the `:test` option for use in your script. In addition, help will now contain
122
+ your customized description in the banner.
123
+
68
124
  ## God
69
125
 
70
126
  Dante can be used well in conjunction with the excellent God process manager. Simply, use Dante to daemonize a process
@@ -93,4 +149,8 @@ God.watch do |w|
93
149
  end
94
150
  ```
95
151
 
96
- and that's all. Of course now you can also easily daemonize as well as start/stop the process on the command line as well.
152
+ and that's all. Of course now you can also easily daemonize as well as start/stop the process on the command line as well.
153
+
154
+ ## Copyright
155
+
156
+ Copyright © 2011 Nathan Esquenazi. See [LICENSE](https://github.com/bazaarlabs/dante/blob/master/LICENSE) for details.
data/dante.gemspec CHANGED
@@ -20,4 +20,5 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_development_dependency 'rake'
22
22
  s.add_development_dependency 'minitest'
23
+ s.add_development_dependency 'mocha'
23
24
  end
data/lib/dante.rb CHANGED
@@ -16,12 +16,12 @@ require "dante/runner"
16
16
 
17
17
  module Dante
18
18
 
19
- # Forks a process and takes some list of params. I don't really know what this does.
19
+ # Forks a process and handles option parsing and start/stopping.
20
20
  #
21
21
  # @example
22
22
  # Dante.run("process-name") { Server.run! }
23
23
  #
24
24
  def self.run(name, options={}, &blk)
25
- Runner.new(name, options, &blk).execute!
25
+ Runner.new(name, options, &blk).execute
26
26
  end
27
27
  end
data/lib/dante/runner.rb CHANGED
@@ -7,7 +7,7 @@ require 'erb'
7
7
 
8
8
  This is a utility for setting up a binary executable for a service.
9
9
 
10
- # Dante::Runner.run("buffet", :pid_path => "/var/run/buffet.pid") do
10
+ # Dante::Runner.new("buffet", :pid_path => "/var/run/buffet.pid") do
11
11
  # ...startup service here...
12
12
  # end
13
13
 
@@ -18,7 +18,7 @@ module Dante
18
18
  # Signal to application that the process is shutting down
19
19
  class Abort < Exception; end
20
20
 
21
- attr_accessor :options
21
+ attr_accessor :options, :name, :description
22
22
 
23
23
  class << self
24
24
  def run(*args, &block)
@@ -29,23 +29,30 @@ module Dante
29
29
  def initialize(name, defaults={}, &block)
30
30
  @name = name
31
31
  @startup_command = block
32
- self.options = {
32
+ @options = {
33
33
  :host => '0.0.0.0',
34
34
  :pid_path => "/var/run/#{@name}.pid"
35
35
  }.merge(defaults)
36
+ end
36
37
 
37
- parse_options
38
+ # Accepts options for the process
39
+ # @runner.with_options { |opts| opts.on(...) }
40
+ def with_options(&block)
41
+ @with_options = block
42
+ end
38
43
 
39
- if options.include?(:kill)
40
- kill_pid(options[:kill] || '*')
41
- end
44
+ # Executes the runner based on options
45
+ # @runner.execute
46
+ # @runner.execute { ... }
47
+ def execute(&block)
48
+ parse_options
49
+ kill_pid(options[:kill] || '*') if options.include?(:kill)
42
50
 
43
51
  Process.euid = options[:user] if options[:user]
44
52
  Process.egid = options[:group] if options[:group]
45
- end
46
53
 
47
- # Executes the runner based on options
48
- def execute!
54
+ @startup_command = block if block_given?
55
+
49
56
  if !options[:daemonize]
50
57
  start
51
58
  else
@@ -65,7 +72,7 @@ module Dante
65
72
  exit
66
73
  }
67
74
 
68
- @startup_command.call
75
+ @startup_command.call(self.options) if @startup_command
69
76
  end
70
77
 
71
78
  def stop
@@ -74,11 +81,12 @@ module Dante
74
81
  end
75
82
 
76
83
  def parse_options
84
+ headline = [@name, @description].compact.join(" - ")
77
85
  OptionParser.new do |opts|
78
86
  opts.summary_width = 25
79
- opts.banner = ["#{@name} (#{VERSION})\n\n",
80
- "Usage: #{@name} [-P file] [-d] [-k port]\n",
81
- " #{@name} --help\n"].join("")
87
+ opts.banner = [headline, "\n\n",
88
+ "Usage: #{@name} [-p port] [-P file] [-d] [-k]\n",
89
+ " #{@name} --help\n"].compact.join("")
82
90
  opts.separator ""
83
91
 
84
92
  opts.on("-p", "--port PORT", Integer, "Specify port", "(default: #{options[:port]})") do |v|
@@ -109,6 +117,9 @@ module Dante
109
117
  puts "#{opts}\n"
110
118
  exit
111
119
  end
120
+
121
+ # Load options specified through 'with_options'
122
+ instance_exec(opts, &@with_options) if @with_options
112
123
  end.parse!
113
124
  options
114
125
  end
data/lib/dante/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dante
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/test/runner_test.rb CHANGED
@@ -5,7 +5,7 @@ describe "dante runner" do
5
5
  before do
6
6
  @process = TestingProcess.new('a')
7
7
  @runner = Dante::Runner.new('test-process') { @process.run_a! }
8
- @stdout = capture_stdout { @runner.execute! }
8
+ @stdout = capture_stdout { @runner.execute }
9
9
  end
10
10
 
11
11
  it "prints correct stdout" do
@@ -21,9 +21,10 @@ describe "dante runner" do
21
21
  describe "with daemonize flag" do
22
22
  before do
23
23
  @process = TestingProcess.new('b')
24
- @run_options = { :daemonize => true, :pid_path => "/tmp/dante.pid" }
25
- @runner = Dante::Runner.new('test-process-2', @run_options) { @process.run_b! }
26
- @stdout = capture_stdout { @runner.execute! }
24
+ @run_options = { :daemonize => true, :pid_path => "/tmp/dante.pid", :port => 8080 }
25
+ @runner = Dante::Runner.new('test-process-2', @run_options) { |opts|
26
+ @process.run_b!(opts[:port]) }
27
+ @stdout = capture_stdout { @runner.execute }
27
28
  sleep(1)
28
29
  end
29
30
 
@@ -32,7 +33,7 @@ describe "dante runner" do
32
33
  Process.kill "INT", @pid
33
34
  sleep(1) # Wait to complete
34
35
  @output = File.read(@process.tmp_path)
35
- assert_match /Started!!/, @output
36
+ assert_match /Started on 8080!!/, @output
36
37
  assert_match /Abort!!/, @output
37
38
  assert_match /Closing!!/, @output
38
39
  end
@@ -42,9 +43,70 @@ describe "dante runner" do
42
43
  Process.kill "TERM", @pid
43
44
  sleep(1) # Wait to complete
44
45
  @output = File.read(@process.tmp_path)
45
- assert_match /Started!!/, @output
46
+ assert_match /Started on 8080!!/, @output
46
47
  assert_match /Abort!!/, @output
47
48
  assert_match /Closing!!/, @output
48
49
  end
49
50
  end # daemonize
51
+
52
+ describe "with execute accepting block" do
53
+ before do
54
+ @process = TestingProcess.new('b')
55
+ @run_options = { :daemonize => true, :pid_path => "/tmp/dante.pid", :port => 8080 }
56
+ @runner = Dante::Runner.new('test-process-2', @run_options)
57
+ @stdout = capture_stdout { @runner.execute { |opts| @process.run_b!(opts[:port]) } }
58
+ sleep(1)
59
+ end
60
+
61
+ it "can properly handles aborts and starts / stops on INT" do
62
+ refute_equal 0, @pid = `cat /tmp/dante.pid`.to_i
63
+ Process.kill "INT", @pid
64
+ sleep(1) # Wait to complete
65
+ @output = File.read(@process.tmp_path)
66
+ assert_match /Started on 8080!!/, @output
67
+ assert_match /Abort!!/, @output
68
+ assert_match /Closing!!/, @output
69
+ end
70
+ end # execute with block
71
+
72
+ describe "with parsing options" do
73
+ before do
74
+ Object.send(:remove_const, 'ARGV'); ARGV = ['-t test_text']
75
+ @process = TestingProcess.new('a')
76
+ @runner = Dante::Runner.new('test-process')
77
+ @runner.with_options do |opts|
78
+ opts.on("-t", "--test TEST", String, "Test this thing") { |test| options[:test] = test }
79
+ end
80
+ @stdout = capture_stdout { @runner.execute { |opts| @process.run_a!(opts[:test]) } }
81
+ end
82
+
83
+ it "prints correct stdout" do
84
+ assert_match /Starting test-process/, @stdout
85
+ end
86
+
87
+ it "prints correct data" do
88
+ @output = File.read(@process.tmp_path)
89
+ assert_match /test_text/, @output
90
+ end
91
+
92
+ it "starts successfully when executed" do
93
+ @output = File.read(@process.tmp_path)
94
+ assert_match /Started/, @output
95
+ end
96
+ end # options parsing
97
+
98
+ describe "with help command" do
99
+ before do
100
+ Object.send(:remove_const, 'ARGV'); ARGV = ['--help']
101
+ @process = TestingProcess.new('a')
102
+ @runner = Dante::Runner.new('test-process')
103
+ @runner.description = "Test process banana"
104
+ @runner.expects(:exit).once.returns(true)
105
+ @stdout = capture_stdout { @runner.execute { @process.run_a! } }
106
+ end
107
+
108
+ it "prints correct stdout" do
109
+ assert_match /test-process - Test process banana/, @stdout
110
+ end
111
+ end # help
50
112
  end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'tempfile'
3
3
  require 'minitest/autorun'
4
+ require 'mocha'
4
5
  $:.unshift File.expand_path("../../lib")
5
6
  require 'dante'
6
7
 
@@ -32,16 +33,17 @@ class TestingProcess
32
33
  @tmp_path = "/tmp/dante-#{name}.log"
33
34
  end # initialize
34
35
 
35
- def run_a!
36
+ def run_a!(data=nil)
36
37
  @tmp = File.new(@tmp_path, 'w')
37
- @tmp.print("Started")
38
+ @tmp.puts("Started")
39
+ @tmp.puts "Data is: #{data}" if data
38
40
  @tmp.close
39
41
  end # run_a!
40
42
 
41
- def run_b!
43
+ def run_b!(port=9090)
42
44
  begin
43
45
  @tmp = File.new(@tmp_path, 'w')
44
- @tmp.print "Started!!"
46
+ @tmp.print "Started on #{port}!!"
45
47
  sleep(100)
46
48
  rescue Dante::Runner::Abort
47
49
  @tmp.print "Abort!!"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dante
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Nathan Esquenazi
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-21 00:00:00 -08:00
18
+ date: 2011-11-28 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -46,6 +46,20 @@ dependencies:
46
46
  version: "0"
47
47
  type: :development
48
48
  version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: mocha
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
49
63
  description: Turn any process into a demon.
50
64
  email:
51
65
  - nesquena@gmail.com