moved condition before/after hooks to action method
[god.git] / lib / god / watch.rb
blob450dfa34a840ebda4bc2dc06bf7135195e6f37fc
1 module God
2   
3   class Watch < Base
4     # config
5     attr_accessor :name, :cwd, :start, :stop, :restart, :grace
6     
7     # api
8     attr_accessor :behaviors, :conditions
9     
10     # 
11     def initialize
12       # no grace period by default
13       self.grace = 0
14       
15       # keep track of which action each condition belongs to
16       @action = nil
17       
18       self.behaviors = []
19       
20       # the list of conditions for each action
21       self.conditions = {:start => [],
22                          :restart => []}
23     end
24     
25     def behavior(kind)
26       # create the behavior
27       begin
28         b = Behavior.generate(kind)
29       rescue NoSuchBehaviorError => e
30         puts e.message
31         exit
32       end
33       
34       # send to block so config can set attributes
35       yield(b) if block_given?
36       
37       # exit if the Behavior is invalid, the Behavior will have printed
38       # out its own error messages by now
39       unless b.valid?
40         exit
41       end
42       
43       self.behaviors << b
44     end
45     
46     def start_if
47       @action = :start
48       yield(self)
49       @action = nil
50     end
51     
52     def restart_if
53       @action = :restart
54       yield(self)
55       @action = nil
56     end
57     
58     # Instantiate a Condition of type +kind+ and pass it into the optional
59     # block. Attributes of the condition must be set in the config file
60     def condition(kind)
61       # must be in a _if block
62       unless @action
63         puts "Watch#condition can only be called from inside a start_if block"
64         exit
65       end
66       
67       # create the condition
68       begin
69         c = Condition.generate(kind)
70       rescue NoSuchConditionError => e
71         puts e.message
72         exit
73       end
74       
75       # send to block so config can set attributes
76       yield(c) if block_given?
77       
78       # call prepare on the condition
79       c.prepare
80       
81       # exit if the Condition is invalid, the Condition will have printed
82       # out its own error messages by now
83       unless c.valid?
84         exit
85       end
86       
87       self.conditions[@action] << c
88     end
89     
90     def run
91       [:start, :restart].each do |cmd|
92         self.conditions[cmd].each do |c|
93           if c.test
94             puts self.name + ' ' + c.class.name + ' [ok]'
95           else
96             puts self.name + ' ' + c.class.name + ' [fail]'
97             c.after
98             action(cmd, c)
99             return
100           end
101         end
102       end
103     end
104     
105     private
106     
107     def action(a, c)
108       case a
109       when :start
110         puts self.start
111         Dir.chdir(self.cwd) do
112           call_action(c, :start, self.start)
113         end
114         sleep(self.grace)
115       when :restart
116         if self.restart
117           puts self.restart
118           Dir.chdir(self.cwd) do
119             call_action(c, :restart, self.restart)
120           end
121         else
122           self.action(:stop, c)
123           self.action(:start, c)
124         end
125         sleep(self.grace)
126       when :stop
127         puts self.stop
128         Dir.chdir(self.cwd) do
129           call_action(c, :stop, self.stop)
130         end
131         sleep(self.grace)
132       end      
133     end
134     
135     def call_action(condition, action, command)
136       # before
137       (self.behaviors + [condition]).each { |b| b.send("before_#{action}") }
138       
139       # action
140       if command.kind_of?(String)
141         # string command
142         system(command)
143       else
144         # lambda command
145         command.call
146       end
147       
148       # after
149       (self.behaviors + [condition]).each { |b| b.send("after_#{action}") }
150     end
151   end
152