rerun 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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