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 +71 -11
- data/dante.gemspec +1 -0
- data/lib/dante.rb +2 -2
- data/lib/dante/runner.rb +25 -14
- data/lib/dante/version.rb +1 -1
- data/test/runner_test.rb +68 -6
- data/test/test_helper.rb +6 -4
- metadata +18 -4
data/README.md
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
# Dante
|
2
2
|
|
3
|
-
Turn any
|
3
|
+
Turn any ruby into a daemon.
|
4
4
|
|
5
|
-
##
|
5
|
+
## Description
|
6
6
|
|
7
|
-
Dante is the simplest possible thing that
|
8
|
-
can be started
|
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/
|
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
|
-
|
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
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
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
48
|
-
|
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 = ["
|
80
|
-
"Usage: #{@name} [-P file] [-d] [-k
|
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
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) {
|
26
|
-
|
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.
|
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:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
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-
|
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
|