[Feature] Add the possibility to pause/unpause by sending OS signal #254

Merged
merged 1 commit into from Mar 14, 2012
View
12 README.md
@@ -339,6 +339,18 @@ $ guard start -I
$ guard start --no-vendor
```
+### Pause watching (all but Windows)
+
+```bash
+$ kill -USR1 <guard_pid>
+```
+
+### Continue watching (all but Windows)
+
+```bash
+$ kill -USR2 <guard_pid>
+```
+
### List
You can list the available Guards with the `list` task:
View
14 lib/guard/listener.rb
@@ -82,6 +82,7 @@ def start_reactor
return if ENV["GUARD_ENV"] == 'test'
Thread.new do
+ add_signal_handlers unless self.windows?
loop do
if @changed_files != [] && !@paused
changed_files = @changed_files.dup
@@ -138,6 +139,19 @@ def update_last_event
@last_event = Time.now
end
+ # Add signals handlers (works only on posix-compatible systems).
+ # (Yes, they're not atomic. Be nice to them. :)
+ def add_signal_handlers
+ Signal.trap("USR1") do
+ UI.info "Paused Guard on signal USR1" unless @paused
+ pause
+ end
+ Signal.trap("USR2") do
+ UI.info "Continued Guard on signal USR2" if @paused
+ run
+ end
+ end
+
# Get the modified files.
#
# If the `:watch_all_modifications` option is true, then moved and
View
197 spec/guard/listeners/signals_spec.rb
@@ -0,0 +1,197 @@
+require 'spec_helper'
+require 'guard/listener'
+
+describe Guard::Listener do
+
+ if windows?
+ STDERR.puts "ERROR guard listener signal testing not run because windows"
+ else # ! windows
+
+ describe 'when #initialize a new Listener' do
+ let(:guard) { Guard::Listener.new }
+ let(:ui) { Guard::UI }
+
+ before { ENV['GUARD_ENV'] = 'test_signals' }
+ after { ENV['GUARD_ENV'] = 'test' if ENV['GUARD_ENV'] == 'test_signals' }
+
+ # ---- USR* signals while running
+
+ context 'on an USR1 signal' do
+ before { Process.kill :USR1, Process.pid }
+
+ it '#pause once' do
+ guard.should_receive(:pause).once
+ guard.should_not_receive(:run).any_number_of_times
+
+ ui.should_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on an USR2 signal' do
+ before { Process.kill :USR2, Process.pid }
+
+ it 'does nothing' do
+ guard.should_not_receive(:pause).any_number_of_times
+ guard.should_not_receive(:run).any_number_of_times
+
+ ui.should_not_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on duplicate USR1 signals' do
+ before do
+ Process.kill :USR1, Process.pid
+ Process.kill :USR1, Process.pid
+ end
+
+ it '#pause once' do
+ guard.should_receive(:pause).once
+ guard.should_receive(:run).any_number_of_times
+
+ ui.should_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on duplicate USR2 signals' do
+ before do
+ Process.kill :USR2, Process.pid
+ Process.kill :USR2, Process.pid
+ end
+
+ it 'does nothing' do
+ guard.should_not_receive(:pause).any_number_of_times
+ guard.should_not_receive(:run).any_number_of_times
+
+ ui.should_not_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on an USR1 and then USR2 signal' do
+ before do
+ Process.kill :USR1, Process.pid
+ Process.kill :USR2, Process.pid
+ end
+
+ it '#pause and then #run' do
+ guard.should_receive(:pause).once
+ guard.should_receive(:run).once
+
+ ui.should_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on an USR2 and then USR1 signal' do
+ before do
+ Process.kill :USR2, Process.pid
+ Process.kill :USR1, Process.pid
+ end
+
+ it '#run once' do
+ guard.should_receive(:pause).once
+ guard.should_not_receive(:run).any_number_of_times
+
+ ui.should_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+
+ # ---- USR* signals while started and then paused
+
+ context 'when #pause' do
+ before { guard.stub(:pause) }
+
+ context 'on an USR1 signal' do
+ before { Process.kill :USR1, Process.pid }
+
+ it 'does nothing' do
+ guard.should_not_receive(:pause).any_number_of_times
+ guard.should_not_receive(:run).any_number_of_times
+
+ ui.should_not_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on an USR2 signal' do
+ before { Process.kill :USR2, Process.pid }
+
+ it '#pause once' do
+ guard.should_not_receive(:pause).any_number_of_times
+ guard.should_receive(:run).once
+
+ ui.should_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on duplicate USR1 signals' do
+ before do
+ Process.kill :USR1, Process.pid
+ Process.kill :USR1, Process.pid
+ end
+
+ it 'does nothing' do
+ guard.should_not_receive(:pause).any_number_of_times
+ guard.should_not_receive(:run).any_number_of_times
+
+ ui.should_not_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_not_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on duplicate USR2 signals' do
+ before do
+ Process.kill :USR2, Process.pid
+ Process.kill :USR2, Process.pid
+ end
+
+ it '#run once' do
+ guard.should_not_receive(:pause).any_number_of_times
+ guard.should_receive(:run).once
+
+ ui.should_not_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on an USR1 and then USR2 signal' do
+ before do
+ Process.kill :USR1, Process.pid
+ Process.kill :USR2, Process.pid
+ end
+
+ it '#run once' do
+ guard.should_not_receive(:pause).any_number_of_times
+ guard.should_receive(:run).once
+
+ ui.should_not_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+
+ context 'on an USR2 and then USR1 signal' do
+ before do
+ Process.kill :USR2, Process.pid
+ Process.kill :USR1, Process.pid
+ end
+
+ it '#run and then #pause' do
+ guard.should_not_receive(:pause).once
+ guard.should_receive(:run).once
+
+ ui.should_receive(:info).with("Paused Guard on signal USR1")
+ ui.should_receive(:info).with("Continued Guard on signal USR2")
+ end
+ end
+ end # when #pause
+
+ end # describe when #start
+ end # !windows
+end # describe Guard::Listener