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