rerun 0.11.0 → 0.12.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a237bdcfe8672bdd765c6a480fbd397e30f0fc45
4
- data.tar.gz: 46a4241842ffad57cfdb560bf2b7da0088f35c47
3
+ metadata.gz: a1489afa035f2da5780ee35de95b95bd272c5440
4
+ data.tar.gz: 2610078f1caaf80bb29540fd398149b539b88b12
5
5
  SHA512:
6
- metadata.gz: 3abd42a820c468ae5c5ac50095a888106967e0c64dfe4bdb4c8aca3adef2ce84e85262278a7c9c5382a276437c359de5f875b578da7624c001b2b0d4d7c5d458
7
- data.tar.gz: 20964c0461cb634bbe11ea931b2eb25d740e4dd228c6a6e8ab18cdf6e2a368376b8e47c3614a073385323856d0ad6238db5031cfb3fbc732415c7fce5d4f9f38
6
+ metadata.gz: ff6bf2054ab858b4a9bfde9600ffb5966be77c63584e1049bf2f4299b01b437fe5fdf83b7e890b55d2ab249243d02cd60ad035ce2ad1145d83f904f9a53b272e
7
+ data.tar.gz: 88f0dd6fd81c98ab774a4ab2f5a7f545b827f3295d19a4613a0504b42e6de0dd4a13a5d6381e59a43f0f067aca3100ff4d2b177bb3a46f723100c85d369c7764
data/README.md CHANGED
@@ -14,14 +14,18 @@ Rerun's advantage is its simple design. Since it uses `exec` and the standard
14
14
  Unix `SIGINT` and `SIGKILL` signals, you're sure the restarted app is really
15
15
  acting just like it was when you ran it from the command line the first time.
16
16
 
17
- By default it watches files ending in: `rb,js,coffee,css,scss,sass,erb,html,haml,ru,yml,slim,md,feature`.
17
+ By default it watches files ending in: `rb,js,coffee,css,scss,sass,erb,html,haml,ru,yml,slim,md,feature,c,h`.
18
18
  Use the `--pattern` option if you want to change this.
19
19
 
20
20
  As of version 0.7.0, we use the Listen gem, which tries to use your OS's
21
21
  built-in facilities for monitoring the filesystem, so CPU use is very light.
22
22
 
23
- Rerun does not work on Windows. Sorry, but you can't do much relaunching
24
- without "fork".
23
+ **UPDATE**: Now Rerun *does* work on Windows. Caveats:
24
+ * not well-tested
25
+ * after running, it may continue to slurp up some of your console input, so run it in a separate window, and/or use `--background` to disable on-the-fly commands, and/or press `q` to quit instead of CTRL-C
26
+ * you may need to install the `wdm` gem manually: `gem install wdm`
27
+ * You may see this persistent `INFO` error message; to remove it, use`--no-notify`:
28
+ * `INFO: Could not find files for the given pattern(s)`
25
29
 
26
30
  # Installation:
27
31
 
@@ -40,10 +44,19 @@ they're not available. Unfortunately, Rubygems doesn't understand optional
40
44
  dependencies very well, so you may have to install extra gems (and/or put them
41
45
  in your Gemfile) to make Rerun work more smoothly on your system.
42
46
  (Learn more at <https://github.com/guard/listen#listen-adapters>.)
43
- For example, on Mac OS X, use
47
+
48
+ On Mac OS X, use
44
49
 
45
50
  gem install rb-fsevent
46
51
 
52
+ On Windows, use
53
+
54
+ gem install wdm
55
+
56
+ On *BSD, use
57
+
58
+ gem install rb-kqueue
59
+
47
60
  # Usage:
48
61
 
49
62
  rerun [options] [--] cmd
@@ -116,44 +129,56 @@ Procfile processes locally and restart them all when necessary.
116
129
  `--dir` directory (or directories) to watch (default = "."). Separate multiple paths with ',' and/or use multiple `-d` options.
117
130
 
118
131
  `--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.
119
- By default it watches files ending in: `rb,js,coffee,css,scss,sass,erb,html,haml,ru,yml,slim,md,feature`.
132
+ By default it watches files ending in: `rb,js,coffee,css,scss,sass,erb,html,haml,ru,yml,slim,md,feature,c,h`.
120
133
  On top of this, it also ignores dotfiles, `.tmp` files, and some other files and directories (like `.git` and `log`).
121
134
  Run `rerun --help` to see the actual list.
122
135
 
123
- `--ignore pattern` file glob to ignore (can be set many times). To ignore a directory, you must append '/*' e.g.
136
+ `--ignore pattern` file glob to ignore (can be set many times). To ignore a directory, you must append `'/*'` e.g.
124
137
  `--ignore 'coverage/*'`.
125
138
 
126
139
  *On top of --pattern and --ignore, we ignore any changes to files and dirs starting with a dot.*
127
140
 
128
- `--signal` (or `-s`) use specified signal (instead of the default SIGTERM) to terminate the previous process.
141
+ `--signal` (or `-s`) use specified signal(s) (instead of the default `TERM,INT,KILL`) to terminate the previous process. You can use a comma-delimited list if you want to try a signal, wait up to 5 seconds for the process to die, then try again with a different signal, and so on.
129
142
  This may be useful for forcing the respective process to terminate as quickly as possible.
130
143
  (`--signal KILL` is the equivalent of `kill -9`)
131
144
 
145
+ `--wait sec` (or `-w`) after asking the process to terminate, wait this long (in seconds) before either aborting, or trying the next signal in series. Default: 2 sec
146
+
132
147
  `--restart` (or `-r`) expect process to restart itself, using signal HUP by default
133
148
  (e.g. `-r -s INT` will send a INT and then resume watching for changes)
134
149
 
135
- `--clear` (or -c) clear the screen before each run
136
-
137
150
  `--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.
138
151
 
152
+ `--clear` (or -c) clear the screen before each run
153
+
139
154
  `--background` (or -b) disable on-the-fly commands, allowing the process to be backgrounded
140
155
 
141
- `--notify NOTIFIER` use `growl` or `osx` for notifications (see below)
156
+ `--notify NOTIFIER` use `growl` or `osx` or `notify-send` for notifications (see below)
142
157
 
143
- `--no-notify` don't use growl (or osx) notifications
158
+ `--no-notify` disable notifications
144
159
 
145
160
  `--name` set the app name (for display)
146
161
 
162
+ `--force-polling` use polling instead of a native filesystem scan (useful for Vagrant)
163
+
164
+ `--quiet` silences most messages
165
+
166
+ `--verbose` enables even more messages (unless you also specified `--quiet`, which overrides `--verbose`)
167
+
147
168
  Also `--version` and `--help`, naturally.
148
169
 
149
170
  # Notifications
150
171
 
151
172
  If you have `growlnotify` available on the `PATH`, it sends notifications to
152
173
  growl in addition to the console.
174
+
153
175
  If you have `terminal-notifier`, it sends notifications to
154
176
  the OS X notification center in addition to the console.
155
177
 
156
- If you have both, Rerun will pick one, or you can choose between them using `--notify growl` or `--notify osx` respectively.
178
+ If you have `notify-send`, it sends notifications to Freedesktop-compatible
179
+ desktops in addition to the console.
180
+
181
+ If you have more than one available notification program, Rerun will pick one, or you can choose between them using `--notify growl`, `--notify osx`, `--notify notify-send`, etc.
157
182
 
158
183
  If you have a notifier installed but don't want rerun to use it,
159
184
  set the `--no-notify` option.
@@ -163,11 +188,14 @@ now that Growl has moved to the App Store.
163
188
 
164
189
  Install [terminal-notifier](https://github.com/julienXX/terminal-notifier) using `gem install terminal-notifier`. (You may have to put it in your system gemset and/or use `sudo` too.) Using Homebrew to install terminal-notifier is not recommended.
165
190
 
191
+ On Debian/Ubuntu, `notify-send` is availble in the `libnotify-bin` package. On other GNU/Linux systems, it might be in a package with a different name.
192
+
166
193
  # On-The-Fly Commands
167
194
 
168
195
  While the app is (re)running, you can make things happen by pressing keys:
169
196
 
170
197
  * **r** -- restart (as if a file had changed)
198
+ * **f** -- force restart (stop and start)
171
199
  * **c** -- clear the screen
172
200
  * **x** or **q** -- exit (just like control-C)
173
201
  * **p** -- pause/unpause filesystem watching
@@ -180,14 +208,31 @@ keys to be trapped, so use the `--background` option.
180
208
  The current algorithm for killing the process is:
181
209
 
182
210
  * send [SIGTERM](http://en.wikipedia.org/wiki/SIGTERM) (or the value of the `--signal` option)
183
- * if that doesn't work after 4 seconds, send SIGINT (aka control-C)
211
+ * if that doesn't work after 2 seconds, send SIGINT (aka control-C)
184
212
  * if that doesn't work after 2 more seconds, send SIGKILL (aka kill -9)
185
213
 
186
214
  This seems like the most gentle and unixy way of doing things, but it does
187
- mean that if your program ignores SIGTERM, it takes an extra 4 to 6 seconds to
215
+ mean that if your program ignores SIGTERM, it takes an extra 2 to 4 seconds to
188
216
  restart.
189
217
 
218
+ If you want to use your own series of signals, use the `--signal` option. If you want to change the delay before attempting the next signal, use the `--wait` option.
219
+
220
+ # Vagrant and VirtualBox
221
+
222
+ If running inside a shared directory using Vagrant and VirtualBox, you must pass the `--force-polling` option. You may also have to pass some extra `--ignore` options too; otherwise each scan can take 10 or more seconds on directories with a large number of files or subdirectories underneath it.
223
+
190
224
  # Troubleshooting
225
+
226
+ ## Vagrant ##
227
+
228
+ Rerun will not pick up changes made to shared folders. This means that the common
229
+ method of using Vagrant for an execution environment and using the `/vagrant`
230
+ shared folder for source code will not work.
231
+
232
+ Instead, use [shotgun](https://rubygems.org/gems/shotgun).
233
+
234
+ ## zsh ##
235
+
191
236
  If you are using `zsh` as your shell, and you are specifying your `--pattern` as `**/*.rb`, you may face this error
192
237
  ```
193
238
  Errno::EACCES: Permission denied - <filename>
@@ -210,24 +255,17 @@ rerun -p "**/*.rb" rake test
210
255
  * Optionally do "bundle install" before and "bundle exec" during launch
211
256
 
212
257
  ## Nice to have
213
- * Smarter --signal option (specifying signal to try and a timeout to wait, repeated)
214
258
  * If the last element of the command is a `.ru` file and there's no other command then use `rackup`
215
259
  * Figure out an algorithm so "-x" is not needed (if possible) -- maybe by accepting a "--port" option or reading `config.ru`
216
260
  * Specify (or deduce) port to listen for to determine success of a web server launch
217
261
  * see also [todo.md](todo.md)
218
262
 
219
263
  ## Wacky Ideas
220
- * Make it work on Windows, like Guard now does. See
221
- * https://github.com/guard/guard/issues/59
222
- * https://github.com/guard/guard/issues/27
264
+
223
265
  * On OS X:
224
266
  * use a C library using growl's developer API <http://growl.info/developer/>
225
267
  * Use growl's AppleScript or SDK instead of relying on growlnotify
226
- * Use OS X notifications
227
268
  * "Failed" icon for notifications
228
- * On Linux:
229
- * Test on Linux.
230
- * Use libnotify or notify-send http://www.linuxjournal.com/content/tech-tip-get-notifications-your-scripts-notify-send
231
269
 
232
270
  # Other projects that do similar things
233
271
 
@@ -321,9 +359,28 @@ Based upon and/or inspired by:
321
359
  * James Edward Gray II <https://github.com/JEG2>
322
360
  * Raul E Rangel <https://github.com/ismell> and Antonio Terceiro <https://github.com/terceiro>
323
361
  * Mike Pastore <https://github.com/mwpastore>
362
+ * Andy Duncan <https://github.com/ajduncan>
363
+ * Brent Van Minnen
364
+ * Matthew O'Riordan <https://github.com/mattheworiordan>
365
+ * Antonio Terceiro <https://github.com/terceiro>
366
+ * <https://github.com/mattbrictson>
367
+ * <https://github.com/krissi>
324
368
 
325
369
  # Version History
326
370
 
371
+ * v0.12.0 23 January 2018
372
+ * smarter `--signal` option, allowing you to specify a series of signals to try in order; also `--wait` to change how long between tries
373
+ * `--force-polling` option (thanks ajduncan)
374
+ * `f` key to force stop and start (thanks mwpastore)
375
+ * add `.c` and `.h` files to default ignore list
376
+ * support for Windows
377
+ * use `Kernel.spawn` instead of `fork`
378
+ * use `wdm` gem for Windows Directory Monitor
379
+ * TODO: fix `INFO` error message
380
+ * TODO: fix console input contention bug
381
+ * support for notifications on GNU/Linux using [notify-send](http://www.linuxjournal.com/content/tech-tip-get-notifications-your-scripts-notify-send) (thanks terceiro)
382
+ * fix `Gem::LoadError - terminal-notifier is not part of the bundle` [bug](https://github.com/alexch/rerun/issues/108) (thanks mattheworiordan)
383
+
327
384
  * 0.11.0 7 October 2015
328
385
  * better 'changed' message
329
386
  * `--notify osx` option
data/Rakefile CHANGED
@@ -1,82 +1,82 @@
1
- require 'rake'
2
- require 'rake/clean'
3
- require 'rake/testtask'
4
- require 'rspec/core/rake_task'
5
-
6
- task :default => [:spec]
7
- task :test => :spec
8
-
9
- desc "Run all specs"
10
- RSpec::Core::RakeTask.new('spec') do |t|
11
- ENV['ENV'] = "test"
12
- t.pattern = 'spec/**/*_spec.rb'
13
- t.rspec_opts = ['--color']
14
- end
15
-
16
- $rubyforge_project = 'pivotalrb'
17
-
18
- $spec =
19
- begin
20
- require 'rubygems/specification'
21
- data = File.read('rerun.gemspec')
22
- spec = nil
23
- #Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
24
- spec = eval data
25
- spec
26
- end
27
-
28
- def package(ext='')
29
- "pkg/#{$spec.name}-#{$spec.version}" + ext
30
- end
31
-
32
- desc 'Exit if git is dirty'
33
- task :check_git do
34
- state = `git status 2> /dev/null | tail -n1`
35
- clean = (state =~ /working directory clean/)
36
- unless clean
37
- warn "can't do that on an unclean git dir"
38
- exit 1
39
- end
40
- end
41
-
42
- desc 'Build packages'
43
- task :package => %w[.gem .tar.gz].map { |e| package(e) }
44
-
45
- desc 'Build and install as local gem'
46
- task :install => package('.gem') do
47
- sh "gem install #{package('.gem')}"
48
- end
49
-
50
- directory 'pkg/'
51
- CLOBBER.include('pkg')
52
-
53
- file package('.gem') => %W[pkg/ #{$spec.name}.gemspec] + $spec.files do |f|
54
- sh "gem build #{$spec.name}.gemspec"
55
- mv File.basename(f.name), f.name
56
- end
57
-
58
- file package('.tar.gz') => %w[pkg/] + $spec.files do |f|
59
- cmd = <<-SH
60
- git archive \
61
- --prefix=#{$spec.name}-#{$spec.version}/ \
62
- --format=tar \
63
- HEAD | gzip > #{f.name}
64
- SH
65
- sh cmd.gsub(/ +/, ' ')
66
- end
67
-
68
- desc 'Publish gem and tarball to rubyforge'
69
- task 'release' => [:check_git, package('.gem'), package('.tar.gz')] do |t|
70
- puts "Releasing #{$spec.version}"
71
- sh "gem push #{package('.gem')}"
72
- puts "Tagging and pushing"
73
- sh "git tag v#{$spec.version}"
74
- sh "git push && git push --tags"
75
- end
76
-
77
- desc 'download github issues and pull requests'
78
- task 'github' do
79
- %w(issues pulls).each do |type|
80
- sh "curl -o #{type}.json https://api.github.com/repos/alexch/rerun/#{type}"
81
- end
82
- end
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rspec/core/rake_task'
5
+
6
+ task :default => [:spec]
7
+ task :test => :spec
8
+
9
+ desc "Run all specs"
10
+ RSpec::Core::RakeTask.new('spec') do |t|
11
+ ENV['ENV'] = "test"
12
+ t.pattern = 'spec/**/*_spec.rb'
13
+ t.rspec_opts = ['--color']
14
+ end
15
+
16
+ $rubyforge_project = 'pivotalrb'
17
+
18
+ $spec =
19
+ begin
20
+ require 'rubygems/specification'
21
+ data = File.read('rerun.gemspec')
22
+ spec = nil
23
+ #Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
24
+ spec = eval data
25
+ spec
26
+ end
27
+
28
+ def package(ext='')
29
+ "pkg/#{$spec.name}-#{$spec.version}" + ext
30
+ end
31
+
32
+ desc 'Exit if git is dirty'
33
+ task :check_git do
34
+ # state = `git status 2> /dev/null | tail -n1`
35
+ # clean = (state =~ /working (directory|tree) clean/)
36
+ # unless clean
37
+ # warn "can't do that on an unclean git dir"
38
+ # exit 1
39
+ # end
40
+ end
41
+
42
+ desc 'Build packages'
43
+ task :package => %w[.gem .tar.gz].map { |e| package(e) }
44
+
45
+ desc 'Build and install as local gem'
46
+ task :install => package('.gem') do
47
+ sh "gem install #{package('.gem')}"
48
+ end
49
+
50
+ directory 'pkg/'
51
+ CLOBBER.include('pkg')
52
+
53
+ file package('.gem') => %W[pkg/ #{$spec.name}.gemspec] + $spec.files do |f|
54
+ sh "gem build #{$spec.name}.gemspec"
55
+ mv File.basename(f.name), f.name
56
+ end
57
+
58
+ file package('.tar.gz') => %w[pkg/] + $spec.files do |f|
59
+ cmd = <<-SH
60
+ git archive \
61
+ --prefix=#{$spec.name}-#{$spec.version}/ \
62
+ --format=tar \
63
+ HEAD | gzip > #{f.name}
64
+ SH
65
+ sh cmd.gsub(/ +/, ' ')
66
+ end
67
+
68
+ desc 'Publish gem and tarball to rubyforge'
69
+ task 'release' => [:check_git, package('.gem'), package('.tar.gz')] do |t|
70
+ puts "Releasing #{$spec.version}"
71
+ sh "gem push #{package('.gem')}"
72
+ puts "Tagging and pushing"
73
+ sh "git tag v#{$spec.version}"
74
+ sh "git push && git push --tags"
75
+ end
76
+
77
+ desc 'download github issues and pull requests'
78
+ task 'github' do
79
+ %w(issues pulls).each do |type|
80
+ sh "curl -o #{type}.json https://api.github.com/repos/alexch/rerun/#{type}"
81
+ end
82
+ end
data/bin/rerun CHANGED
@@ -1,12 +1,12 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
- libdir = "#{File.expand_path(File.dirname(File.dirname(__FILE__)))}/lib"
5
- $LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
6
-
7
- require 'rerun'
8
- require 'optparse'
9
-
10
- options = Rerun::Options.parse
11
- exit if options.nil?
12
- runner = Rerun::Runner.keep_running(options[:cmd], options)
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ libdir = "#{File.expand_path(File.dirname(File.dirname(__FILE__)))}/lib"
5
+ $LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
6
+
7
+ require 'rerun'
8
+ require 'optparse'
9
+
10
+ options = Rerun::Options.parse
11
+ exit if options.nil?
12
+ runner = Rerun::Runner.keep_running(options[:cmd], options)
@@ -0,0 +1,3 @@
1
+ goooo
2
+ goooo
3
+ goooo
@@ -1,15 +1,15 @@
1
- here = File.expand_path(File.dirname(__FILE__))
2
- $: << here unless $:.include?(here)
3
-
4
- require "listen" # pull in the Listen gem
5
- require "rerun/options"
6
- require "rerun/system"
7
- require "rerun/notification"
8
- require "rerun/runner"
9
- require "rerun/watcher"
10
- require "rerun/glob"
11
-
12
- module Rerun
13
-
14
- end
15
-
1
+ here = File.expand_path(File.dirname(__FILE__))
2
+ $: << here unless $:.include?(here)
3
+
4
+ require "listen" # pull in the Listen gem
5
+ require "rerun/options"
6
+ require "rerun/system"
7
+ require "rerun/notification"
8
+ require "rerun/runner"
9
+ require "rerun/watcher"
10
+ require "rerun/glob"
11
+
12
+ module Rerun
13
+
14
+ end
15
+
@@ -1,64 +1,82 @@
1
- # todo: unit tests
2
-
3
- module Rerun
4
- class Notification
5
- include System
6
-
7
- attr_reader :title, :body, :options
8
-
9
- def initialize(title, body, options = Options::DEFAULTS.dup)
10
- @title = title
11
- @body = body
12
- @options = options
13
- end
14
-
15
- def command
16
- return unless mac?
17
-
18
- # todo: strategy or subclass
19
-
20
- s = nil
21
-
22
- if options[:notify] == true or options[:notify] == "growl"
23
- if (cmd = command_named("growlnotify"))
24
- # todo: check version of growlnotify and warn if it's too old
25
- icon_str = ("--image \"#{icon}\"" if icon)
26
- s = "#{cmd} -n \"#{app_name}\" -m \"#{body}\" \"#{app_name} #{title}\" #{icon_str}"
27
- end
28
- end
29
-
30
- if s.nil? and options[:notify] == true or options[:notify] == "osx"
31
- if (cmd = command_named("terminal-notifier"))
32
- icon_str = ("-appIcon \"#{icon}\"" if icon)
33
- s = "#{cmd} -title \"#{app_name}\" -message \"#{body}\" \"#{app_name} #{title}\" #{icon_str}"
34
- end
35
- end
36
-
37
- s
38
- end
39
-
40
- def command_named(name)
41
- path = `which #{name}`.chomp
42
- path.empty? ? nil : path
43
- end
44
-
45
- def send(background = true)
46
- return unless command
47
- `#{command}#{" &" if background}`
48
- end
49
-
50
- def app_name
51
- options[:name]
52
- end
53
-
54
- def icon
55
- "#{icon_dir}/rails_red_sml.png" if rails?
56
- end
57
-
58
- def icon_dir
59
- here = File.expand_path(File.dirname(__FILE__))
60
- File.expand_path("#{here}/../../icons")
61
- end
62
-
63
- end
64
- end
1
+ # todo: unit tests
2
+
3
+ module Rerun
4
+ class Notification
5
+ include System
6
+
7
+ attr_reader :title, :body, :options
8
+
9
+ def initialize(title, body, options = Options::DEFAULTS.dup)
10
+ @title = title
11
+ @body = body
12
+ @options = options
13
+ end
14
+
15
+ def command
16
+ # todo: strategy or subclass
17
+
18
+ s = nil
19
+
20
+ if options[:notify] == true or options[:notify] == "growl"
21
+ if (cmd = command_named("growlnotify"))
22
+ # todo: check version of growlnotify and warn if it's too old
23
+ icon_str = ("--image \"#{icon}\"" if icon)
24
+ s = "#{cmd} -n \"#{app_name}\" -m \"#{body}\" \"#{app_name} #{title}\" #{icon_str}"
25
+ end
26
+ end
27
+
28
+ if s.nil? and options[:notify] == true or options[:notify] == "osx"
29
+ if (cmd = command_named("terminal-notifier"))
30
+ icon_str = ("-appIcon \"#{icon}\"" if icon)
31
+ s = "#{cmd} -title \"#{app_name}\" -message \"#{body}\" \"#{app_name} #{title}\" #{icon_str}"
32
+ end
33
+ end
34
+
35
+ if s.nil? and options[:notify] == true or options[:notify] == "notify-send"
36
+ if (cmd = command_named('notify-send'))
37
+ icon_str = "--icon #{icon}" if icon
38
+ s = "#{cmd} -t 500 --hint=int:transient:1 #{icon_str} \"#{app_name}: #{title}\" \"#{body}\""
39
+ end
40
+ end
41
+
42
+ s
43
+ end
44
+
45
+ def command_named(name)
46
+ which_command = windows? ? 'where.exe' : 'which'
47
+ # TODO: remove 'INFO' error message
48
+ path = `#{which_command} #{name}`.chomp
49
+ path.empty? ? nil : path
50
+ end
51
+
52
+ def send(background = true)
53
+ return unless command
54
+ with_clean_env do
55
+ `#{command}#{" &" if background}`
56
+ end
57
+ end
58
+
59
+ def app_name
60
+ options[:name]
61
+ end
62
+
63
+ def icon
64
+ "#{icon_dir}/rails_red_sml.png" if rails?
65
+ end
66
+
67
+ def icon_dir
68
+ here = File.expand_path(File.dirname(__FILE__))
69
+ File.expand_path("#{here}/../../icons")
70
+ end
71
+
72
+ def with_clean_env
73
+ if defined?(Bundler)
74
+ Bundler.with_clean_env do
75
+ yield
76
+ end
77
+ else
78
+ yield
79
+ end
80
+ end
81
+ end
82
+ end