rerun 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +37 -6
- data/bin/rerun +3 -57
- data/lib/rerun.rb +1 -0
- data/lib/rerun/options.rb +79 -0
- data/lib/rerun/runner.rb +11 -4
- data/lib/rerun/system.rb +2 -2
- data/lib/rerun/watcher.rb +16 -8
- data/rerun.gemspec +1 -1
- metadata +4 -3
data/README.md
CHANGED
@@ -55,9 +55,9 @@ to restart when you change a config file like this:
|
|
55
55
|
|
56
56
|
Or if you're using Thin to run a Rack app that's configured in config.ru
|
57
57
|
but you want it on port 4000 and in debug mode, and only want to watch
|
58
|
-
the `app`
|
58
|
+
the `app` and `web` subdirectories:
|
59
59
|
|
60
|
-
rerun --dir app -- thin start --debug --port=4000 -R config.ru
|
60
|
+
rerun --dir app,web -- thin start --debug --port=4000 -R config.ru
|
61
61
|
|
62
62
|
The `--` is to separate rerun options from cmd options. You can also
|
63
63
|
use a quoted string for the command, e.g.
|
@@ -104,22 +104,31 @@ Procfile processes locally and restart them all when necessary.
|
|
104
104
|
|
105
105
|
# Options:
|
106
106
|
|
107
|
-
`--dir` directory to watch (default = ".")
|
107
|
+
`--dir` directory (or directories) to watch (default = "."). Separate multiple paths with ','.
|
108
108
|
|
109
109
|
`--pattern` glob to match inside directory. This uses the Ruby Dir glob style -- see <http://www.ruby-doc.org/core/classes/Dir.html#M002322> for details.
|
110
110
|
By default it watches files ending in: `rb,js,css,scss,sass,erb,html,haml,ru`.
|
111
111
|
It also ignores directories named `.rbx .bundle .git .svn log tmp vendor` and files named `.DS_Store`.
|
112
112
|
|
113
|
+
`--signal` (or -s) use specified signal (instead of the default SIGTERM) to terminate the previous process.
|
114
|
+
This may be useful for forcing the respective process to terminate as quickly as possible.
|
115
|
+
(`--signal KILL` is the equivalent of `kill -9`)
|
116
|
+
|
113
117
|
`--clear` (or -c) clear the screen before each run
|
114
118
|
|
115
119
|
`--exit` (or -x) expect the program to exit. With this option, rerun checks the return value; without it, rerun checks that the launched process is still running.
|
116
120
|
|
121
|
+
`--background` (or -b) disable on-the-fly commands, allowing the process to be backgrounded
|
122
|
+
|
123
|
+
`--no-growl` don't use growl
|
124
|
+
|
117
125
|
Also --version and --help, naturally.
|
118
126
|
|
119
127
|
# Growl Notifications
|
120
128
|
|
121
129
|
If you have `growlnotify` available on the `PATH`, it sends notifications to
|
122
|
-
growl in addition to the console.
|
130
|
+
growl in addition to the console. If you have growl but don't want rerun to use it,
|
131
|
+
set the `--no-growl` option.
|
123
132
|
|
124
133
|
Download [growlnotify here](http://growl.info/downloads.php#generaldownloads)
|
125
134
|
now that Growl has moved to the App Store.
|
@@ -132,19 +141,29 @@ While the app is (re)running, you can make things happen by pressing keys:
|
|
132
141
|
* **c** -- clear the screen
|
133
142
|
* **x** or **q** -- exit (just like control-C)
|
134
143
|
|
144
|
+
# Signals
|
145
|
+
|
146
|
+
The current algorithm for killing the process is:
|
147
|
+
|
148
|
+
* send [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM)
|
149
|
+
* if that doesn't work after 4 seconds, send SIGINT (aka control-C)
|
150
|
+
* if that doesn't work after 2 more seconds, send SIGKILL (aka kill -9)
|
151
|
+
|
152
|
+
This seems like the most gentle and unixy way of doing things, but it does
|
153
|
+
mean that if your program ignores SIGTERM, it takes an extra 4 to 6 seconds to
|
154
|
+
restart.
|
155
|
+
|
135
156
|
# To Do:
|
136
157
|
|
137
158
|
* Cooldown (so if a dozen files appear in a burst, say from 'git pull', it only restarts once)
|
138
159
|
* If the last element of the command is a `.ru` file and there's no other command then use `rackup`
|
139
160
|
* Exclude files beginning with a dot, unless the pattern explicitly says to include them
|
140
|
-
* Allow multiple sets of directories and patterns
|
141
161
|
* --exclude pattern
|
142
162
|
* ".rerun" file to specify options per project or in $HOME.
|
143
163
|
* Test on Linux.
|
144
164
|
* On OS X, use a C library using growl's developer API <http://growl.info/developer/>
|
145
165
|
* Use growl's AppleScript or SDK instead of relying on growlnotify
|
146
166
|
* "Failed" icon
|
147
|
-
* Get Rails icon working
|
148
167
|
* Figure out an algorithm so "-x" is not needed (if possible)
|
149
168
|
* Specify (or deduce) port to listen for to determine success of a web server launch
|
150
169
|
* Make sure to pass through quoted options correctly to target process [bug]
|
@@ -152,6 +171,7 @@ While the app is (re)running, you can make things happen by pressing keys:
|
|
152
171
|
* https://github.com/guard/guard/issues/59
|
153
172
|
* https://github.com/guard/guard/issues/27
|
154
173
|
* Optionally do "bundle install" before and "bundle exec" during launch
|
174
|
+
|
155
175
|
# Other projects that do similar things
|
156
176
|
|
157
177
|
* Restartomatic: <http://github.com/adammck/restartomatic>
|
@@ -236,9 +256,20 @@ Based upon and/or inspired by:
|
|
236
256
|
* Jens B <https://github.com/dpree>
|
237
257
|
* Andrés Botero <https://github.com/anbotero>
|
238
258
|
* Dreamcat4
|
259
|
+
* <https://github.com/FND>
|
260
|
+
* Barry Sia <https://github.com/bsia>
|
239
261
|
|
240
262
|
# Version History
|
241
263
|
|
264
|
+
* v0.8.0
|
265
|
+
* --background option (thanks FND!) to disable the keyboard listener
|
266
|
+
* --signal option (thanks FND!)
|
267
|
+
* --no-growl option
|
268
|
+
* --dir supports multiple directories (thanks Barry!)
|
269
|
+
|
270
|
+
* v0.7.1
|
271
|
+
* bugfix: make rails icon work again
|
272
|
+
|
242
273
|
* v0.7.0
|
243
274
|
* uses Listen gem (which uses rb-fsevent for lightweight filesystem snooping)
|
244
275
|
|
data/bin/rerun
CHANGED
@@ -1,66 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
-
|
5
4
|
libdir = "#{File.expand_path(File.dirname(File.dirname(__FILE__)))}/lib"
|
6
5
|
$LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
|
7
6
|
|
8
|
-
load "#{libdir}/../rerun.gemspec" # defines "$spec" variable, which we read the version from
|
9
|
-
|
10
7
|
require 'rerun'
|
11
8
|
require 'optparse'
|
12
9
|
|
13
|
-
options =
|
14
|
-
|
15
|
-
|
16
|
-
opts.banner = "Usage: rerun [options] [--] cmd"
|
17
|
-
|
18
|
-
opts.separator ""
|
19
|
-
opts.separator "Launches an app, and restarts it when the filesystem changes."
|
20
|
-
opts.separator "See http://github.com/alexch/rerun for more info."
|
21
|
-
opts.separator ""
|
22
|
-
opts.separator "Options:"
|
23
|
-
|
24
|
-
opts.on("-d dir", "--dir dir", "directory to watch") do |dir|
|
25
|
-
options[:dir] = dir
|
26
|
-
end
|
27
|
-
|
28
|
-
opts.on("-p pattern", "--pattern pattern", "file glob, default = \"#{Rerun::DEFAULT_PATTERN}\"") do |pattern|
|
29
|
-
options[:pattern] = pattern
|
30
|
-
end
|
31
|
-
|
32
|
-
opts.on("-c", "--clear", "clear screen before each run") do
|
33
|
-
options[:clear] = true
|
34
|
-
end
|
35
|
-
|
36
|
-
opts.on("-x", "--exit", "expect the program to exit. With this option, rerun checks the return value; without it, rerun checks that the process is running.") do |dir|
|
37
|
-
options[:exit] = true
|
38
|
-
end
|
39
|
-
|
40
|
-
opts.on_tail("-h", "--help", "--usage", "show this message") do
|
41
|
-
puts opts
|
42
|
-
exit
|
43
|
-
end
|
44
|
-
|
45
|
-
opts.on_tail("--version", "show version") do
|
46
|
-
puts $spec.version
|
47
|
-
exit
|
48
|
-
end
|
49
|
-
|
50
|
-
opts.parse! ARGV
|
51
|
-
}
|
52
|
-
|
53
|
-
#config = ARGV[0] || "config.ru"
|
54
|
-
#abort "configuration #{config} not found" unless File.exist? config
|
55
|
-
#
|
56
|
-
#if config =~ /\.ru$/ && File.read(config)[/^#\\(.*)/]
|
57
|
-
# opts.parse! $1.split(/\s+/)
|
58
|
-
#end
|
59
|
-
|
60
|
-
if ARGV.empty?
|
61
|
-
puts opts
|
62
|
-
exit
|
63
|
-
end
|
64
|
-
|
65
|
-
cmd = ARGV.join(" ")
|
66
|
-
runner = Rerun::Runner.keep_running(cmd, options)
|
10
|
+
options = Rerun::Options.parse
|
11
|
+
exit if options.nil?
|
12
|
+
runner = Rerun::Runner.keep_running(options[:cmd], options)
|
data/lib/rerun.rb
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
libdir = "#{File.expand_path(File.dirname(File.dirname(__FILE__)))}"
|
4
|
+
load "#{libdir}/../rerun.gemspec" # defines "$spec" variable, which we read the version from
|
5
|
+
|
6
|
+
module Rerun
|
7
|
+
class Options
|
8
|
+
DEFAULT_PATTERN = "**/*.{rb,js,css,scss,sass,erb,html,haml,ru}"
|
9
|
+
|
10
|
+
DEFAULTS = {
|
11
|
+
:dir => ["."],
|
12
|
+
:pattern => DEFAULT_PATTERN,
|
13
|
+
:signal => "TERM",
|
14
|
+
:growl => true,
|
15
|
+
}
|
16
|
+
|
17
|
+
def self.parse args = ARGV
|
18
|
+
options = DEFAULTS.dup
|
19
|
+
opts = OptionParser.new("", 24, ' ') do |opts|
|
20
|
+
opts.banner = "Usage: rerun [options] [--] cmd"
|
21
|
+
|
22
|
+
opts.separator ""
|
23
|
+
opts.separator "Launches an app, and restarts it when the filesystem changes."
|
24
|
+
opts.separator "See http://github.com/alexch/rerun for more info."
|
25
|
+
opts.separator "Version: #{$spec.version}"
|
26
|
+
opts.separator ""
|
27
|
+
opts.separator "Options:"
|
28
|
+
|
29
|
+
opts.on("-d dir", "--dir dir", "directory to watch, default = \"#{DEFAULTS[:dir]}\". Separate multiple paths with ','.") do |dir|
|
30
|
+
options[:dir] = dir.split(",")
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on("-p pattern", "--pattern pattern", "file glob, default = \"#{DEFAULTS[:pattern]}\"") do |pattern|
|
34
|
+
options[:pattern] = pattern
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on("-s", "--signal signal", "terminate process using this signal, default = \"#{DEFAULTS[:signal]}\"") do |signal|
|
38
|
+
options[:signal] = signal
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on("-c", "--clear", "clear screen before each run") do
|
42
|
+
options[:clear] = true
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on("-x", "--exit", "expect the program to exit. With this option, rerun checks the return value; without it, rerun checks that the process is running.") do |dir|
|
46
|
+
options[:exit] = true
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on("-b", "--background", "disable on-the-fly commands, allowing the process to be backgrounded") do
|
50
|
+
options[:background] = true
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on("--no-growl", "don't use growl") do
|
54
|
+
options[:growl] = false
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on_tail("-h", "--help", "--usage", "show this message") do
|
58
|
+
puts opts
|
59
|
+
return
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on_tail("--version", "show version") do
|
63
|
+
puts $spec.version
|
64
|
+
return
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if args.empty?
|
69
|
+
puts opts
|
70
|
+
nil
|
71
|
+
else
|
72
|
+
opts.parse! args
|
73
|
+
options[:cmd] = args.join(" ")
|
74
|
+
options
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/lib/rerun/runner.rb
CHANGED
@@ -18,6 +18,8 @@ module Rerun
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def start_keypress_thread
|
21
|
+
return if @options[:background]
|
22
|
+
|
21
23
|
@keypress_thread = Thread.new do
|
22
24
|
while true
|
23
25
|
if c = key_pressed
|
@@ -59,11 +61,15 @@ module Rerun
|
|
59
61
|
end
|
60
62
|
|
61
63
|
def dir
|
64
|
+
@options[:dir]
|
65
|
+
end
|
66
|
+
|
67
|
+
def dirs
|
62
68
|
@options[:dir] || "."
|
63
69
|
end
|
64
70
|
|
65
71
|
def pattern
|
66
|
-
@options[:pattern]
|
72
|
+
@options[:pattern]
|
67
73
|
end
|
68
74
|
|
69
75
|
def clear?
|
@@ -140,7 +146,7 @@ module Rerun
|
|
140
146
|
|
141
147
|
unless @watcher
|
142
148
|
|
143
|
-
watcher = Watcher.new(:directory =>
|
149
|
+
watcher = Watcher.new(:directory => dirs, :pattern => pattern) do |changes|
|
144
150
|
|
145
151
|
message = [:modified, :added, :removed].map do |change|
|
146
152
|
count = changes[change].size
|
@@ -181,12 +187,13 @@ module Rerun
|
|
181
187
|
|
182
188
|
# todo: test escalation
|
183
189
|
def stop
|
190
|
+
default_signal = @options[:signal] || "TERM"
|
184
191
|
if @pid && (@pid != 0)
|
185
192
|
notify "stopping", "All good things must come to an end." unless @restarting
|
186
193
|
begin
|
187
194
|
timeout(4) do # todo: escalation timeout setting
|
188
195
|
# start with a polite SIGTERM
|
189
|
-
signal(
|
196
|
+
signal(default_signal) && Process.wait(@pid)
|
190
197
|
end
|
191
198
|
rescue Timeout::Error
|
192
199
|
begin
|
@@ -216,7 +223,7 @@ module Rerun
|
|
216
223
|
end
|
217
224
|
|
218
225
|
def notify(title, body)
|
219
|
-
growl title, body
|
226
|
+
growl title, body if @options[:growl]
|
220
227
|
puts
|
221
228
|
say "#{app_name} #{title}"
|
222
229
|
end
|
data/lib/rerun/system.rb
CHANGED
@@ -14,7 +14,7 @@ module Rerun
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# do we have growl or not?
|
17
|
-
def
|
17
|
+
def growl_available?
|
18
18
|
mac? && (growlcmd != "")
|
19
19
|
end
|
20
20
|
|
@@ -37,7 +37,7 @@ module Rerun
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def growl(title, body, background = true)
|
40
|
-
if
|
40
|
+
if growl_available?
|
41
41
|
icon_str = ("--image \"#{icon}\"" if icon)
|
42
42
|
s = "#{growlcmd} -n \"#{app_name}\" -m \"#{body}\" \"#{app_name} #{title}\" #{icon_str}"
|
43
43
|
s += " &" if background
|
data/lib/rerun/watcher.rb
CHANGED
@@ -30,25 +30,33 @@ module Rerun
|
|
30
30
|
}.merge(options)
|
31
31
|
|
32
32
|
@pattern = options[:pattern]
|
33
|
-
@
|
34
|
-
@
|
35
|
-
unless FileTest.exists?(@directory) && FileTest.readable?(@directory)
|
36
|
-
raise InvalidDirectoryError, "Directory '#{@directory}' either doesnt exist or isnt readable"
|
37
|
-
end
|
33
|
+
@directories = options[:directory]
|
34
|
+
@directories = sanitize_dirs(@directories)
|
38
35
|
@priority = options[:priority]
|
39
36
|
@thread = nil
|
40
37
|
end
|
41
38
|
|
39
|
+
def sanitize_dirs(dirs)
|
40
|
+
dirs = [*dirs]
|
41
|
+
dirs.map do |d|
|
42
|
+
d.chomp!("/")
|
43
|
+
unless FileTest.exists?(d) && FileTest.readable?(d) && FileTest.directory?(d)
|
44
|
+
raise InvalidDirectoryError, "Directory '#{d}' either doesnt exist or isnt readable"
|
45
|
+
end
|
46
|
+
d
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
42
50
|
def start
|
43
51
|
if @thread then
|
44
52
|
raise RuntimeError, "already started"
|
45
53
|
end
|
46
54
|
|
47
55
|
@thread = Thread.new do
|
48
|
-
# todo: multiple dirs
|
49
|
-
|
50
56
|
regexp = Glob.new(@pattern).to_regexp
|
51
|
-
|
57
|
+
dirs = @directories
|
58
|
+
params = dirs << { :filter => regexp }
|
59
|
+
@listener = Listen::MultiListener.new(*params) do |modified, added, removed|
|
52
60
|
@client_callback.call(:modified => modified, :added => added, :removed => removed)
|
53
61
|
end
|
54
62
|
@listener.start
|
data/rerun.gemspec
CHANGED
@@ -3,7 +3,7 @@ $spec = Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'rerun'
|
6
|
-
s.version = '0.
|
6
|
+
s.version = '0.8.0'
|
7
7
|
|
8
8
|
s.description = "Restarts your app when a file changes. A no-frills, command-line alternative to Guard, Shotgun, Autotest, etc."
|
9
9
|
s.summary = "Launches an app, and restarts it whenever the filesystem changes. A no-frills, command-line alternative to Guard, Shotgun, Autotest, etc."
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rerun
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: listen
|
@@ -44,6 +44,7 @@ files:
|
|
44
44
|
- icons/rails_grn_sml.png
|
45
45
|
- icons/rails_red_sml.png
|
46
46
|
- lib/rerun/glob.rb
|
47
|
+
- lib/rerun/options.rb
|
47
48
|
- lib/rerun/runner.rb
|
48
49
|
- lib/rerun/system.rb
|
49
50
|
- lib/rerun/watcher.rb
|
@@ -62,7 +63,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
62
63
|
version: '0'
|
63
64
|
segments:
|
64
65
|
- 0
|
65
|
-
hash:
|
66
|
+
hash: 3891504021895001236
|
66
67
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
68
|
none: false
|
68
69
|
requirements:
|