zeusd 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,5 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+
19
+ *.log
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in zeusd.gemspec
4
4
  gemspec
5
5
 
6
+ gem 'simplecov', :require => false
7
+
6
8
  group :tool do
7
9
  gem "guard-rspec"
8
10
  gem "pry"
data/Guardfile CHANGED
@@ -1,7 +1,6 @@
1
1
  guard :rspec, :failed_mode => :none do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
- watch(%r{^lib/zeusd/(.+)\.rb$}) { |m| "spec/lib/zeusd/#{m[1]}_spec.rb" }
3
+ watch(%r{^lib/zeusd/(.+)\.rb$}) { |m| "spec/zeusd/#{m[1]}_spec.rb" }
5
4
  watch('spec/spec_helper.rb') { "spec" }
6
5
  end
7
6
 
data/README.md CHANGED
@@ -1,48 +1,52 @@
1
- # Zeusd
1
+ # Zeusd [![Gem Version](https://badge.fury.io/rb/zeusd.png)](http://badge.fury.io/rb/zeusd) [![Build Status](https://travis-ci.org/veloper/zeusd.png?branch=master)](https://travis-ci.org/veloper/zeusd) [![Code Climate](https://codeclimate.com/github/veloper/zeusd.png)](https://codeclimate.com/github/veloper/zeusd)
2
2
 
3
- Run the Zeud Gem as a daemon
3
+ *Run Zeus as a daemon.*
4
4
 
5
- [![Build Status](https://travis-ci.org/veloper/zeusd.png?branch=master)](https://travis-ci.org/veloper/zeusd) [![Code Climate](https://codeclimate.com/github/veloper/zeusd.png)](https://codeclimate.com/github/veloper/zeusd)
5
+ ## Introduction
6
6
 
7
+ Zeus**d** lets you work with the [Zeus Gem](https://github.com/burke/zeus) like it's a daemon -- allowing greater control and easier scripting
7
8
 
8
- ## Installation
9
-
10
- Add this line to your application's Gemfile:
11
-
12
- gem 'zeusd'
9
+ ### Primary Commands
13
10
 
14
- And then execute:
15
-
16
- $ bundle
17
-
18
- Or install it yourself as:
11
+ ```
12
+ $ zeusd start [--cwd=/path/to/rails/root]
13
+ [--block | -b]
14
+ [--verbose | -v]
19
15
 
20
- $ gem install zeusd
16
+ $ zeusd restart [--cwd=/path/to/rails/root]
17
+ [--block | -b]
18
+ [--verbose | -v]
21
19
 
22
- ## Usage
20
+ $ zeusd stop [--cwd=/path/to/rails/root]
21
+ [--verbose | -v]
22
+ ```
23
23
 
24
- ### Commands
24
+ ### Utility Commands
25
25
 
26
26
  ```
27
- zeusd start [--block]
28
- zeusd stop
29
- zeusd restart
27
+ $ zeusd tail [--cwd=/path/to/rails/root]
28
+ [--follow | -f]
30
29
  ```
31
30
 
32
- ### Global Flags
33
- * `--cwd=current/work/directory/of/rails/app` or alias `-d`
34
- * `--verbose` or `-v`
31
+ ## Installation
35
32
 
33
+ ```
34
+ $ gem install zeusd
35
+ ```
36
36
 
37
37
  ## Contributing
38
38
 
39
39
  1. Fork it
40
40
  2. Create your feature branch (`git checkout -b my-new-feature`)
41
- 3. Write and test your changes
41
+ 3. Write passing specs that test your changes
42
42
  3. Commit your changes and specs (`git commit -am 'Add some feature'`)
43
43
  4. Push to the branch (`git push origin my-new-feature`)
44
44
  5. Create new Pull Request
45
45
 
46
+ ## Author
47
+
48
+ [Daniel Doezema](http://dan.doezema.com)
49
+
46
50
  ## License
47
51
 
48
52
  * Zeusd is released under the New BSD license. http://dan.doezema.com/licenses/new-bsd/
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rspec/core/rake_task'
3
3
 
4
- RSpec::Core::RakeTask.new('spec')
4
+ RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- # If you want to make this the default task
7
6
  task :default => :spec
data/bin/zeusd CHANGED
@@ -4,37 +4,35 @@ require "zeusd"
4
4
  class ZeusdCLI < Thor
5
5
  class_option :verbose, :type => :boolean, :aliases => :v
6
6
  class_option :block, :type => :boolean, :aliases => :b
7
- class_option :cwd, :type => :string, :aliases => :d
8
- class_option :log, :type => :string, :aliases => :l
7
+ class_option :cwd, :type => :string
9
8
 
10
- desc "start", "."
9
+ desc "start", "Start the daemon."
11
10
  def start
12
- daemon.start! :block => options[:block]
11
+ daemon.start!(:block => options[:block])
13
12
  end
14
13
 
15
- desc "restart", "."
14
+ desc "restart", "Restart the daemon."
16
15
  def restart
17
- stop
18
- start
16
+ daemon.restart!(:block => options[:block])
19
17
  end
20
18
 
21
- desc "stop", "."
19
+ desc "stop", "Stop the daemon."
22
20
  def stop
23
21
  daemon.stop!
24
22
  end
25
23
 
26
- desc "status", "."
27
- def status
28
- # Zeusd::Daemon.new(options).stop!
24
+ desc "tail", "Tail the daemon's log."
25
+ method_option :follow, :type => :boolean, :aliases => :f
26
+ def tail
27
+ cmd = "tail#{options[:follow] ? ' -f' : ''} -n 25 #{daemon.log_file.to_path}"
28
+ puts "\n\n[Zeusd] exec(#{cmd})\n\n"
29
+ exec(cmd)
29
30
  end
30
31
 
31
32
  protected
32
33
 
33
34
  def daemon
34
- Zeusd::Daemon.new(
35
- :verbose => options[:verbose],
36
- :cwd => options[:cwd]
37
- )
35
+ Zeusd::Daemon.new(:verbose => options[:verbose], :cwd => options[:cwd])
38
36
  end
39
37
 
40
38
  end
data/lib/zeusd.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'zeusd/version'
2
2
  require 'zeusd/process'
3
- require 'zeusd/state_interpreter'
3
+ require 'zeusd/interpreter'
4
4
  require 'zeusd/daemon'
5
5
 
6
6
  module Zeusd
data/lib/zeusd/daemon.rb CHANGED
@@ -1,78 +1,113 @@
1
1
  require 'thread'
2
2
  require 'childprocess'
3
3
  require 'pathname'
4
+ require 'hooks'
4
5
 
5
6
  module Zeusd
6
7
  class DaemonException < StandardError; end
7
8
 
8
9
  class Daemon
9
- attr_reader :cwd, :verbose
10
- attr_reader :queue
11
- attr_reader :state
12
- attr_reader :child_process, :reader, :writer
10
+ include Hooks
11
+ define_hooks :after_output, :after_start!, :after_stop!, :after_start_process!
13
12
 
14
- def initialize(options = {})
15
- @cwd = Pathname.new(options.fetch(:cwd, Dir.pwd)).realpath
16
- @verbose = options.fetch(:verbose, false)
17
- @queue = Queue.new
18
- @state = StateInterpreter.new
19
- on_update(&method(:puts)) if verbose
20
- end
13
+ after_start! { log(:start) }
14
+ after_stop! { log(:stop) }
15
+ after_output {|x| log(x, :zeus) }
21
16
 
22
- def stop!
23
- processes = process ? Array([process.descendants, process]).flatten : []
24
- if processes.any?
25
- Zeusd::Process.kill!(processes.map(&:pid))
26
- end
17
+ after_start_process! :ensure_log_worker
18
+
19
+ after_stop! do
27
20
  (socket_file.delete rescue nil) if socket_file.exist?
28
- if (alive_processes = processes).all?(&:alive?)
29
- raise DaemonException, "Unable to KILL processes: " + alive_processes.join(', ')
30
- else
31
- @process = nil
32
- true
33
- end
21
+ @process = nil
22
+ end
23
+
24
+ after_output do |output|
25
+ interpreter.translate(output)
26
+ puts(output) if verbose?
27
+ end
28
+
29
+ attr_reader :cwd, :verbose, :log_file, :log_queue, :interpreter, :child_process
30
+
31
+ def initialize(options = {})
32
+ @cwd = Pathname.new(options.fetch(:cwd, Dir.pwd)).realpath
33
+ @verbose = options.fetch(:verbose, false)
34
+ @interpreter = Interpreter.new
34
35
  end
35
36
 
36
37
  def start!(options = {})
37
- @process = Zeusd::Process.find(start_child_process!.pid)
38
+ @process = Zeusd::Process.find(start_process!.pid)
38
39
 
39
40
  if options.fetch(:block, false)
40
- loop do
41
- if loaded?
42
- puts state.last_status
43
- break
44
- end
45
- sleep(0.1)
46
- end
41
+ sleep(0.1) until loaded?
47
42
  end
48
43
 
49
- process
44
+ self
45
+ ensure
46
+ run_hook :after_start!
50
47
  end
51
48
 
52
- def process
53
- @process ||= Process.all.find do |p|
54
- !!p.command[/zeus.*start$/] && p.cwd == cwd
49
+ def restart!(options = {})
50
+ stop!.start!(options)
51
+ end
52
+
53
+ def stop!
54
+ return self unless process
55
+
56
+ # Kill Pids and Wait
57
+ process.kill!(:recursive => true, :wait => true)
58
+
59
+ # Check for remaining processes
60
+ if[process, process.descendants].flatten.select(&:alive?).any?
61
+ raise DaemonException, "Unable to KILL processes: " + alive_processes.join(', ')
55
62
  end
63
+
64
+ self
65
+ ensure
66
+ run_hook :after_stop!
67
+ end
68
+
69
+ def process
70
+ @process ||= Process.all.find {|p| !!p.command[/zeus.*start$/] && p.cwd == cwd }
56
71
  end
57
72
 
58
73
  def loaded?
59
- process.descendants.all?(&:asleep?)
74
+ interpreter.complete?
60
75
  end
61
76
 
62
- def on_update(&block)
63
- @on_update = block if block_given?
64
- @on_update
77
+
78
+ def log_file
79
+ cwd.join('log/zeusd.log')
65
80
  end
66
81
 
67
82
  def socket_file
68
83
  cwd.join('.zeus.sock')
69
84
  end
70
85
 
86
+ def verbose?
87
+ !!verbose
88
+ end
89
+
71
90
  protected
72
91
 
73
- def start_child_process!
92
+ def log(entry, type = :zeusd)
93
+ log_queue << "<#{type.to_s} utc='#{Time.now.utc}'>#{entry}</#{type.to_s}>\n"
94
+ end
95
+
96
+ def log_queue
97
+ @log_queue ||= Queue.new
98
+ end
99
+
100
+ def ensure_log_worker
101
+ @log_worker ||= Thread.new do
102
+ while value = log_queue.shift
103
+ log_file.open("a+") {|f| f.write(value) }
104
+ end
105
+ end
106
+ end
107
+
108
+ def start_process!
74
109
  @reader, @writer = IO.pipe
75
- @child_process = ChildProcess.build("zeus", "start")
110
+ @child_process = ChildProcess.build("zeus", "start")
76
111
  @child_process.environment["BUNDLE_GEMFILE"] = cwd.join("Gemfile").to_path
77
112
  @child_process.io.stdout = @child_process.io.stderr = @writer
78
113
  @child_process.cwd = cwd.to_path
@@ -80,22 +115,15 @@ module Zeusd
80
115
  @child_process.start
81
116
  @writer.close
82
117
 
83
- Thread.new do
84
- while (buffer = (reader.readpartial(10000) rescue nil)) do
85
- state << buffer
86
- queue << buffer
87
- end
88
- end
118
+ run_hook :after_start_process!
89
119
 
90
- if on_update.is_a?(Proc)
91
- Thread.new do
92
- while output = queue.pop
93
- on_update.call(output)
94
- end
120
+ Thread.new do
121
+ while (buffer = (@reader.readpartial(10000) rescue nil)) do
122
+ run_hook :after_output, buffer
95
123
  end
96
124
  end
97
125
 
98
- sleep(0.1) until state.commands.any?
126
+ sleep 0.1 until interpreter.commands.any?
99
127
 
100
128
  @child_process
101
129
  end
@@ -1,23 +1,22 @@
1
- require 'stringio'
2
1
  module Zeusd
3
- class StateInterpreter
2
+ class Interpreter
4
3
  STATES = %w[ready crashed running connecting waiting]
5
4
 
6
5
  attr_reader :lines
7
6
  attr_reader :state_colors, :commands, :errors
7
+ attr_reader :last_status
8
8
 
9
9
  def initialize(*args)
10
10
  @state_colors = Hash[STATES.zip([nil]*STATES.length)]
11
11
  @commands = {}
12
12
  @errors = []
13
13
  @lines = []
14
- super(*args)
15
14
  end
16
15
 
17
- def <<(input)
18
- input.split("\n").map{|x| Line.new(x) }.each do |line|
16
+ def translate(zeus_output)
17
+ zeus_output.split("\n").map{|x| Line.new(x) }.each do |line|
19
18
  # State Colors
20
- if @state_colors.values.any?(&:nil?) && line.legend?
19
+ if @state_colors.values.any?(&:nil?) && line.state_legend?
21
20
  STATES.each do |state|
22
21
  state_colors[state] = line.color_of(state)
23
22
  end
@@ -32,15 +31,22 @@ module Zeusd
32
31
  # Add Line
33
32
  @lines << line
34
33
  end
34
+
35
+ # Garbage Collection
36
+ if @lines.length > 100
37
+ @lines = @lines.last(100)
38
+ end
35
39
  end
36
40
 
37
- def is_complete?
41
+ def complete?
38
42
  return false if errors.any?
39
- return true if commands.all? {|command, status| %[crashed running].include?(status)}
43
+ return true if commands.all? {|command, status| %[crashed ready].include?(status)}
40
44
  false
41
45
  end
42
46
 
43
- def last_status
47
+
48
+
49
+ def last_update
44
50
  @lines[@lines.rindex(&:update?)..-1].join("\n").to_s
45
51
  end
46
52
 
@@ -55,12 +61,12 @@ module Zeusd
55
61
  end
56
62
 
57
63
  def command
58
- if match = self.match(/^(\e.*?)zeus\s(.*?)(\s|\e)/)
59
- { :name => match[2], :color => match[1] }
64
+ if @match ||= self.match(/^(\e.*?)zeus\s(.*?)(\s|\e)/)
65
+ { :name => @match[2], :color => @match[1] }
60
66
  end
61
67
  end
62
68
 
63
- def legend?
69
+ def state_legend?
64
70
  STATES.all?{|state| !!self[state]}
65
71
  end
66
72
 
data/lib/zeusd/process.rb CHANGED
@@ -7,11 +7,15 @@ module Zeusd
7
7
  "stat" => ->(x){x.to_s},
8
8
  "command" => ->(x){x.to_s}
9
9
  }
10
- attr_accessor :attributes
11
- attr_accessor :children
10
+ attr_accessor :attributes, :children
12
11
 
13
- def initialize(attributes = {})
14
- self.attributes = attributes
12
+ def initialize(attributes_or_pid)
13
+ if attributes_or_pid.is_a? Hash
14
+ self.attributes = attributes_or_pid
15
+ else
16
+ self.attributes = {"pid" => attributes_or_pid.to_i}
17
+ reload!
18
+ end
15
19
  end
16
20
 
17
21
  def self.ps(options = {})
@@ -35,17 +39,10 @@ module Zeusd
35
39
  end
36
40
  end
37
41
 
38
- # Note: Non-chinable, AND joined, Proc allowed for value
39
- # {"attr" => value}
40
42
  def self.where(criteria, options = {})
41
43
  all(options).select do |process|
42
44
  criteria.all? do |key, value|
43
- case value
44
- when Array then value.include?(process.send(key))
45
- when Proc then !!value.call(process)
46
- else
47
- process.send(key) == value
48
- end
45
+ process.send(key) == value
49
46
  end
50
47
  end
51
48
  end
@@ -56,12 +53,24 @@ module Zeusd
56
53
  end
57
54
  end
58
55
 
56
+ def self.wait(pids = [])
57
+ pids = Array(pids).map(&:to_s)
58
+ loop do
59
+ break if (self.ps.map{|x| x["pid"]} & pids).length.zero?
60
+ sleep(0.1)
61
+ end
62
+ end
63
+
59
64
  def self.kill!(pids, options = {})
60
- signal = options.fetch(:signal, "INT")
61
- pids = Array(pids).map(&:to_i).select{|x| x > 0}
62
- if pids.any?
63
- system("kill -#{signal} #{pids.join(' ')}")
64
- $?.success?
65
+ pids = Array(pids).map(&:to_i).select{|x| x > 0}
66
+ processes = pids.map{|pid| self.new(pid)}
67
+ signal = options.fetch(:signal, "TERM")
68
+ wait = options.fetch(:wait, false)
69
+ return false if processes.any?(&:dead?)
70
+
71
+ if system("kill -#{signal} #{processes.map(&:pid).join(' ')}")
72
+ self.wait(pids) if wait
73
+ true
65
74
  else
66
75
  false
67
76
  end
@@ -69,7 +78,7 @@ module Zeusd
69
78
 
70
79
  def reload!
71
80
  self.attributes = self.class.ps(:pid => pid).first || {}
72
- @children = nil
81
+ @children = nil
73
82
  !attributes.empty?
74
83
  end
75
84
 
@@ -112,8 +121,14 @@ module Zeusd
112
121
  end
113
122
 
114
123
  def kill!(options = {})
115
- self.class.kill!(pid, options)
116
- reload!
124
+ return false if dead?
125
+ opts = options.dup
126
+
127
+ pids = [pid].tap do |x|
128
+ x.concat(descendants.map(&:pid)) if !!opts.delete(:recursive)
129
+ end
130
+
131
+ self.class.kill!(pids, opts)
117
132
  end
118
133
 
119
134
  def descendants(options = {})
@@ -123,11 +138,7 @@ module Zeusd
123
138
  end
124
139
 
125
140
  def children(options = {})
126
- @children = self.class.where("ppid" => pid).tap do |processes|
127
- if options.fetch(:recursive, false)
128
- processes.each{|p| p.children(options)}
129
- end
130
- end
141
+ @children = self.class.where("ppid" => pid)
131
142
  end
132
143
 
133
144
  def attributes=(hash)
data/lib/zeusd/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Zeusd
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,6 @@
1
- require 'bundler/setup'
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
2
4
  require 'zeusd'
3
5
 
4
6
  DUMMY_APP_PATH = File.expand_path('../dummy', __FILE__)
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Signal.trap('USR1') do
4
+ sleep (ARGV[1] || 1).to_f
5
+ exit 0
6
+ end
7
+
8
+ stop_time = Time.now.to_f + (ARGV[0] || 2).to_f
9
+
10
+ sleep 0.01 until Time.now.to_i.to_f >= stop_time
@@ -3,23 +3,51 @@ require 'spec_helper'
3
3
  describe Zeusd::Daemon do
4
4
  let(:daemon) { Zeusd::Daemon.new(:cwd => DUMMY_APP_PATH) }
5
5
  after(:each) { daemon.stop! }
6
+
6
7
  describe ".start!" do
8
+ subject { daemon.start!(:verbose => true) }
9
+ it { should be daemon }
10
+ it { should_not be_loaded }
7
11
 
8
- context "blocking" do
12
+ describe ":block option" do
9
13
  subject { daemon.start!(:block => true) }
10
- it { should be_a Zeusd::Process }
14
+ it { should be_loaded }
15
+ end
16
+ end
11
17
 
12
- it "should be a zeus start process" do
13
- process = daemon.start!(:block => true)
14
- process.command[/zeus.*?start$/].should_not be_nil, "Process Command: " + process.command
15
- end
18
+ describe ".stop!" do
19
+ subject { daemon.start!.stop! }
20
+ it { should be daemon }
21
+ it { should_not be_loaded }
22
+ end
23
+
24
+ describe ".restart!" do
25
+ subject { daemon }
26
+ context "when daemon is already running" do
27
+ before { subject.start!.restart!(:block => true) }
28
+ it { should be_loaded }
16
29
  end
30
+ end
17
31
 
18
- context "non-blocking" do
19
- subject { daemon.start! }
20
- it { should be_a Zeusd::Process }
32
+ describe ".process" do
33
+ context "before start" do
34
+ subject { daemon.process }
35
+ it { should be_nil }
21
36
  end
22
37
 
38
+ context "after start" do
39
+ subject { daemon.start!.process }
40
+ it { should be_a Zeusd::Process}
41
+ it { should be_alive }
42
+ its "a zeus start process" do
43
+ subject.command.should match(/zeus.*?start$/)
44
+ end
45
+ end
46
+
47
+ context "after start and stop" do
48
+ subject { daemon.start!.stop!.process }
49
+ it { should be_nil }
50
+ end
23
51
  end
24
52
 
25
53
  end
@@ -1,16 +1,83 @@
1
1
  require 'spec_helper'
2
+ require 'benchmark'
2
3
  require 'zeusd'
3
4
 
4
5
  describe Zeusd::Process do
5
6
 
6
- def spawn_dummy_process(ttl_seconds = 1)
7
- spawn("while [ $(date +\"%s\") -le #{Time.now.to_i + ttl_seconds} ]; do continue; done")
7
+ def spawn_dummy_process(ttl = 1, usr1delay = 0.5, options = {})
8
+ ttl = ttl.to_f.to_s
9
+ usr1delay = usr1delay.to_f.to_s
10
+ script = File.expand_path("../../support/dummy_process.rb", __FILE__)
11
+ p = ChildProcess.build(script, ttl, usr1delay)
12
+ p.cwd = options[:cwd] if options[:cwd]
13
+ p.detach = true
14
+ p.start
15
+ p
8
16
  end
9
17
 
18
+ before(:each) do
19
+ @dummy_ttl = 1
20
+ @dummy_usr1delay = 0.5
21
+ @dummy_process = spawn_dummy_process(@dummy_ttl, @dummy_usr1delay)
22
+ end
10
23
  subject(:model) { Zeusd::Process }
11
24
 
12
- describe "process management class methods" do
13
- before(:each) { @dummy_pid = spawn_dummy_process }
25
+
26
+ describe "process instance" do
27
+ subject { model.find(@dummy_process.pid) }
28
+ it { should be_a Zeusd::Process }
29
+ it { should be_alive }
30
+ it { should_not be_dead }
31
+ end
32
+
33
+ describe "instance methods" do
34
+ subject { model.find(@dummy_process.pid) }
35
+
36
+ describe ".cwd" do
37
+ it "return the current working directory" do
38
+ subject.cwd.to_path == Dir.pwd
39
+ end
40
+ end
41
+
42
+ describe ".kill!" do
43
+ context "when process exists" do
44
+ it "kills the process and returns true" do
45
+ subject.kill!(:wait => true).should be_true
46
+ subject.should be_dead
47
+ end
48
+ end
49
+
50
+ context "when processes does not exists" do
51
+ it "returns false" do
52
+ subject.kill!(:wait => true).should be_true
53
+ subject.kill!.should be_false
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+
60
+ describe "class methods" do
61
+
62
+ describe "::kill!" do
63
+ it "kills a process in under 0.1 seconds" do
64
+ model.kill!(@dummy_process.pid)
65
+ sleep 0.1
66
+ model.find(@dummy_process.pid).should be_nil
67
+ end
68
+
69
+ it "blocks until the process exits" do
70
+ Benchmark.realtime do
71
+ model.kill!(@dummy_process.pid, :signal => "USR1", :wait => true).should be_true
72
+ end.should be < 1.0
73
+ end
74
+ end
75
+
76
+ describe "::wait" do
77
+ it "blocks until the process exits" do
78
+ Benchmark.realtime { model.wait(@dummy_process.pid) }.should be > 1
79
+ end
80
+ end
14
81
 
15
82
  describe "::ps" do
16
83
  subject { model.ps }
@@ -19,7 +86,7 @@ describe Zeusd::Process do
19
86
  subject.all?{|x| x.is_a?(Hash)}.should be_true
20
87
  end
21
88
  it "includes the dummy process" do
22
- subject.map{|x|x["pid"]}.should include(@dummy_pid.to_s)
89
+ subject.map{|x|x["pid"]}.should include(@dummy_process.pid.to_s)
23
90
  end
24
91
  it "allows additional -o keywords" do
25
92
  model.ps(:keywords => "user").first.should include("user")
@@ -60,7 +127,7 @@ describe Zeusd::Process do
60
127
  it { should have_at_least(2).items }
61
128
  end
62
129
  context "criteria not met" do
63
- subject {model.where(:pid => @dummy_pid, :pgid => 9999999999999)}
130
+ subject {model.where(:pid => @dummy_process.pid, :pgid => 9999999999999)}
64
131
  it { should be_an Array }
65
132
  it { should be_empty }
66
133
  end
@@ -68,14 +135,14 @@ describe Zeusd::Process do
68
135
  end
69
136
 
70
137
  describe "::find" do
71
- subject { model.find(@dummy_pid) }
138
+ subject { model.find(@dummy_process.pid) }
72
139
  context "existing process" do
73
140
  it { should be_a Zeusd::Process }
74
141
  it { should be_alive }
75
- it { subject.pid.should eq(@dummy_pid) }
142
+ it { subject.pid.should eq(@dummy_process.pid) }
76
143
  end
77
144
  context "non-existant process" do
78
- before(:each) { ::Process.kill("KILL", @dummy_pid); ::Process.waitpid(@dummy_pid) }
145
+ before(:each) { @dummy_process.stop }
79
146
  it { should be_nil }
80
147
  end
81
148
  end
data/zeusd.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_runtime_dependency "thor"
22
22
  spec.add_runtime_dependency "childprocess"
23
+ spec.add_runtime_dependency "hooks"
23
24
  spec.add_runtime_dependency "zeus"
24
25
 
25
26
  spec.add_development_dependency "bundler", "~> 1.3"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zeusd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-07 00:00:00.000000000 Z
12
+ date: 2014-02-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: hooks
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
46
62
  - !ruby/object:Gem::Dependency
47
63
  name: zeus
48
64
  requirement: !ruby/object:Gem::Requirement
@@ -126,8 +142,8 @@ files:
126
142
  - bin/zeusd
127
143
  - lib/zeusd.rb
128
144
  - lib/zeusd/daemon.rb
145
+ - lib/zeusd/interpreter.rb
129
146
  - lib/zeusd/process.rb
130
- - lib/zeusd/state_interpreter.rb
131
147
  - lib/zeusd/version.rb
132
148
  - spec/dummy/.gitignore
133
149
  - spec/dummy/Gemfile
@@ -180,6 +196,7 @@ files:
180
196
  - spec/dummy/vendor/plugins/.gitkeep
181
197
  - spec/dummy/zeus.json
182
198
  - spec/spec_helper.rb
199
+ - spec/support/dummy_process.rb
183
200
  - spec/zeusd/daemon_spec.rb
184
201
  - spec/zeusd/process_spec.rb
185
202
  - zeusd.gemspec
@@ -198,7 +215,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
198
215
  version: '0'
199
216
  segments:
200
217
  - 0
201
- hash: -2296072518175803333
218
+ hash: -3204481942119935445
202
219
  required_rubygems_version: !ruby/object:Gem::Requirement
203
220
  none: false
204
221
  requirements:
@@ -207,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
224
  version: '0'
208
225
  segments:
209
226
  - 0
210
- hash: -2296072518175803333
227
+ hash: -3204481942119935445
211
228
  requirements: []
212
229
  rubyforge_project:
213
230
  rubygems_version: 1.8.25
@@ -266,5 +283,6 @@ test_files:
266
283
  - spec/dummy/vendor/plugins/.gitkeep
267
284
  - spec/dummy/zeus.json
268
285
  - spec/spec_helper.rb
286
+ - spec/support/dummy_process.rb
269
287
  - spec/zeusd/daemon_spec.rb
270
288
  - spec/zeusd/process_spec.rb