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 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` subdirectory:
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
- opts = OptionParser.new("", 24, ' ') { |opts|
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
@@ -2,6 +2,7 @@ here = File.expand_path(File.dirname(__FILE__))
2
2
  $: << here unless $:.include?(here)
3
3
 
4
4
  require "listen" # pull in the Listen gem
5
+ require "rerun/options"
5
6
  require "rerun/system"
6
7
  require "rerun/runner"
7
8
  require "rerun/watcher"
@@ -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] || DEFAULT_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 => dir, :pattern => pattern) do |changes|
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("TERM") && Process.wait(@pid)
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 growl?
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 growl?
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
- @directory = options[:directory]
34
- @directory.chomp!("/")
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
- @listener = Listen::Listener.new(@directory, :filter => regexp) do |modified, added, removed|
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.7.1'
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.7.1
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: 2012-07-05 00:00:00.000000000 Z
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: 1349085845198859924
66
+ hash: 3891504021895001236
66
67
  required_rubygems_version: !ruby/object:Gem::Requirement
67
68
  none: false
68
69
  requirements: