alloy-kicker 1.1.2 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +16 -1
- data/Rakefile +1 -1
- data/VERSION.yml +2 -2
- data/bin/kicker +1 -1
- data/lib/kicker.rb +46 -109
- data/lib/kicker/callback_chain.rb +21 -0
- data/lib/kicker/growl.rb +23 -0
- data/lib/kicker/options.rb +33 -0
- data/lib/kicker/recipes/could_not_handle_file.rb +7 -0
- data/lib/kicker/recipes/execute_cli_command.rb +7 -0
- data/lib/kicker/utils.rb +34 -0
- data/lib/kicker/validate.rb +24 -0
- data/test/callback_chain_test.rb +103 -0
- data/test/filesystem_change_test.rb +75 -0
- data/test/initialization_test.rb +133 -0
- data/test/options_test.rb +25 -0
- data/test/recipes/could_not_handle_file_test.rb +9 -0
- data/test/recipes/execute_cli_command_test.rb +25 -0
- data/test/utils_test.rb +74 -0
- metadata +23 -4
- data/test/kicker_test.rb +0 -221
data/README.rdoc
CHANGED
@@ -35,4 +35,19 @@ And for fun, ghetto-autotest:
|
|
35
35
|
|
36
36
|
== Installation
|
37
37
|
|
38
|
-
$ sudo gem install alloy-kicker -s http://gems.github.com
|
38
|
+
$ sudo gem install alloy-kicker -s http://gems.github.com
|
39
|
+
|
40
|
+
== TODO
|
41
|
+
|
42
|
+
15:12 sandbags: ideally i would like all events within a small window (e.g. 2s) to be batched into one
|
43
|
+
15:12 sandbags: depending upon whether what is being reported is "file X changed" or "some files in directory X" changed
|
44
|
+
15:12 sandbags: i forget the granularity FSEvents supports
|
45
|
+
15:13 alloy: Yeah the window can be changed, which is a good idea
|
46
|
+
15:13 alloy: FSEvents simply reports changes to files in dir X. nothing more
|
47
|
+
15:14 sandbags: btw.. what is your rationale for using "!" in method names?
|
48
|
+
15:14 alloy: So in this case we should simply keep the time at which an event occurs and then grep the dirs for files with an higher mtime
|
49
|
+
15:14 sandbags: works for me
|
50
|
+
15:16 alloy: Well the rationale in these cases was either it could raise something (validate) or it would run something external. But really it was just for kicks :)
|
51
|
+
15:16 alloy: It could be cleaned up, as I agree it doesn't help much
|
52
|
+
15:17 sandbags: i think it would be easy to grok without them
|
53
|
+
15:17 alloy: Yeah indeed
|
data/Rakefile
CHANGED
data/VERSION.yml
CHANGED
data/bin/kicker
CHANGED
data/lib/kicker.rb
CHANGED
@@ -1,65 +1,53 @@
|
|
1
1
|
$:.unshift File.expand_path('../../vendor', __FILE__)
|
2
2
|
require 'rucola/fsevents'
|
3
|
-
|
4
|
-
require '
|
3
|
+
|
4
|
+
require 'kicker/callback_chain'
|
5
|
+
require 'kicker/growl'
|
6
|
+
require 'kicker/options'
|
7
|
+
require 'kicker/utils'
|
8
|
+
require 'kicker/validate'
|
9
|
+
|
10
|
+
require 'kicker/recipes/could_not_handle_file'
|
11
|
+
require 'kicker/recipes/execute_cli_command'
|
5
12
|
|
6
13
|
class Kicker
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
14
|
+
class << self
|
15
|
+
attr_accessor :latency
|
16
|
+
|
17
|
+
def latency
|
18
|
+
@latency ||= 1.5
|
19
|
+
end
|
20
|
+
|
21
|
+
def paths
|
22
|
+
@paths ||= %w{ . }
|
23
|
+
end
|
24
|
+
|
25
|
+
def run(argv = ARGV)
|
26
|
+
load '.kick' if File.exist?('.kick')
|
27
|
+
new(parse_options(argv)).start
|
22
28
|
end
|
23
29
|
end
|
24
30
|
|
25
|
-
|
26
|
-
argv = argv.dup
|
27
|
-
options = { :growl => true }
|
28
|
-
OPTION_PARSER.call(options).parse!(argv)
|
29
|
-
options[:paths] = argv
|
30
|
-
options
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.run!(argv = ARGV)
|
34
|
-
new(parse_options(argv)).start
|
35
|
-
end
|
36
|
-
|
37
|
-
include Growl
|
38
|
-
GROWL_NOTIFICATIONS = {
|
39
|
-
:change => 'Change occured',
|
40
|
-
:succeeded => 'Command succeeded',
|
41
|
-
:failed => 'Command failed'
|
42
|
-
}
|
43
|
-
GROWL_DEFAULT_CALLBACK = lambda do
|
44
|
-
OSX::NSWorkspace.sharedWorkspace.launchApplication('Terminal')
|
45
|
-
end
|
46
|
-
|
47
|
-
attr_writer :command
|
48
|
-
attr_reader :paths
|
49
|
-
attr_accessor :use_growl, :growl_command
|
31
|
+
attr_reader :latency, :paths, :last_event_processed_at
|
50
32
|
|
51
33
|
def initialize(options)
|
52
|
-
@paths
|
53
|
-
|
34
|
+
@paths = (options[:paths] ? options[:paths] : Kicker.paths).map { |path| File.expand_path(path) }
|
35
|
+
|
36
|
+
@latency = options[:latency] || self.class.latency
|
54
37
|
@use_growl = options[:growl]
|
55
38
|
@growl_command = options[:growl_command]
|
39
|
+
|
40
|
+
finished_processing!
|
41
|
+
end
|
42
|
+
|
43
|
+
def callback_chain
|
44
|
+
self.class.callback_chain
|
56
45
|
end
|
57
46
|
|
58
47
|
def start
|
59
48
|
validate_options!
|
60
49
|
|
61
50
|
log "Watching for changes on: #{@paths.join(', ')}"
|
62
|
-
log "With command: #{command}"
|
63
51
|
log ''
|
64
52
|
|
65
53
|
run_watch_dog!
|
@@ -68,52 +56,11 @@ class Kicker
|
|
68
56
|
OSX.CFRunLoopRun
|
69
57
|
end
|
70
58
|
|
71
|
-
def command
|
72
|
-
"sh -c #{@command.inspect}"
|
73
|
-
end
|
74
|
-
|
75
59
|
private
|
76
60
|
|
77
|
-
def validate_options!
|
78
|
-
validate_paths_and_command!
|
79
|
-
validate_paths_exist!
|
80
|
-
end
|
81
|
-
|
82
|
-
def validate_paths_and_command!
|
83
|
-
if @paths.empty? && @command.nil?
|
84
|
-
puts OPTION_PARSER.call(nil).help
|
85
|
-
exit
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def validate_paths_exist!
|
90
|
-
@paths.each do |path|
|
91
|
-
unless File.exist?(path)
|
92
|
-
puts "The given path `#{path}' does not exist"
|
93
|
-
exit 1
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def log(message)
|
99
|
-
puts "[#{Time.now}] #{message}"
|
100
|
-
end
|
101
|
-
|
102
|
-
def last_command_succeeded?
|
103
|
-
$?.success?
|
104
|
-
end
|
105
|
-
|
106
|
-
def last_command_status
|
107
|
-
$?.to_i
|
108
|
-
end
|
109
|
-
|
110
|
-
def start_growl!
|
111
|
-
Growl::Notifier.sharedInstance.register('Kicker', Kicker::GROWL_NOTIFICATIONS.values)
|
112
|
-
end
|
113
|
-
|
114
61
|
def run_watch_dog!
|
115
62
|
dirs = @paths.map { |path| File.directory?(path) ? path : File.dirname(path) }
|
116
|
-
watch_dog = Rucola::FSEvents.start_watching(
|
63
|
+
watch_dog = Rucola::FSEvents.start_watching(dirs, :latency => @latency) { |events| process(events) }
|
117
64
|
|
118
65
|
trap('INT') do
|
119
66
|
log "Cleaning up…"
|
@@ -122,30 +69,20 @@ class Kicker
|
|
122
69
|
end
|
123
70
|
end
|
124
71
|
|
125
|
-
def
|
126
|
-
|
127
|
-
@paths.each do |path|
|
128
|
-
return execute! if event.last_modified_file =~ /^#{path}/
|
129
|
-
end
|
130
|
-
end
|
72
|
+
def finished_processing!
|
73
|
+
@last_event_processed_at = Time.now
|
131
74
|
end
|
132
75
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
if last_command_succeeded?
|
144
|
-
callback = @growl_command.nil? ? GROWL_DEFAULT_CALLBACK : lambda { system(@growl_command) }
|
145
|
-
growl(GROWL_NOTIFICATIONS[:succeeded], "Kicker: Command succeeded", output, &callback)
|
146
|
-
else
|
147
|
-
growl(GROWL_NOTIFICATIONS[:failed], "Kicker: Command failed (#{last_command_status})", output, &GROWL_DEFAULT_CALLBACK)
|
148
|
-
end
|
76
|
+
def changed_files(events)
|
77
|
+
events.map do |event|
|
78
|
+
event.files.select { |file| File.mtime(file) > @last_event_processed_at }
|
79
|
+
end.flatten
|
80
|
+
end
|
81
|
+
|
82
|
+
def process(events)
|
83
|
+
unless (files = changed_files(events)).empty?
|
84
|
+
callback_chain.run(self, files)
|
85
|
+
finished_processing!
|
149
86
|
end
|
150
87
|
end
|
151
88
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Kicker
|
2
|
+
class CallbackChain < Array
|
3
|
+
alias_method :append_callback, :push
|
4
|
+
alias_method :prepend_callback, :unshift
|
5
|
+
|
6
|
+
def run(kicker, files)
|
7
|
+
each do |callback|
|
8
|
+
files = callback.call(kicker, files)
|
9
|
+
break if !files.is_a?(Array) || files.empty?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.callback_chain
|
15
|
+
@callback_chain ||= CallbackChain.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.callback=(callback)
|
19
|
+
callback_chain.prepend_callback(callback)
|
20
|
+
end
|
21
|
+
end
|
data/lib/kicker/growl.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'growlnotifier/growl_helpers'
|
2
|
+
|
3
|
+
class Kicker
|
4
|
+
include Growl
|
5
|
+
|
6
|
+
attr_accessor :use_growl, :growl_command
|
7
|
+
|
8
|
+
GROWL_NOTIFICATIONS = {
|
9
|
+
:change => 'Change occured',
|
10
|
+
:succeeded => 'Command succeeded',
|
11
|
+
:failed => 'Command failed'
|
12
|
+
}
|
13
|
+
|
14
|
+
GROWL_DEFAULT_CALLBACK = lambda do
|
15
|
+
OSX::NSWorkspace.sharedWorkspace.launchApplication('Terminal')
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def start_growl!
|
21
|
+
Growl::Notifier.sharedInstance.register('Kicker', Kicker::GROWL_NOTIFICATIONS.values)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
class Kicker
|
4
|
+
def self.option_parser
|
5
|
+
@option_parser ||= OptionParser.new do |opt|
|
6
|
+
opt.banner = "Usage: #{$0} [options] [paths to watch]"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
OPTION_PARSER_CALLBACK = lambda do |options|
|
11
|
+
option_parser.on('--[no-]growl', 'Whether or not to use Growl. Default is to use growl.') do |growl|
|
12
|
+
options[:growl] = growl
|
13
|
+
end
|
14
|
+
|
15
|
+
option_parser.on('--growl-command [COMMAND]', 'The command to execute when the Growl succeeded message is clicked.') do |command|
|
16
|
+
options[:growl_command] = command
|
17
|
+
end
|
18
|
+
|
19
|
+
option_parser.on('-l', '--latency [FLOAT]', 'FSEvent grouping latency') do |latency|
|
20
|
+
options[:latency] = Float(latency)
|
21
|
+
end
|
22
|
+
|
23
|
+
option_parser
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.parse_options(argv)
|
27
|
+
argv = argv.dup
|
28
|
+
options = { :growl => true }
|
29
|
+
OPTION_PARSER_CALLBACK.call(options).parse!(argv)
|
30
|
+
options[:paths] = argv unless argv.empty?
|
31
|
+
options
|
32
|
+
end
|
33
|
+
end
|
data/lib/kicker/utils.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
class Kicker
|
2
|
+
def execute_command(command)
|
3
|
+
log "Change occured. Executing command:"
|
4
|
+
growl(GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command') if @use_growl
|
5
|
+
|
6
|
+
output = `#{command}`
|
7
|
+
output.strip.split("\n").each { |line| log " #{line}" }
|
8
|
+
|
9
|
+
log "Command #{last_command_succeeded? ? 'succeeded' : "failed (#{last_command_status})"}"
|
10
|
+
|
11
|
+
if @use_growl
|
12
|
+
if last_command_succeeded?
|
13
|
+
callback = @growl_command.nil? ? GROWL_DEFAULT_CALLBACK : lambda { system(@growl_command) }
|
14
|
+
growl(GROWL_NOTIFICATIONS[:succeeded], "Kicker: Command succeeded", output, &callback)
|
15
|
+
else
|
16
|
+
growl(GROWL_NOTIFICATIONS[:failed], "Kicker: Command failed (#{last_command_status})", output, &GROWL_DEFAULT_CALLBACK)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def log(message)
|
22
|
+
puts "[#{Time.now}] #{message}"
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def last_command_succeeded?
|
28
|
+
$?.success?
|
29
|
+
end
|
30
|
+
|
31
|
+
def last_command_status
|
32
|
+
$?.to_i
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Kicker
|
2
|
+
private
|
3
|
+
|
4
|
+
def validate_options!
|
5
|
+
validate_paths_and_command!
|
6
|
+
validate_paths_exist!
|
7
|
+
end
|
8
|
+
|
9
|
+
def validate_paths_and_command!
|
10
|
+
if callback_chain.length == 1
|
11
|
+
puts OPTION_PARSER_CALLBACK.call(nil).help
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_paths_exist!
|
17
|
+
@paths.each do |path|
|
18
|
+
unless File.exist?(path)
|
19
|
+
puts "The given path `#{path}' does not exist"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Kicker, concerning its callback chain" do
|
4
|
+
it "should return the callback chain instance" do
|
5
|
+
Kicker.callback_chain.should.be.instance_of Kicker::CallbackChain
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should provide a shortcut method which prepends a callback" do
|
9
|
+
Kicker.callback = lambda { :from_callback }
|
10
|
+
Kicker.callback_chain.first.call.should == :from_callback
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be accessible by an instance" do
|
14
|
+
kicker = Kicker.new({})
|
15
|
+
kicker.callback_chain.should.be Kicker.callback_chain
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "Kicker::CallbackChain" do
|
20
|
+
it "should be a subclass of Array" do
|
21
|
+
Kicker::CallbackChain.superclass.should.be Array
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "An instance of Kicker::CallbackChain, concerning it's API" do
|
26
|
+
before do
|
27
|
+
@chain = Kicker::CallbackChain.new
|
28
|
+
|
29
|
+
@callback1 = lambda {}
|
30
|
+
@callback2 = lambda {}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should append a callback" do
|
34
|
+
@chain << @callback1
|
35
|
+
@chain.append_callback(@callback2)
|
36
|
+
|
37
|
+
@chain.should == [@callback1, @callback2]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should prepend a callback" do
|
41
|
+
@chain << @callback1
|
42
|
+
@chain.prepend_callback(@callback2)
|
43
|
+
|
44
|
+
@chain.should == [@callback2, @callback1]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "An instance of Kicker::CallbackChain, when running the chain" do
|
49
|
+
before do
|
50
|
+
@kicker = Kicker.new({})
|
51
|
+
|
52
|
+
@chain = Kicker::CallbackChain.new
|
53
|
+
@result = []
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should call the callbacks from first to last" do
|
57
|
+
@chain.append_callback lambda { @result << 1 }
|
58
|
+
@chain.append_callback lambda { @result << 2 }
|
59
|
+
@chain.run(@kicker, [])
|
60
|
+
@result.should == [1, 2]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should pass in the Kicker instance with each yield" do
|
64
|
+
kicker = nil
|
65
|
+
@chain.append_callback lambda { |x, _| kicker = x }
|
66
|
+
@chain.run(@kicker, [])
|
67
|
+
kicker.should.be @kicker
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should pass the files array given to run to the first callback and pass the result array of that call to the next callback and so on" do
|
71
|
+
@chain.append_callback lambda { |_, files|
|
72
|
+
@result.concat(files)
|
73
|
+
%w{ /file/3 /file/4 }
|
74
|
+
}
|
75
|
+
|
76
|
+
@chain.append_callback lambda { |_, files|
|
77
|
+
@result.concat(files)
|
78
|
+
[]
|
79
|
+
}
|
80
|
+
|
81
|
+
@chain.run(@kicker, %w{ /file/1 /file/2 })
|
82
|
+
@result.should == %w{ /file/1 /file/2 /file/3 /file/4 }
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should halt the callback chain once an empty array is returned from a callback" do
|
86
|
+
@chain.append_callback lambda { @result << 1; [] }
|
87
|
+
@chain.append_callback lambda { @result << 2 }
|
88
|
+
@chain.run(@kicker, %w{ /file/1 /file/2 })
|
89
|
+
@result.should == [1]
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should halt the callback chain if not an Array instance is returned from a callback" do
|
93
|
+
[nil, false, ''].each do |object|
|
94
|
+
@chain.clear
|
95
|
+
@result.clear
|
96
|
+
|
97
|
+
@chain.append_callback lambda { @result << 1; object }
|
98
|
+
@chain.append_callback lambda { @result << 2 }
|
99
|
+
@chain.run(@kicker, %w{ /file/1 /file/2 })
|
100
|
+
@result.should == [1]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Kicker, when a change occurs" do
|
4
|
+
before do
|
5
|
+
Kicker.any_instance.stubs(:last_command_succeeded?).returns(true)
|
6
|
+
Kicker.any_instance.stubs(:log)
|
7
|
+
@kicker = Kicker.new({})
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should store the current time as when the last change occurred" do
|
11
|
+
now = Time.now
|
12
|
+
Time.stubs(:now).returns(now)
|
13
|
+
|
14
|
+
@kicker.send(:finished_processing!)
|
15
|
+
@kicker.last_event_processed_at.should.be now
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return an array of files that have changed since the last event" do
|
19
|
+
file1 = touch('1')
|
20
|
+
file2 = touch('2')
|
21
|
+
file3 = touch('3')
|
22
|
+
file4 = touch('4')
|
23
|
+
@kicker.send(:finished_processing!)
|
24
|
+
|
25
|
+
events = [event(file1, file2), event(file3, file4)]
|
26
|
+
|
27
|
+
@kicker.send(:changed_files, events).should == []
|
28
|
+
@kicker.send(:finished_processing!)
|
29
|
+
|
30
|
+
sleep(1)
|
31
|
+
touch('2')
|
32
|
+
|
33
|
+
@kicker.send(:changed_files, events).should == [file2]
|
34
|
+
@kicker.send(:finished_processing!)
|
35
|
+
|
36
|
+
sleep(1)
|
37
|
+
touch('1')
|
38
|
+
touch('3')
|
39
|
+
|
40
|
+
@kicker.send(:changed_files, events).should == [file1, file3]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should run the callback chain with all changed files" do
|
44
|
+
files = %w{ /file/1 /file/2 }
|
45
|
+
events = [event('/file/1'), event('/file/2')]
|
46
|
+
|
47
|
+
@kicker.expects(:changed_files).with(events).returns(files)
|
48
|
+
@kicker.callback_chain.expects(:run).with(@kicker, files)
|
49
|
+
@kicker.expects(:finished_processing!)
|
50
|
+
|
51
|
+
@kicker.send(:process, events)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not run the callback chain if there were no changed files" do
|
55
|
+
@kicker.stubs(:changed_files).returns([])
|
56
|
+
@kicker.callback_chain.expects(:run).never
|
57
|
+
@kicker.expects(:finished_processing!).never
|
58
|
+
|
59
|
+
@kicker.send(:process, [event()])
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def touch(file)
|
65
|
+
file = "/tmp/kicker_test_tmp_#{file}"
|
66
|
+
`touch #{file}`
|
67
|
+
file
|
68
|
+
end
|
69
|
+
|
70
|
+
def event(*files)
|
71
|
+
event = stub('FSEvent')
|
72
|
+
event.stubs(:files).returns(files)
|
73
|
+
event
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Kicker" do
|
4
|
+
it "should return the default paths to watch" do
|
5
|
+
Kicker.paths.should == %w{ . }
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should check if a .kick file exists and if so load it before running" do
|
9
|
+
Kicker.any_instance.stubs(:start)
|
10
|
+
|
11
|
+
File.expects(:exist?).with('.kick').returns(true)
|
12
|
+
Kicker.expects(:load).with('.kick')
|
13
|
+
Kicker.run
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Kicker, when initializing" do
|
18
|
+
before do
|
19
|
+
@now = Time.now
|
20
|
+
Time.stubs(:now).returns(@now)
|
21
|
+
|
22
|
+
@kicker = Kicker.new(:paths => %w{ /some/dir a/relative/path })
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return the extended paths to watch" do
|
26
|
+
@kicker.paths.should == ['/some/dir', File.expand_path('a/relative/path')]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should have assigned the current time to last_event_processed_at" do
|
30
|
+
@kicker.last_event_processed_at.should == @now
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should use the default paths if no paths were given" do
|
34
|
+
Kicker.new({}).paths.should == [File.expand_path('.')]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should use the default FSEvents latency if none was given" do
|
38
|
+
@kicker.latency.should == 1.5
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should use the given FSEvents latency if one was given" do
|
42
|
+
Kicker.new(:latency => 3.5).latency.should == 3.5
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "Kicker, when starting" do
|
47
|
+
before do
|
48
|
+
@kicker = Kicker.new(:paths => %w{ /some/file.rb })
|
49
|
+
@kicker.stubs(:log)
|
50
|
+
Rucola::FSEvents.stubs(:start_watching)
|
51
|
+
OSX.stubs(:CFRunLoopRun)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should show the usage banner and exit when there is no extra callback defined" do
|
55
|
+
@kicker.stubs(:validate_paths_exist!)
|
56
|
+
Kicker.stubs(:callback_chain).returns([1])
|
57
|
+
|
58
|
+
Kicker::OPTION_PARSER_CALLBACK.stubs(:call).returns(mock('OptionParser', :help => 'help'))
|
59
|
+
@kicker.expects(:puts).with("help")
|
60
|
+
@kicker.expects(:exit)
|
61
|
+
|
62
|
+
@kicker.start
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should warn the user and exit if any of the given paths doesn't exist" do
|
66
|
+
@kicker.stubs(:validate_paths_and_command!)
|
67
|
+
|
68
|
+
@kicker.expects(:puts).with("The given path `/some/file.rb' does not exist")
|
69
|
+
@kicker.expects(:exit).with(1)
|
70
|
+
|
71
|
+
@kicker.start
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should start a FSEvents stream with the assigned latency" do
|
75
|
+
@kicker.stubs(:validate_options!)
|
76
|
+
|
77
|
+
Rucola::FSEvents.expects(:start_watching).with(['/some'], :latency => @kicker.latency)
|
78
|
+
@kicker.start
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should start a FSEvents stream which watches all paths, but the dirnames of paths if they're files" do
|
82
|
+
@kicker.stubs(:validate_options!)
|
83
|
+
File.stubs(:directory?).with('/some/file.rb').returns(false)
|
84
|
+
|
85
|
+
Rucola::FSEvents.expects(:start_watching).with(['/some'], :latency => @kicker.latency)
|
86
|
+
@kicker.start
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should start a FSEvents stream with a block which calls #process with any generated events" do
|
90
|
+
@kicker.stubs(:validate_options!)
|
91
|
+
|
92
|
+
Rucola::FSEvents.expects(:start_watching).yields(['event'])
|
93
|
+
@kicker.expects(:process).with(['event'])
|
94
|
+
|
95
|
+
@kicker.start
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should setup a signal handler for `INT' which stops the FSEvents stream and exits" do
|
99
|
+
@kicker.stubs(:validate_options!)
|
100
|
+
|
101
|
+
watch_dog = stub('Rucola::FSEvents')
|
102
|
+
Rucola::FSEvents.stubs(:start_watching).returns(watch_dog)
|
103
|
+
|
104
|
+
@kicker.expects(:trap).with('INT').yields
|
105
|
+
watch_dog.expects(:stop)
|
106
|
+
@kicker.expects(:exit)
|
107
|
+
|
108
|
+
@kicker.start
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should start a CFRunLoop" do
|
112
|
+
@kicker.stubs(:validate_options!)
|
113
|
+
|
114
|
+
OSX.expects(:CFRunLoopRun)
|
115
|
+
@kicker.start
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should register with growl if growl should be used" do
|
119
|
+
@kicker.stubs(:validate_options!)
|
120
|
+
@kicker.use_growl = true
|
121
|
+
|
122
|
+
Growl::Notifier.sharedInstance.expects(:register).with('Kicker', Kicker::GROWL_NOTIFICATIONS.values)
|
123
|
+
@kicker.start
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should _not_ register with growl if growl should not be used" do
|
127
|
+
@kicker.stubs(:validate_options!)
|
128
|
+
@kicker.use_growl = false
|
129
|
+
|
130
|
+
Growl::Notifier.sharedInstance.expects(:register).never
|
131
|
+
@kicker.start
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Kicker.parse_options" do
|
4
|
+
it "should parse the paths" do
|
5
|
+
Kicker.parse_options([])[:paths].should.be nil
|
6
|
+
|
7
|
+
Kicker.parse_options(%w{ /some/file.rb })[:paths].should == %w{ /some/file.rb }
|
8
|
+
Kicker.parse_options(%w{ /some/file.rb /a/dir /and/some/other/file.rb })[:paths].should ==
|
9
|
+
%w{ /some/file.rb /a/dir /and/some/other/file.rb }
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should parse if growl shouldn't be used" do
|
13
|
+
Kicker.parse_options([])[:growl].should == true
|
14
|
+
Kicker.parse_options(%w{ --no-growl })[:growl].should == false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should parse the Growl command to use when the user clicks the Growl succeeded message" do
|
18
|
+
Kicker.parse_options(%w{ --growl-command ls })[:growl_command].should == 'ls'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should parse the latency to pass to FSEvents" do
|
22
|
+
Kicker.parse_options(%w{ -l 2.5 })[:latency].should == 2.5
|
23
|
+
Kicker.parse_options(%w{ --latency 3.5 })[:latency].should == 3.5
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Kicker, concerning the default `could not handle file' callback" do
|
4
|
+
it "should log that it could not handle the given files" do
|
5
|
+
kicker = Kicker.new({})
|
6
|
+
kicker.expects(:log).with("Could not handle: /file/1, /file/2")
|
7
|
+
Kicker.callback_chain.last.call(kicker, %w{ /file/1 /file/2 })
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Kicker, concerning the `execute a command-line' callback" do
|
4
|
+
it "should parse the command and add the callback" do
|
5
|
+
before = Kicker.callback_chain.length
|
6
|
+
|
7
|
+
Kicker.parse_options(%w{ -e ls })
|
8
|
+
Kicker.callback_chain.length.should == before + 1
|
9
|
+
|
10
|
+
Kicker.parse_options(%w{ --execute ls })
|
11
|
+
Kicker.callback_chain.length.should == before + 2
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should call execute_command with the given command" do
|
15
|
+
Kicker.parse_options(%w{ -e ls })
|
16
|
+
|
17
|
+
callback = Kicker.callback_chain.first
|
18
|
+
callback.should.be.instance_of Proc
|
19
|
+
|
20
|
+
kicker = Kicker.new({})
|
21
|
+
kicker.expects(:execute_command).with('sh -c "ls"')
|
22
|
+
|
23
|
+
callback.call(kicker, %w{ /file/1 /file/2 }).should.not.be.instance_of Array
|
24
|
+
end
|
25
|
+
end
|
data/test/utils_test.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "A Kicker instance, concerning its utility methods" do
|
4
|
+
before do
|
5
|
+
Kicker.any_instance.stubs(:last_command_succeeded?).returns(true)
|
6
|
+
@kicker = Kicker.new(:paths => %w{ /some/dir }, :command => 'ls -l')
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should print a log entry with timestamp" do
|
10
|
+
now = Time.now
|
11
|
+
Time.stubs(:now).returns(now)
|
12
|
+
|
13
|
+
@kicker.expects(:puts).with("[#{now}] the message")
|
14
|
+
@kicker.send(:log, 'the message')
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should log the output of the command indented by 2 spaces and whether or not the command succeeded" do
|
18
|
+
@kicker.stubs(:`).returns("line 1\nline 2")
|
19
|
+
|
20
|
+
@kicker.expects(:log).with('Change occured. Executing command:')
|
21
|
+
@kicker.expects(:log).with(' line 1')
|
22
|
+
@kicker.expects(:log).with(' line 2')
|
23
|
+
@kicker.expects(:log).with('Command succeeded')
|
24
|
+
@kicker.execute_command('')
|
25
|
+
|
26
|
+
@kicker.stubs(:last_command_succeeded?).returns(false)
|
27
|
+
@kicker.stubs(:last_command_status).returns(123)
|
28
|
+
@kicker.expects(:log).with('Change occured. Executing command:')
|
29
|
+
@kicker.expects(:log).with(' line 1')
|
30
|
+
@kicker.expects(:log).with(' line 2')
|
31
|
+
@kicker.expects(:log).with('Command failed (123)')
|
32
|
+
@kicker.execute_command('')
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should send the Growl messages with the default click callback" do
|
36
|
+
@kicker.stubs(:log)
|
37
|
+
|
38
|
+
@kicker.stubs(:`).returns("line 1\nline 2")
|
39
|
+
@kicker.use_growl = true
|
40
|
+
|
41
|
+
OSX::NSWorkspace.sharedWorkspace.expects(:launchApplication).with('Terminal').times(2)
|
42
|
+
|
43
|
+
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command')
|
44
|
+
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:succeeded], 'Kicker: Command succeeded', "line 1\nline 2").yields
|
45
|
+
@kicker.execute_command('')
|
46
|
+
|
47
|
+
@kicker.stubs(:last_command_succeeded?).returns(false)
|
48
|
+
@kicker.stubs(:last_command_status).returns(123)
|
49
|
+
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command')
|
50
|
+
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:failed], 'Kicker: Command failed (123)', "line 1\nline 2").yields
|
51
|
+
@kicker.execute_command('')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should send the Growl messages with a click callback which executes the specified growl command when succeeded" do
|
55
|
+
@kicker.stubs(:log)
|
56
|
+
|
57
|
+
@kicker.stubs(:`).returns("line 1\nline 2")
|
58
|
+
@kicker.use_growl = true
|
59
|
+
@kicker.growl_command = 'ls -l'
|
60
|
+
|
61
|
+
@kicker.expects(:system).with('ls -l').times(1)
|
62
|
+
OSX::NSWorkspace.sharedWorkspace.expects(:launchApplication).with('Terminal').times(1)
|
63
|
+
|
64
|
+
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command')
|
65
|
+
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:succeeded], 'Kicker: Command succeeded', "line 1\nline 2").yields
|
66
|
+
@kicker.execute_command('')
|
67
|
+
|
68
|
+
@kicker.stubs(:last_command_succeeded?).returns(false)
|
69
|
+
@kicker.stubs(:last_command_status).returns(123)
|
70
|
+
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command')
|
71
|
+
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:failed], 'Kicker: Command failed (123)', "line 1\nline 2").yields
|
72
|
+
@kicker.execute_command('')
|
73
|
+
end
|
74
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alloy-kicker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eloy Duran
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-25 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -30,8 +30,21 @@ files:
|
|
30
30
|
- VERSION.yml
|
31
31
|
- bin/kicker
|
32
32
|
- lib/kicker.rb
|
33
|
-
-
|
33
|
+
- lib/kicker/callback_chain.rb
|
34
|
+
- lib/kicker/growl.rb
|
35
|
+
- lib/kicker/options.rb
|
36
|
+
- lib/kicker/recipes/could_not_handle_file.rb
|
37
|
+
- lib/kicker/recipes/execute_cli_command.rb
|
38
|
+
- lib/kicker/utils.rb
|
39
|
+
- lib/kicker/validate.rb
|
40
|
+
- test/callback_chain_test.rb
|
41
|
+
- test/filesystem_change_test.rb
|
42
|
+
- test/initialization_test.rb
|
43
|
+
- test/options_test.rb
|
44
|
+
- test/recipes/could_not_handle_file_test.rb
|
45
|
+
- test/recipes/execute_cli_command_test.rb
|
34
46
|
- test/test_helper.rb
|
47
|
+
- test/utils_test.rb
|
35
48
|
- vendor/growlnotifier/growl.rb
|
36
49
|
- vendor/growlnotifier/growl_helpers.rb
|
37
50
|
- vendor/rucola/fsevents.rb
|
@@ -63,5 +76,11 @@ signing_key:
|
|
63
76
|
specification_version: 2
|
64
77
|
summary: A simple OS X CLI tool which uses FSEvents to run a given shell command.
|
65
78
|
test_files:
|
66
|
-
- test/
|
79
|
+
- test/callback_chain_test.rb
|
80
|
+
- test/filesystem_change_test.rb
|
81
|
+
- test/initialization_test.rb
|
82
|
+
- test/options_test.rb
|
83
|
+
- test/recipes/could_not_handle_file_test.rb
|
84
|
+
- test/recipes/execute_cli_command_test.rb
|
67
85
|
- test/test_helper.rb
|
86
|
+
- test/utils_test.rb
|
data/test/kicker_test.rb
DELETED
@@ -1,221 +0,0 @@
|
|
1
|
-
require File.expand_path('../test_helper', __FILE__)
|
2
|
-
|
3
|
-
describe "Kicker.parse_options" do
|
4
|
-
it "should parse the paths" do
|
5
|
-
Kicker.parse_options(%w{ /some/file.rb })[:paths].should == %w{ /some/file.rb }
|
6
|
-
Kicker.parse_options(%w{ /some/file.rb /a/dir /and/some/other/file.rb })[:paths].should ==
|
7
|
-
%w{ /some/file.rb /a/dir /and/some/other/file.rb }
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should parse the command" do
|
11
|
-
Kicker.parse_options(%w{ -e ls })[:command].should == 'ls'
|
12
|
-
Kicker.parse_options(%w{ --execute ls })[:command].should == 'ls'
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should parse if growl shouldn't be used" do
|
16
|
-
Kicker.parse_options([])[:growl].should == true
|
17
|
-
Kicker.parse_options(%w{ --no-growl })[:growl].should == false
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should parse the Growl command to use when the user clicks the Growl succeeded message" do
|
21
|
-
Kicker.parse_options(%w{ --growl-command ls })[:growl_command].should == 'ls'
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe "Kicker, when initializing" do
|
26
|
-
before do
|
27
|
-
@kicker = Kicker.new(:paths => %w{ /some/dir a/relative/path }, :command => 'ls -l')
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should return the extended paths to watch" do
|
31
|
-
@kicker.paths.should == ['/some/dir', File.expand_path('a/relative/path')]
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should return the command to execute once a change occurs" do
|
35
|
-
@kicker.command.should == 'sh -c "ls -l"'
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe "Kicker, when starting" do
|
40
|
-
before do
|
41
|
-
@kicker = Kicker.new(:paths => %w{ /some/file.rb }, :command => 'ls -l')
|
42
|
-
@kicker.stubs(:log)
|
43
|
-
Rucola::FSEvents.stubs(:start_watching)
|
44
|
-
OSX.stubs(:CFRunLoopRun)
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should show the usage banner and exit when there are no paths and a command" do
|
48
|
-
@kicker.instance_variable_set("@paths", [])
|
49
|
-
@kicker.command = nil
|
50
|
-
@kicker.stubs(:validate_paths_exist!)
|
51
|
-
|
52
|
-
Kicker::OPTION_PARSER.stubs(:call).returns(mock('OptionParser', :help => 'help'))
|
53
|
-
@kicker.expects(:puts).with("help")
|
54
|
-
@kicker.expects(:exit)
|
55
|
-
|
56
|
-
@kicker.start
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should warn the user and exit if any of the given paths doesn't exist" do
|
60
|
-
@kicker.expects(:puts).with("The given path `/some/file.rb' does not exist")
|
61
|
-
@kicker.expects(:exit).with(1)
|
62
|
-
|
63
|
-
@kicker.start
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should start a FSEvents stream which watches all paths, but the dirnames of paths if they're files" do
|
67
|
-
@kicker.stubs(:validate_options!)
|
68
|
-
File.stubs(:directory?).with('/some/file.rb').returns(false)
|
69
|
-
|
70
|
-
Rucola::FSEvents.expects(:start_watching).with('/some')
|
71
|
-
@kicker.start
|
72
|
-
end
|
73
|
-
|
74
|
-
it "should start a FSEvents stream with a block which calls #process with any generated events" do
|
75
|
-
@kicker.stubs(:validate_options!)
|
76
|
-
|
77
|
-
Rucola::FSEvents.expects(:start_watching).yields(['event'])
|
78
|
-
@kicker.expects(:process).with(['event'])
|
79
|
-
|
80
|
-
@kicker.start
|
81
|
-
end
|
82
|
-
|
83
|
-
it "should setup a signal handler for `INT' which stops the FSEvents stream and exits" do
|
84
|
-
@kicker.stubs(:validate_options!)
|
85
|
-
|
86
|
-
watch_dog = stub('Rucola::FSEvents')
|
87
|
-
Rucola::FSEvents.stubs(:start_watching).returns(watch_dog)
|
88
|
-
|
89
|
-
@kicker.expects(:trap).with('INT').yields
|
90
|
-
watch_dog.expects(:stop)
|
91
|
-
@kicker.expects(:exit)
|
92
|
-
|
93
|
-
@kicker.start
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should start a CFRunLoop" do
|
97
|
-
@kicker.stubs(:validate_options!)
|
98
|
-
|
99
|
-
OSX.expects(:CFRunLoopRun)
|
100
|
-
@kicker.start
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should register with growl if growl should be used" do
|
104
|
-
@kicker.stubs(:validate_options!)
|
105
|
-
@kicker.use_growl = true
|
106
|
-
|
107
|
-
Growl::Notifier.sharedInstance.expects(:register).with('Kicker', Kicker::GROWL_NOTIFICATIONS.values)
|
108
|
-
@kicker.start
|
109
|
-
end
|
110
|
-
|
111
|
-
it "should _not_ register with growl if growl should not be used" do
|
112
|
-
@kicker.stubs(:validate_options!)
|
113
|
-
@kicker.use_growl = false
|
114
|
-
|
115
|
-
Growl::Notifier.sharedInstance.expects(:register).never
|
116
|
-
@kicker.start
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
describe "Kicker, when a change occurs" do
|
121
|
-
before do
|
122
|
-
Kicker.any_instance.stubs(:last_command_succeeded?).returns(true)
|
123
|
-
Kicker.any_instance.stubs(:log)
|
124
|
-
@kicker = Kicker.new(:paths => %w{ /some/file.rb /some/dir }, :command => 'ls -l')
|
125
|
-
end
|
126
|
-
|
127
|
-
it "should execute the command if a change occured to a watched path which is a file" do
|
128
|
-
event = stub('Event', :last_modified_file => '/some/file.rb')
|
129
|
-
|
130
|
-
@kicker.expects(:`).with(@kicker.command).returns('')
|
131
|
-
@kicker.send(:process, [event])
|
132
|
-
end
|
133
|
-
|
134
|
-
it "should execute the command if a change occured to some file in watched path which is a directory" do
|
135
|
-
event = stub('Event', :last_modified_file => '/some/dir/with/file.rb')
|
136
|
-
|
137
|
-
@kicker.expects(:`).with(@kicker.command).returns('')
|
138
|
-
@kicker.send(:process, [event])
|
139
|
-
end
|
140
|
-
|
141
|
-
it "should _not_ execute the command if a change occured to a file that isn't being watched" do
|
142
|
-
event1 = stub('Event', :last_modified_file => '/some/other_file.rb')
|
143
|
-
event2 = stub('Event', :last_modified_file => '/some/not/watched/dir/with/file.rb')
|
144
|
-
|
145
|
-
@kicker.expects(:`).never
|
146
|
-
@kicker.send(:process, [event1, event2])
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
describe "Kicker, in general" do
|
151
|
-
before do
|
152
|
-
Kicker.any_instance.stubs(:last_command_succeeded?).returns(true)
|
153
|
-
@kicker = Kicker.new(:paths => %w{ /some/dir }, :command => 'ls -l')
|
154
|
-
end
|
155
|
-
|
156
|
-
it "should print a log entry with timestamp" do
|
157
|
-
now = Time.now
|
158
|
-
Time.stubs(:now).returns(now)
|
159
|
-
|
160
|
-
@kicker.expects(:puts).with("[#{now}] the message")
|
161
|
-
@kicker.send(:log, 'the message')
|
162
|
-
end
|
163
|
-
|
164
|
-
it "should log the output of the command indented by 2 spaces and whether or not the command succeeded" do
|
165
|
-
@kicker.stubs(:`).returns("line 1\nline 2")
|
166
|
-
|
167
|
-
@kicker.expects(:log).with('Change occured. Executing command:')
|
168
|
-
@kicker.expects(:log).with(' line 1')
|
169
|
-
@kicker.expects(:log).with(' line 2')
|
170
|
-
@kicker.expects(:log).with('Command succeeded')
|
171
|
-
@kicker.send(:execute!)
|
172
|
-
|
173
|
-
@kicker.stubs(:last_command_succeeded?).returns(false)
|
174
|
-
@kicker.stubs(:last_command_status).returns(123)
|
175
|
-
@kicker.expects(:log).with('Change occured. Executing command:')
|
176
|
-
@kicker.expects(:log).with(' line 1')
|
177
|
-
@kicker.expects(:log).with(' line 2')
|
178
|
-
@kicker.expects(:log).with('Command failed (123)')
|
179
|
-
@kicker.send(:execute!)
|
180
|
-
end
|
181
|
-
|
182
|
-
it "should send the Growl messages with the default click callback" do
|
183
|
-
@kicker.stubs(:log)
|
184
|
-
|
185
|
-
@kicker.stubs(:`).returns("line 1\nline 2")
|
186
|
-
@kicker.use_growl = true
|
187
|
-
|
188
|
-
OSX::NSWorkspace.sharedWorkspace.expects(:launchApplication).with('Terminal').times(2)
|
189
|
-
|
190
|
-
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command')
|
191
|
-
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:succeeded], 'Kicker: Command succeeded', "line 1\nline 2").yields
|
192
|
-
@kicker.send(:execute!)
|
193
|
-
|
194
|
-
@kicker.stubs(:last_command_succeeded?).returns(false)
|
195
|
-
@kicker.stubs(:last_command_status).returns(123)
|
196
|
-
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command')
|
197
|
-
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:failed], 'Kicker: Command failed (123)', "line 1\nline 2").yields
|
198
|
-
@kicker.send(:execute!)
|
199
|
-
end
|
200
|
-
|
201
|
-
it "should send the Growl messages with a click callback which executes the specified growl command when succeeded" do
|
202
|
-
@kicker.stubs(:log)
|
203
|
-
|
204
|
-
@kicker.stubs(:`).returns("line 1\nline 2")
|
205
|
-
@kicker.use_growl = true
|
206
|
-
@kicker.growl_command = 'ls -l'
|
207
|
-
|
208
|
-
@kicker.expects(:system).with('ls -l').times(1)
|
209
|
-
OSX::NSWorkspace.sharedWorkspace.expects(:launchApplication).with('Terminal').times(1)
|
210
|
-
|
211
|
-
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command')
|
212
|
-
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:succeeded], 'Kicker: Command succeeded', "line 1\nline 2").yields
|
213
|
-
@kicker.send(:execute!)
|
214
|
-
|
215
|
-
@kicker.stubs(:last_command_succeeded?).returns(false)
|
216
|
-
@kicker.stubs(:last_command_status).returns(123)
|
217
|
-
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:change], 'Kicker: Change occured', 'Executing command')
|
218
|
-
@kicker.expects(:growl).with(Kicker::GROWL_NOTIFICATIONS[:failed], 'Kicker: Command failed (123)', "line 1\nline 2").yields
|
219
|
-
@kicker.send(:execute!)
|
220
|
-
end
|
221
|
-
end
|