alloy-kicker 1.1.2 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|