kicker 3.0.0 → 4.0.0.p1
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.
- checksums.yaml +7 -0
- data/COPYING +20 -0
- data/README.rdoc +0 -150
- data/bin/kicker +1 -3
- data/lib/kicker.rb +16 -117
- data/lib/kicker/cli.rb +130 -0
- data/lib/kicker/core_ext/array.rb +40 -0
- data/lib/kicker/debug.rb +5 -0
- data/lib/kicker/deprecated.rb +14 -0
- data/lib/kicker/formatter.rb +15 -0
- data/lib/kicker/option_parser.rb +37 -0
- data/lib/kicker/recipe/ignore.rb +2 -0
- data/lib/kicker/recipe/peck.rb +54 -0
- data/lib/kicker/recipe/reload.rb +0 -0
- data/lib/kicker/{recipes → recipe}/ruby.rb +10 -10
- data/lib/kicker/script.rb +77 -0
- data/lib/kicker/version.rb +2 -2
- data/lib/kicker/watcher.rb +113 -0
- metadata +32 -120
- data/LICENSE +0 -54
- data/lib/kicker/callback_chain.rb +0 -95
- data/lib/kicker/core_ext.rb +0 -38
- data/lib/kicker/fsevents.rb +0 -36
- data/lib/kicker/job.rb +0 -57
- data/lib/kicker/notification.rb +0 -31
- data/lib/kicker/options.rb +0 -96
- data/lib/kicker/recipes.rb +0 -98
- data/lib/kicker/recipes/could_not_handle_file.rb +0 -7
- data/lib/kicker/recipes/dot_kick.rb +0 -47
- data/lib/kicker/recipes/execute_cli_command.rb +0 -9
- data/lib/kicker/recipes/ignore.rb +0 -41
- data/lib/kicker/recipes/jstest.rb +0 -10
- data/lib/kicker/recipes/rails.rb +0 -109
- data/lib/kicker/utils.rb +0 -127
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b3f1b8e56a45f76314daaf713f764f37228d42b4
|
4
|
+
data.tar.gz: 4867e2dbf6f21d39ecd0f7367c6d87bb0b94a9d7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1ed6e797ccff80a9a4cbd9d056ac6ae205907fef59c94b72c61c811576caa678df63b82eb043b657fe08e48438b24e5ea8e49eee62839cbc66ca5a97b2eecf2f
|
7
|
+
data.tar.gz: f23d431352c3eea377adee626ae6a76001151585e3a2a50d5f6203a2426a68fd79ebe65eff3781969bafa5ba4c6b351b9ecf033ef7ee9990c2f0a9f9f1b942df
|
data/COPYING
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c)
|
2
|
+
Eloy Duran <eloy.de.enige@gmail.com>
|
3
|
+
Manfred Stienstra, Fingertips <manfred@fngtps.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -1,150 +0,0 @@
|
|
1
|
-
= Kicker
|
2
|
-
|
3
|
-
{<img src="https://secure.travis-ci.org/alloy/kicker.png" />}[http://travis-ci.org/alloy/kicker]
|
4
|
-
|
5
|
-
A lean, agnostic, flexible file-change watcher.
|
6
|
-
|
7
|
-
== Installation
|
8
|
-
|
9
|
-
$ gem install kicker -s http://gemcutter.org
|
10
|
-
|
11
|
-
== The short version
|
12
|
-
|
13
|
-
Usage: ./bin/kicker [options] [paths to watch]
|
14
|
-
|
15
|
-
Available recipes: ignore, jstest, rails, ruby.
|
16
|
-
|
17
|
-
-s, --silent Keep output to a minimum.
|
18
|
-
-q, --quiet Quiet output. Don't print timestamps when logging.
|
19
|
-
-c, --clear Clear console before each run.
|
20
|
-
-l, --latency [FLOAT] The time to collect file change events before acting on them. Defaults to 1 second.
|
21
|
-
-r, --recipe [NAME] A named recipe to load.
|
22
|
-
-e, --execute [COMMAND] The command to execute.
|
23
|
-
-b, --ruby [PATH] Use an alternate Ruby binary for spawned test runners. (Default is `ruby')
|
24
|
-
|
25
|
-
|
26
|
-
== The long version
|
27
|
-
|
28
|
-
=== Execute a shell command
|
29
|
-
|
30
|
-
Show all files, whenever a change occurs in the current work directory:
|
31
|
-
|
32
|
-
$ kicker -e "ls -l" .
|
33
|
-
|
34
|
-
Show all files, whenever a change occurs to a specific file:
|
35
|
-
|
36
|
-
$ kicker -e "ls -l" foo.txt
|
37
|
-
|
38
|
-
Or use it as a ghetto-autotest, running tests whenever files change:
|
39
|
-
|
40
|
-
$ kicker -e "ruby test/test_case.rb" test/test_case.rb lib/file.rb
|
41
|
-
|
42
|
-
Et cetera.
|
43
|
-
|
44
|
-
=== Using recipes
|
45
|
-
|
46
|
-
A recipe is a predefined handler. You can use as many as you like, by
|
47
|
-
specifying them with the <tt>--recipe</tt> (<tt>-r</tt>) option.
|
48
|
-
|
49
|
-
For instance, when in the root of a typical Ruby on Rails application, using
|
50
|
-
the <tt>rails</tt> recipe will map models, concerns, controllers, helpers, and
|
51
|
-
views to their respective test files. These will then all be ran with Ruby.
|
52
|
-
|
53
|
-
A few recipes come shipped with Kicker:
|
54
|
-
* Typical Ruby library.
|
55
|
-
* Ruby on Rails, as aforementioned.
|
56
|
-
* JavaScript tests, to run it needs
|
57
|
-
HeadlessSquirrel[http://github.com/Fingertips/Headless-squirrel].
|
58
|
-
* Ignore, ignores logs, tmp, and svn and git files.
|
59
|
-
|
60
|
-
Add your own shared recipes to <tt>~/.kick</tt> folder or
|
61
|
-
current working directory <tt>.kick</tt>.
|
62
|
-
|
63
|
-
=== Project specific handlers
|
64
|
-
|
65
|
-
Most of the time, you’ll want to create handlers specific to the project at
|
66
|
-
hand. This can be done by adding your handlers to a <tt>.kick</tt> file and
|
67
|
-
running Kicker from the directory containing it.
|
68
|
-
|
69
|
-
This file is reloaded once saved. No need to stop Kicker.
|
70
|
-
|
71
|
-
== Writing handlers
|
72
|
-
|
73
|
-
Whenever file-change events occur, Kicker will go through a chain of handlers
|
74
|
-
until that the files list is empty, or the end of the chain is reached.
|
75
|
-
|
76
|
-
Handlers are objects that respond to <tt>#call</tt>. These are typically Proc
|
77
|
-
objects. (If you know Rack, you’re familiar with this concept.) Every handler
|
78
|
-
gets passed a list of changed files and can decide whether or not to act on
|
79
|
-
them. Normally when handling a file, you should remove it from the files list,
|
80
|
-
unless you want to let the file fall through to another handler. In the same
|
81
|
-
way, one can add files to handler to the files list.
|
82
|
-
|
83
|
-
==== Time for a simple example
|
84
|
-
|
85
|
-
process do |files|
|
86
|
-
execute("rake docs:generate && open -a Safari html/index.html") if files.delete("README.rdoc")
|
87
|
-
end
|
88
|
-
|
89
|
-
A handler is defined by passing a block to <tt>process</tt>. Which is one of
|
90
|
-
three possible callback chains to add your handlers to, the others being:
|
91
|
-
<tt>pre_process</tt> and <tt>post_process</tt>. See Kernel for more info.
|
92
|
-
|
93
|
-
Then <tt>README.rdoc</tt> is deleted from the files array. If it did exist in
|
94
|
-
the array and was deleted, a shell command is executed which runs a rake task
|
95
|
-
to generate rdoc and open the docs with Safari.
|
96
|
-
|
97
|
-
==== Something more elaborate.
|
98
|
-
|
99
|
-
Consider a Rails application with a mailer. Since the naming convention of
|
100
|
-
mailer views tend to be fairly application specific, a specific handler has to
|
101
|
-
be added:
|
102
|
-
|
103
|
-
process do |files|
|
104
|
-
test_files = files.take_and_map do |file|
|
105
|
-
if path =~ %r{^app/views/mailer/\w+\.erb$}
|
106
|
-
'test/unit/mailer_test.rb'
|
107
|
-
|
108
|
-
# elsif ... handle more app specific stuff
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
Ruby.run_tests test_files
|
113
|
-
end
|
114
|
-
|
115
|
-
The files list is iterated over with the Array#take_and_map method, which both
|
116
|
-
removes and maps the results. This is an easy way to do a common thing in
|
117
|
-
recipes. See Kicker::ArrayExt for details.
|
118
|
-
|
119
|
-
The handler then checks if the file is a mailer view and if so runs the
|
120
|
-
mailers test case. Ruby.run_tests runs them with something like the following
|
121
|
-
command:
|
122
|
-
|
123
|
-
execute "ruby -r #{test_files.join(' -r ')} -e ''" unless test_files.empty?
|
124
|
-
|
125
|
-
See Kernel for more info on the utility methods.
|
126
|
-
|
127
|
-
To load recipes from your <tt>~/.kick</tt> file:
|
128
|
-
|
129
|
-
recipe :ignore
|
130
|
-
ignore(/^data\//)
|
131
|
-
|
132
|
-
That’s basically it, just remember that the order of specifying handlers _can_
|
133
|
-
be important in your decision on where to specify handlers.
|
134
|
-
|
135
|
-
== Notifiers
|
136
|
-
|
137
|
-
For platform specific notifications we use the notify gem. For supported
|
138
|
-
backends see: https://github.com/jugyo/notify#feature.
|
139
|
-
|
140
|
-
You select the notify backend by setting the NOTIFY environment variable.
|
141
|
-
|
142
|
-
gem install terminal-notifier
|
143
|
-
env NOTIFY=terminal-notifier kicker
|
144
|
-
|
145
|
-
== Contributors
|
146
|
-
|
147
|
-
* Manfred Stienstra (@manfred)
|
148
|
-
* Cristi Balan (@evilchelu)
|
149
|
-
* Damir Zekic (@sidonath)
|
150
|
-
* Adam Keys (@therealadam)
|
data/bin/kicker
CHANGED
data/lib/kicker.rb
CHANGED
@@ -1,123 +1,22 @@
|
|
1
|
-
require '
|
2
|
-
require 'kicker/
|
3
|
-
require 'kicker/callback_chain'
|
4
|
-
require 'kicker/core_ext'
|
5
|
-
require 'kicker/job'
|
6
|
-
require 'kicker/notification'
|
7
|
-
require 'kicker/options'
|
8
|
-
require 'kicker/utils'
|
9
|
-
require 'kicker/recipes'
|
1
|
+
require 'tidings'
|
2
|
+
require 'kicker/core_ext/array'
|
10
3
|
|
11
|
-
class Kicker
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
def initialize
|
20
|
-
finished_processing!
|
21
|
-
end
|
22
|
-
|
23
|
-
def paths
|
24
|
-
@paths ||= Kicker.paths.map { |path| File.expand_path(path) }
|
25
|
-
end
|
26
|
-
|
27
|
-
def start
|
28
|
-
validate_options!
|
29
|
-
|
30
|
-
log "Watching for changes on: #{paths.join(', ')}"
|
31
|
-
log ''
|
32
|
-
|
33
|
-
run_startup_chain
|
34
|
-
run_watch_dog!
|
35
|
-
|
36
|
-
self
|
37
|
-
end
|
38
|
-
|
39
|
-
def loop!
|
40
|
-
(Thread.list - [Thread.current, Thread.main]).each(&:join)
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def validate_options!
|
46
|
-
validate_paths_and_command!
|
47
|
-
validate_paths_exist!
|
48
|
-
end
|
4
|
+
class Kicker
|
5
|
+
autoload :CLI, 'kicker/cli'
|
6
|
+
autoload :Deprecated, 'kicker/deprecated'
|
7
|
+
autoload :Formatter, 'kicker/formatter'
|
8
|
+
autoload :OptionParser, 'kicker/option_parser'
|
9
|
+
autoload :Script, 'kicker/script'
|
10
|
+
autoload :VERSION, 'kicker/version'
|
11
|
+
autoload :Watcher, 'kicker/watcher'
|
49
12
|
|
50
|
-
|
51
|
-
if startup_chain.empty? && process_chain.empty? && pre_process_chain.empty?
|
52
|
-
puts Kicker::Options.parser.help
|
53
|
-
exit
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def validate_paths_exist!
|
58
|
-
paths.each do |path|
|
59
|
-
unless File.exist?(path)
|
60
|
-
puts "The given path `#{path}' does not exist"
|
61
|
-
exit 1
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def run_watch_dog!
|
67
|
-
dirs = @paths.map { |path| File.directory?(path) ? path : File.dirname(path) }
|
68
|
-
watch_dog = Kicker::FSEvents.start_watching(dirs, :latency => self.class.latency) do |events|
|
69
|
-
process events
|
70
|
-
end
|
71
|
-
trap('INT') do
|
72
|
-
log "Exiting ..."
|
73
|
-
watch_dog.stop
|
74
|
-
exit
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def run_startup_chain
|
79
|
-
startup_chain.call([], false)
|
80
|
-
end
|
81
|
-
|
82
|
-
def finished_processing!
|
83
|
-
@last_event_processed_at = Time.now
|
84
|
-
end
|
85
|
-
|
86
|
-
def process(events)
|
87
|
-
unless (files = changed_files(events)).empty?
|
88
|
-
Utils.should_clear_screen = true
|
89
|
-
full_chain.call(files)
|
90
|
-
finished_processing!
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def changed_files(events)
|
95
|
-
make_paths_relative(events.map do |event|
|
96
|
-
files_in_directory(event.path).select { |file| file_changed_since_last_event? file }
|
97
|
-
end.flatten.uniq.sort)
|
98
|
-
end
|
99
|
-
|
100
|
-
def files_in_directory(dir)
|
101
|
-
Dir.entries(dir).sort[2..-1].map { |f| File.join(dir, f) }
|
102
|
-
rescue Errno::ENOENT
|
103
|
-
[]
|
104
|
-
end
|
13
|
+
extend Kicker::Formatter
|
105
14
|
|
106
|
-
def
|
107
|
-
|
108
|
-
rescue Errno::ENOENT
|
109
|
-
false
|
15
|
+
def self.debug(*)
|
16
|
+
# By default we ignore all debugging information
|
110
17
|
end
|
111
18
|
|
112
|
-
def
|
113
|
-
|
114
|
-
wd = Dir.pwd
|
115
|
-
files.map do |file|
|
116
|
-
if file[0..wd.length-1] == wd
|
117
|
-
file[wd.length+1..-1]
|
118
|
-
else
|
119
|
-
file
|
120
|
-
end
|
121
|
-
end
|
19
|
+
def self.version
|
20
|
+
Kicker::VERSION
|
122
21
|
end
|
123
|
-
end
|
22
|
+
end
|
data/lib/kicker/cli.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
class Kicker
|
2
|
+
class CLI
|
3
|
+
def initialize(argv)
|
4
|
+
@options, @argv = Kicker::OptionParser.parse(argv)
|
5
|
+
end
|
6
|
+
|
7
|
+
def switches
|
8
|
+
@options.map(&:first)
|
9
|
+
end
|
10
|
+
|
11
|
+
def any_switch?(*test)
|
12
|
+
!(switches & test).empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def option_value(*switches)
|
16
|
+
@options.each do |key, value|
|
17
|
+
if switches.include?(key)
|
18
|
+
return value
|
19
|
+
end
|
20
|
+
end; nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def osx?
|
24
|
+
RUBY_PLATFORM.downcase.include?("darwin")
|
25
|
+
end
|
26
|
+
|
27
|
+
def debug?
|
28
|
+
$DEBUG || any_switch?('d', 'debug')
|
29
|
+
end
|
30
|
+
|
31
|
+
def show_version?
|
32
|
+
any_switch?('v', 'version')
|
33
|
+
end
|
34
|
+
|
35
|
+
def show_usage?
|
36
|
+
any_switch?('h', 'help')
|
37
|
+
end
|
38
|
+
|
39
|
+
def show_version
|
40
|
+
puts Kicker::VERSION
|
41
|
+
end
|
42
|
+
|
43
|
+
def available_recipes_as_sentence
|
44
|
+
available = Kicker::Script.available_recipes
|
45
|
+
available[0..-2].join(', ') + ', and ' + available[-1]
|
46
|
+
end
|
47
|
+
|
48
|
+
def dump_options?
|
49
|
+
any_switch?('dump-options')
|
50
|
+
end
|
51
|
+
|
52
|
+
def dump_options
|
53
|
+
puts options.inspect
|
54
|
+
end
|
55
|
+
|
56
|
+
def show_usage
|
57
|
+
puts "Usage: #{$0} [options] [paths to watch]"
|
58
|
+
puts ""
|
59
|
+
puts " Available recipes: #{available_recipes_as_sentence}."
|
60
|
+
puts ""
|
61
|
+
puts "OPTIONS"
|
62
|
+
puts ""
|
63
|
+
if osx?
|
64
|
+
puts " -a, --activate: The application to activate when a notification is clicked. Defaults to `com.apple.Terminal'."
|
65
|
+
end
|
66
|
+
puts " -c, --clear: Clear console before each run."
|
67
|
+
puts " -d, --debug: Print debug messages for Kicker internals."
|
68
|
+
puts " -k, --kickfile: Use a specific Kickfile."
|
69
|
+
puts " -l, --latency: The time to collect events before acting on them. (float)."
|
70
|
+
puts " -n, --no-notify: Don't send notifications."
|
71
|
+
puts " -q, --quiet: Quiet output. Don't print timestamps when logging."
|
72
|
+
puts " -r, --recipe: Load named recipe."
|
73
|
+
puts " -s, --silent: Don't output anything."
|
74
|
+
puts " -v, --version: Print the Kicker version."
|
75
|
+
end
|
76
|
+
|
77
|
+
def verbosity
|
78
|
+
if any_switch?('s', 'silent')
|
79
|
+
:silent
|
80
|
+
elsif any_switch?('q', 'quiet')
|
81
|
+
:quiet
|
82
|
+
else
|
83
|
+
:regular
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def kickfile
|
88
|
+
if path = option_value('k', 'kickfile')
|
89
|
+
File.absolute_path(path)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def recipes
|
94
|
+
@options.map do |switch, name|
|
95
|
+
if %w(r recipe).include?(switch)
|
96
|
+
name
|
97
|
+
end
|
98
|
+
end.compact
|
99
|
+
end
|
100
|
+
|
101
|
+
def options
|
102
|
+
{
|
103
|
+
activate: option_value('a', 'activate'),
|
104
|
+
clear_before_execute: any_switch?('c', 'clear'),
|
105
|
+
kickfile: kickfile,
|
106
|
+
notifications: !any_switch?('n', 'no-notify'),
|
107
|
+
recipes: recipes,
|
108
|
+
verbosity: verbosity
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def run
|
113
|
+
if show_version?
|
114
|
+
show_version
|
115
|
+
elsif show_usage?
|
116
|
+
show_usage
|
117
|
+
elsif dump_options?
|
118
|
+
dump_options
|
119
|
+
else
|
120
|
+
require 'kicker/debug' if debug?
|
121
|
+
watcher = ::Kicker::Watcher.new(options)
|
122
|
+
watcher.run
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.run(argv)
|
127
|
+
new(argv).run
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|