rerun 0.7.1 → 0.8.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.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:
|