guard 2.8.2 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -7
  3. data/lib/guard.rb +220 -152
  4. data/lib/guard.rb.orig +213 -155
  5. data/lib/guard/aruba_adapter.rb +2 -2
  6. data/lib/guard/cli.rb +8 -13
  7. data/lib/guard/cli.rb.orig +12 -10
  8. data/lib/guard/commander.rb +15 -7
  9. data/lib/guard/commands/all.rb +3 -0
  10. data/lib/guard/commands/change.rb +3 -0
  11. data/lib/guard/commands/pause.rb +2 -0
  12. data/lib/guard/commands/reload.rb +4 -0
  13. data/lib/guard/commands/scope.rb +3 -0
  14. data/lib/guard/config.rb +24 -0
  15. data/lib/guard/deprecated/dsl.rb +45 -0
  16. data/lib/guard/deprecated/guard.rb +166 -0
  17. data/lib/guard/deprecated/guardfile.rb +84 -0
  18. data/lib/guard/dsl.rb +24 -13
  19. data/lib/guard/dsl.rb.orig +378 -0
  20. data/lib/guard/dsl_describer.rb +8 -2
  21. data/lib/guard/dsl_describer.rb.orig +11 -3
  22. data/lib/guard/guardfile.rb +32 -44
  23. data/lib/guard/guardfile/evaluator.rb +13 -6
  24. data/lib/guard/guardfile/generator.rb +4 -3
  25. data/lib/guard/interactor.rb +7 -3
  26. data/lib/guard/internals/debugging.rb +1 -0
  27. data/lib/guard/internals/environment.rb +93 -0
  28. data/lib/guard/internals/helpers.rb +13 -0
  29. data/lib/guard/internals/traps.rb +10 -0
  30. data/lib/guard/jobs/pry_wrapper.rb +4 -3
  31. data/lib/guard/jobs/sleep.rb +2 -0
  32. data/lib/guard/metadata.rb +190 -0
  33. data/lib/guard/notifier.rb +124 -99
  34. data/lib/guard/notifier.rb.orig +124 -99
  35. data/lib/guard/notifier/detected.rb +83 -0
  36. data/lib/guard/notifiers/emacs.rb +2 -1
  37. data/lib/guard/notifiers/tmux.rb +173 -177
  38. data/lib/guard/plugin/base.rb +2 -0
  39. data/lib/guard/plugin_util.rb +26 -32
  40. data/lib/guard/reevaluator.rb +3 -3
  41. data/lib/guard/reevaluator.rb.orig +22 -0
  42. data/lib/guard/runner.rb +1 -0
  43. data/lib/guard/session.rb +5 -0
  44. data/lib/guard/sheller.rb +2 -2
  45. data/lib/guard/templates/Guardfile +4 -0
  46. data/lib/guard/templates/Guardfile.orig +2 -0
  47. data/lib/guard/terminal.rb +1 -0
  48. data/lib/guard/ui.rb +4 -1
  49. data/lib/guard/version.rb +1 -1
  50. data/lib/guard/version.rb.orig +1 -1
  51. data/lib/guard/watcher.rb +3 -1
  52. data/lib/guard/watcher.rb.orig +122 -0
  53. data/man/guard.1 +1 -4
  54. data/man/guard.1.html +1 -4
  55. metadata +17 -25
  56. data/lib/guard/commander.rb.orig +0 -103
  57. data/lib/guard/commands/all.rb.orig +0 -36
  58. data/lib/guard/commands/reload.rb.orig +0 -34
  59. data/lib/guard/commands/scope.rb.orig +0 -36
  60. data/lib/guard/deprecated_methods.rb +0 -72
  61. data/lib/guard/deprecated_methods.rb.orig +0 -71
  62. data/lib/guard/deprecator.rb +0 -133
  63. data/lib/guard/deprecator.rb.orig +0 -206
  64. data/lib/guard/guard.rb +0 -100
  65. data/lib/guard/guard.rb.orig +0 -42
  66. data/lib/guard/guardfile.rb.orig +0 -43
  67. data/lib/guard/guardfile/evaluator.rb.orig +0 -275
  68. data/lib/guard/internals/debugging.rb.orig +0 -0
  69. data/lib/guard/internals/environment.rb.orig +0 -0
  70. data/lib/guard/internals/tracing.rb.orig +0 -0
  71. data/lib/guard/notifiers/base.rb.orig +0 -221
  72. data/lib/guard/notifiers/tmux.rb.orig +0 -339
  73. data/lib/guard/plugin_util.rb.orig +0 -186
  74. data/lib/guard/runner.rb.orig +0 -210
  75. data/lib/guard/setuper.rb +0 -359
  76. data/lib/guard/setuper.rb.orig +0 -395
  77. data/lib/guard/ui.rb.orig +0 -278
@@ -0,0 +1,83 @@
1
+ require "guard/internals/environment"
2
+
3
+ require_relative "../notifiers/emacs"
4
+ require_relative "../notifiers/file_notifier"
5
+ require_relative "../notifiers/gntp"
6
+ require_relative "../notifiers/growl"
7
+ require_relative "../notifiers/libnotify"
8
+ require_relative "../notifiers/notifysend"
9
+ require_relative "../notifiers/rb_notifu"
10
+ require_relative "../notifiers/terminal_notifier"
11
+ require_relative "../notifiers/terminal_title"
12
+ require_relative "../notifiers/tmux"
13
+
14
+ module Guard
15
+ module Notifier
16
+ # @private api
17
+ class Detected
18
+ NO_SUPPORTED_NOTIFIERS = "Guard could not detect any of the supported" +
19
+ " notification libraries."
20
+
21
+ class NoneAvailableError < RuntimeError
22
+ end
23
+
24
+ def initialize(supported)
25
+ @supported = supported
26
+ @environment = Internals::Environment.new("GUARD").tap do |env|
27
+ env.create_method(:notifiers=) { |data| YAML::dump(data) }
28
+ env.create_method(:notifiers) { |data| data ? YAML::load(data) : [] }
29
+ end
30
+ end
31
+
32
+ def reset
33
+ @environment.notifiers = nil
34
+ end
35
+
36
+ def detect
37
+ return unless _data.empty?
38
+ @supported.each do |group|
39
+ group.detect { |name, _| add(name, silent: true) }
40
+ end
41
+
42
+ fail NoneAvailableError, NO_SUPPORTED_NOTIFIERS if _data.empty?
43
+ end
44
+
45
+ def available
46
+ _data.map { |entry| [_to_module(entry[:name]), entry[:options]] }
47
+ end
48
+
49
+ def add(name, opts)
50
+ klass = _to_module(name)
51
+ return false unless klass
52
+
53
+ all = @environment.notifiers
54
+
55
+ # Silently skip if it's already available, because otherwise
56
+ # we'd have to do :turn_off, then configure, then :turn_on
57
+ names = all.map(&:first).map(&:last)
58
+ unless names.include?(name)
59
+ return false unless klass.available?(opts)
60
+ @environment.notifiers = all << { name: name, options: opts }
61
+ true
62
+ end
63
+
64
+ # Just overwrite the options (without turning the notifier off or on),
65
+ # so those options will be passed in next calls to notify()
66
+ all.each { |item| item[:options] = opts if item[:name] == name }
67
+ true
68
+ end
69
+
70
+ def _to_module(name)
71
+ @supported.each do |group|
72
+ next unless (notifier = group.detect { |n, _| n == name })
73
+ return notifier.last
74
+ end
75
+ nil
76
+ end
77
+
78
+ def _data
79
+ @environment.notifiers || []
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,4 +1,5 @@
1
1
  require "guard/notifiers/base"
2
+ require "guard/sheller"
2
3
 
3
4
  module Guard
4
5
  module Notifier
@@ -21,7 +22,7 @@ module Guard
21
22
  return false unless super
22
23
 
23
24
  client_name = opts.fetch(:client, DEFAULTS[:client])
24
- cmd = "#{client_name} --eval '1' 2> #{DEV_NULL} || echo 'N/A'"
25
+ cmd = "#{client_name} --eval '1' 2> #{IO::NULL} || echo 'N/A'"
25
26
  stdout = Sheller.stdout(cmd)
26
27
  return false if stdout.nil?
27
28
  !%w(N/A 'N/A').include?(stdout.chomp)
@@ -1,4 +1,5 @@
1
1
  require "guard/notifiers/base"
2
+ require "guard/sheller"
2
3
 
3
4
  module Guard
4
5
  module Notifier
@@ -15,60 +16,152 @@ module Guard
15
16
  # notification :tmux, color_location: 'status-right-bg'
16
17
  #
17
18
  class Tmux < Base
19
+ @@session = nil
20
+
18
21
  # Default options for the tmux notifications.
19
- DEFAULTS = {
20
- client: "tmux",
21
- tmux_environment: "TMUX",
22
- success: "green",
23
- failed: "red",
24
- pending: "yellow",
25
- default: "green",
26
- timeout: 5,
27
- display_message: false,
28
- default_message_format: "%s - %s",
29
- default_message_color: "white",
30
- display_on_all_clients: false,
31
- display_title: false,
32
- default_title_format: "%s - %s",
33
- line_separator: " - ",
34
- change_color: true,
35
- color_location: "status-left-bg"
36
- }
37
-
38
- ERROR_NOT_INSIDE_SESSION = "The :tmux notifier runs only on when Guard"\
39
- " is executed inside of a tmux session."
22
+ class Defaults
23
+ DEFAULTS = {
24
+ tmux_environment: "TMUX",
25
+ success: "green",
26
+ failed: "red",
27
+ pending: "yellow",
28
+ default: "green",
29
+ timeout: 5,
30
+ display_message: false,
31
+ default_message_format: "%s - %s",
32
+ default_message_color: "white",
33
+ display_on_all_clients: false,
34
+ display_title: false,
35
+ default_title_format: "%s - %s",
36
+ line_separator: " - ",
37
+ change_color: true,
38
+ color_location: "status-left-bg"
39
+ }
40
+
41
+ def self.option(opts, name)
42
+ opts.fetch(name, DEFAULTS[name])
43
+ end
40
44
 
41
- def self.available?(opts = {})
42
- super && _register!(opts)
45
+ def self.[](name)
46
+ DEFAULTS[name]
47
+ end
43
48
  end
44
49
 
45
- # @private
46
- #
47
- # @return [Boolean] whether or not a TMUX environment is available
48
- #
49
- def self._tmux_environment_available?(opts)
50
- !ENV[opts.fetch(:tmux_environment, DEFAULTS[:tmux_environment])].nil?
50
+ class Client
51
+ CLIENT = "tmux"
52
+ class << self
53
+ def version
54
+ Float(_capture("-V")[/\d+\.\d+/])
55
+ end
56
+
57
+ def clients
58
+ ttys = _capture("list-clients", "-F", "'\#{client_tty}'")
59
+ ttys = ttys.split(/\n/)
60
+
61
+ # if user is running 'tmux -C' remove this client from list
62
+ ttys.delete("(null)")
63
+ ttys
64
+ end
65
+
66
+ def set(client, key, value)
67
+ case client
68
+ when :all, true
69
+ # call ourself
70
+ clients.each { |cl| Client.set(cl, key, value) }
71
+ else
72
+ args = client ? ["-t", client.strip] : nil
73
+ _run("set", "-q", *args, key, value)
74
+ end
75
+ end
76
+
77
+ def display(client, message)
78
+ case client
79
+ when :all, true
80
+ # call ourself
81
+ clients.each { |cl| Client.display(cl, message) }
82
+ else
83
+ args += ["-c", client.strip] if client
84
+ _run("display", *args, message)
85
+ end
86
+ end
87
+
88
+ def unset(client, key, value)
89
+ return set(client, key, value) if value
90
+ args = client ? ["-t", client.strip] : []
91
+ _run("set", "-q", "-u", *args, key)
92
+ end
93
+
94
+ def parse_options(client)
95
+ output = _capture("show", "-t", client)
96
+ Hash[output.lines.map { |line| _parse_option(line) }]
97
+ end
98
+
99
+ def _parse_option(line)
100
+ line.partition(" ").map(&:strip).reject(&:empty?)
101
+ end
102
+
103
+ def _capture(*args)
104
+ Sheller.stdout(([CLIENT] + args).join(" "))
105
+ end
106
+
107
+ def _run(*args)
108
+ Sheller.run(([CLIENT] + args).join(" "))
109
+ end
110
+ end
51
111
  end
52
112
 
53
- # @private
54
- #
55
- # Detects if a TMUX environment is available and if not,
56
- # displays an error message unless `opts[:silent]` is true.
57
- #
58
- # @return [Boolean] whether or not a TMUX environment is available
59
- #
60
- def self._register!(opts)
61
- @options_stored = false
62
- if _tmux_environment_available?(opts)
63
- true
64
- else
65
- unless opts[:silent]
66
- ::Guard::UI.error ERROR_NOT_INSIDE_SESSION
113
+ class Session
114
+ def initialize(_tmux)
115
+ @options_store = {}
116
+
117
+ Client.clients.each do |client|
118
+ @options_store[client] = {
119
+ "status-left-bg" => nil,
120
+ "status-right-bg" => nil,
121
+ "status-left-fg" => nil,
122
+ "status-right-fg" => nil,
123
+ "message-bg" => nil,
124
+ "message-fg" => nil,
125
+ "display-time" => nil
126
+ }.merge(Client.parse_options(client))
127
+ end
128
+ end
129
+
130
+ def close
131
+ @options_store.each do |client, options|
132
+ options.each do |key, value|
133
+ Client.unset(client, key, value)
134
+ end
67
135
  end
68
- false
136
+ @options_store = nil
69
137
  end
70
138
  end
71
139
 
140
+ class Error < RuntimeError
141
+ end
142
+
143
+ ERROR_NOT_INSIDE_TMUX = "The :tmux notifier runs only on when Guard"\
144
+ " is executed inside of a tmux session."
145
+
146
+ ERROR_ANCIENT_TMUX = "Your tmux version is way too old!"
147
+
148
+ def self.available?(opts = {})
149
+ return unless super
150
+
151
+ fail "PREVIOUS TMUX SESSION NOT CLEARED!" if @@session || nil
152
+
153
+ var_name = Defaults.option(opts, :tmux_environment)
154
+ fail Error, ERROR_NOT_INSIDE_TMUX unless ENV.key?(var_name)
155
+
156
+ version = Client.version
157
+ fail Error, format(ERROR_ANCIENT_TMUX, version) if version < 1.7
158
+
159
+ true
160
+ rescue Error => e
161
+ ::Guard::UI.error e.message unless opts[:silent]
162
+ false
163
+ end
164
+
72
165
  # Shows a system notification.
73
166
  #
74
167
  # By default, the Tmux notifier only makes
@@ -99,25 +192,21 @@ module Guard
99
192
  super
100
193
  opts.delete(:image)
101
194
 
102
- if opts.fetch(:change_color, DEFAULTS[:change_color])
103
- options = opts.fetch(:color_location, DEFAULTS[:color_location])
104
- color_locations = Array(options)
105
- color = tmux_color(opts[:type], opts)
106
-
107
- color_locations.each do |color_location|
108
- _run_client "set", "#{self.class._quiet_option}"\
109
- "#{color_location} #{color}"
110
- end
111
- end
112
-
195
+ change_color = Defaults.option(opts, :change_color)
196
+ options = Array(Defaults.option(opts, :color_location))
197
+ display_the_title = Defaults.option(opts, :display_title)
198
+ display_message = Defaults.option(opts, :display_message)
113
199
  type = opts.delete(:type).to_s
114
200
  title = opts.delete(:title)
115
201
 
116
- if opts.fetch(:display_title, DEFAULTS[:display_title])
117
- display_title(type, title, message, opts)
202
+ if change_color
203
+ color = tmux_color(type, opts)
204
+ options.each { |location| Client.set(_all?, location, color) }
118
205
  end
119
206
 
120
- return unless opts.fetch(:display_message, DEFAULTS[:display_message])
207
+ display_title(type, title, message, opts) if display_the_title
208
+
209
+ return unless display_message
121
210
  display_message(type, title, message, opts)
122
211
  end
123
212
 
@@ -137,14 +226,12 @@ module Guard
137
226
  #
138
227
  def display_title(type, title, message, opts = {})
139
228
  format = "#{type}_title_format".to_sym
140
- defaults = DEFAULTS[:default_title_format]
141
- options = opts.fetch(:default_title_format, defaults)
229
+ options = Defaults.option(opts, :default_title_format)
142
230
  title_format = opts.fetch(format, options)
143
231
  teaser_message = message.split("\n").first
144
232
  display_title = title_format % [title, teaser_message]
145
233
 
146
- _run_client "set-option", "#{self.class._quiet_option}"\
147
- "set-titles-string '#{display_title}'"
234
+ Client.set(_all?, "set-titles-string", "'#{display_title}'")
148
235
  end
149
236
 
150
237
  # Displays a message in the status bar of tmux.
@@ -176,32 +263,25 @@ module Guard
176
263
  # line-break.
177
264
  #
178
265
  def display_message(type, title, message, opts = {})
179
- default_format = DEFAULTS[:default_message_format]
180
- default_format = opts.fetch(:default_message_format, default_format)
266
+ default_format = Defaults.option(opts, :default_message_format)
267
+ default_color = Defaults.option(opts, :default_message_color)
268
+ display_time = Defaults.option(opts, :timeout)
269
+ separator = Defaults.option(opts, :line_separator)
270
+
181
271
  format = "#{type}_message_format".to_sym
182
272
  message_format = opts.fetch(format, default_format)
183
273
 
184
- default_color = DEFAULTS[:default_message_color]
185
- default_color = opts.fetch(:default_message_color, default_color)
186
274
  color = "#{type}_message_color".to_sym
187
275
  message_color = opts.fetch(color, default_color)
188
276
 
189
- display_time = opts.fetch(:timeout, DEFAULTS[:timeout])
190
- separator = opts.fetch(:line_separator, DEFAULTS[:line_separator])
191
-
192
- color = tmux_color type, opts
277
+ color = tmux_color(type, opts)
193
278
  formatted_message = message.split("\n").join(separator)
194
279
  display_message = message_format % [title, formatted_message]
195
280
 
196
- _run_client(
197
- "set",
198
- "#{self.class._quiet_option}display-time #{display_time * 1000}")
199
-
200
- _run_client "set", "#{self.class._quiet_option}"\
201
- "message-fg #{message_color}"
202
- _run_client "set", "#{self.class._quiet_option}"\
203
- "message-bg #{color}"
204
- _run_client "display-message", "'#{display_message}'"
281
+ Client.set(_all?, "display-time", display_time * 1000)
282
+ Client.set(_all?, "message-fg", message_color)
283
+ Client.set(_all?, "message-bg", color)
284
+ Client.display(_all?, "'#{display_message}'")
205
285
  end
206
286
 
207
287
  # Get the Tmux color for the notification type.
@@ -212,23 +292,14 @@ module Guard
212
292
  #
213
293
  def tmux_color(type, opts = {})
214
294
  type = type.to_sym
215
-
216
- opts[type] || DEFAULTS[type] || opts[:default] || DEFAULTS[:default]
295
+ opts[type] || Defaults[type] || Defaults.option(opts, :default)
217
296
  end
218
297
 
219
298
  # Notification starting, save the current Tmux settings
220
299
  # and quiet the Tmux output.
221
300
  #
222
301
  def self.turn_on
223
- unless @options_stored
224
- _reset_options_store
225
-
226
- _clients.each do |client|
227
- @options_store[client].merge!(_options_for_client(client))
228
- end
229
-
230
- @options_stored = true
231
- end
302
+ _start_session
232
303
  end
233
304
 
234
305
  # Notification stopping. Restore the previous Tmux state
@@ -236,103 +307,28 @@ module Guard
236
307
  # are unset) and unquiet the Tmux output.
237
308
  #
238
309
  def self.turn_off
239
- if @options_stored
240
- @options_store.each do |client, options|
241
- options.each do |key, value|
242
- args = [
243
- DEFAULTS[:client], "set", "-t",
244
- client, _quiet_option.strip
245
- ]
246
- args << "-u" unless value
247
- args << key
248
- args << value if value
249
- Sheller.run(args.join(" "))
250
- end
251
- end
252
- _reset_options_store
253
- end
254
- end
255
-
256
- def self.options_store
257
- @options_store ||= {}
310
+ _end_session
258
311
  end
259
312
 
260
313
  private
261
314
 
262
- def self._clients
263
- args = [DEFAULTS[:client], "list-clients", "-F", "'\#{client_tty}'"]
264
- ttys = Sheller.stdout(args.join(" "))
265
- ttys = ttys.split(/\n/)
266
-
267
- # if user is running 'tmux -C' remove this client from list
268
- ttys.delete("(null)")
269
-
270
- ttys
271
- end
272
-
273
- def self._options_for_client(client)
274
- options = {}
275
-
276
- lines = Sheller.stdout("#{DEFAULTS[:client]} show -t #{client}")
277
-
278
- lines.each_line do |line|
279
- option, _, setting = line.chomp.partition(" ")
280
- options[option] = setting
281
- end
282
-
283
- options
315
+ def self._start_session
316
+ fail "Already turned on!" if @@session
317
+ @@session = Session.new(self)
284
318
  end
285
319
 
286
- def _clients
287
- self.class._clients
288
- end
289
-
290
- def _run_client(cmd, args)
291
- default = DEFAULTS[:display_on_all_clients]
292
- all_clients = @options.fetch(:display_on_all_clients, default)
293
- clients = all_clients ? _clients : [nil]
294
- clients.each do |client|
295
- cmd_args = if client
296
- "#{_client_cmd_flag(cmd)} #{client.strip} #{args}"
297
- else
298
- args
299
- end
300
- Sheller.run("#{DEFAULTS[:client]} #{cmd} #{cmd_args}")
301
- end
302
- end
303
-
304
- def _client_cmd_flag(cmd)
305
- case cmd
306
- when "set", "set-option" then "-t"
307
- when "display-message" then "-c"
308
- end
309
- end
310
-
311
- # Reset the internal Tmux options store defaults.
312
- #
313
- def self._reset_options_store
314
- @options_stored = false
315
- @options_store = {}
316
-
317
- _clients.each do |client|
318
- @options_store[client] = {
319
- "status-left-bg" => nil,
320
- "status-right-bg" => nil,
321
- "status-left-fg" => nil,
322
- "status-right-fg" => nil,
323
- "message-bg" => nil,
324
- "message-fg" => nil,
325
- "display-time" => nil
326
- }
327
- end
320
+ def self._end_session
321
+ fail "Already turned off!" unless @@session || nil
322
+ @@session.close
323
+ @@session = nil
328
324
  end
329
325
 
330
- def self._tmux_version
331
- @@tmux_version ||= Float(Sheller.stdout("tmux -V")[/\d+\.\d+/])
326
+ def self._session
327
+ @@session
332
328
  end
333
329
 
334
- def self._quiet_option
335
- "-q " if _tmux_version >= 1.7
330
+ def _all?
331
+ Defaults.option(options, :display_on_all_clients)
336
332
  end
337
333
  end
338
334
  end