dante 0.0.1 → 0.0.2

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/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