guard 1.4.0 → 2.18.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 +7 -0
- data/CHANGELOG.md +1 -677
- data/LICENSE +4 -2
- data/README.md +91 -753
- data/bin/_guard-core +11 -0
- data/bin/guard +108 -3
- data/lib/guard/aruba_adapter.rb +59 -0
- data/lib/guard/cli/environments/bundler.rb +22 -0
- data/lib/guard/cli/environments/evaluate_only.rb +35 -0
- data/lib/guard/cli/environments/valid.rb +69 -0
- data/lib/guard/cli.rb +129 -128
- data/lib/guard/commander.rb +104 -0
- data/lib/guard/commands/all.rb +37 -0
- data/lib/guard/commands/change.rb +31 -0
- data/lib/guard/commands/notification.rb +26 -0
- data/lib/guard/commands/pause.rb +29 -0
- data/lib/guard/commands/reload.rb +36 -0
- data/lib/guard/commands/scope.rb +38 -0
- data/lib/guard/commands/show.rb +24 -0
- data/lib/guard/config.rb +18 -0
- data/lib/guard/deprecated/dsl.rb +45 -0
- data/lib/guard/deprecated/evaluator.rb +39 -0
- data/lib/guard/deprecated/guard.rb +328 -0
- data/lib/guard/deprecated/guardfile.rb +84 -0
- data/lib/guard/deprecated/watcher.rb +27 -0
- data/lib/guard/dsl.rb +332 -363
- data/lib/guard/dsl_describer.rb +132 -122
- data/lib/guard/dsl_reader.rb +51 -0
- data/lib/guard/group.rb +34 -14
- data/lib/guard/guardfile/evaluator.rb +232 -0
- data/lib/guard/guardfile/generator.rb +128 -0
- data/lib/guard/guardfile.rb +24 -60
- data/lib/guard/interactor.rb +31 -255
- data/lib/guard/internals/debugging.rb +68 -0
- data/lib/guard/internals/groups.rb +40 -0
- data/lib/guard/internals/helpers.rb +13 -0
- data/lib/guard/internals/plugins.rb +53 -0
- data/lib/guard/internals/queue.rb +51 -0
- data/lib/guard/internals/scope.rb +121 -0
- data/lib/guard/internals/session.rb +180 -0
- data/lib/guard/internals/state.rb +25 -0
- data/lib/guard/internals/tracing.rb +33 -0
- data/lib/guard/internals/traps.rb +10 -0
- data/lib/guard/jobs/base.rb +21 -0
- data/lib/guard/jobs/pry_wrapper.rb +336 -0
- data/lib/guard/jobs/sleep.rb +26 -0
- data/lib/guard/notifier.rb +46 -212
- data/lib/guard/options.rb +22 -0
- data/lib/guard/plugin.rb +303 -0
- data/lib/guard/plugin_util.rb +191 -0
- data/lib/guard/rake_task.rb +42 -0
- data/lib/guard/runner.rb +80 -140
- data/lib/guard/templates/Guardfile +14 -0
- data/lib/guard/terminal.rb +13 -0
- data/lib/guard/ui/colors.rb +56 -0
- data/lib/guard/ui/config.rb +70 -0
- data/lib/guard/ui/logger.rb +30 -0
- data/lib/guard/ui.rb +163 -128
- data/lib/guard/version.rb +1 -2
- data/lib/guard/watcher/pattern/deprecated_regexp.rb +45 -0
- data/lib/guard/watcher/pattern/match_result.rb +18 -0
- data/lib/guard/watcher/pattern/matcher.rb +33 -0
- data/lib/guard/watcher/pattern/pathname_path.rb +15 -0
- data/lib/guard/watcher/pattern/simple_path.rb +23 -0
- data/lib/guard/watcher/pattern.rb +24 -0
- data/lib/guard/watcher.rb +52 -95
- data/lib/guard.rb +108 -376
- data/lib/tasks/releaser.rb +116 -0
- data/man/guard.1 +12 -9
- data/man/guard.1.html +18 -12
- metadata +148 -77
- data/images/guard.png +0 -0
- data/lib/guard/guard.rb +0 -156
- data/lib/guard/hook.rb +0 -120
- data/lib/guard/interactors/coolline.rb +0 -64
- data/lib/guard/interactors/helpers/completion.rb +0 -32
- data/lib/guard/interactors/helpers/terminal.rb +0 -46
- data/lib/guard/interactors/readline.rb +0 -94
- data/lib/guard/interactors/simple.rb +0 -19
- data/lib/guard/notifiers/emacs.rb +0 -69
- data/lib/guard/notifiers/gntp.rb +0 -118
- data/lib/guard/notifiers/growl.rb +0 -99
- data/lib/guard/notifiers/growl_notify.rb +0 -92
- data/lib/guard/notifiers/libnotify.rb +0 -96
- data/lib/guard/notifiers/notifysend.rb +0 -84
- data/lib/guard/notifiers/rb_notifu.rb +0 -102
- data/lib/guard/notifiers/terminal_notifier.rb +0 -66
- data/lib/guard/notifiers/tmux.rb +0 -69
- data/lib/guard/version.rbc +0 -130
@@ -0,0 +1,336 @@
|
|
1
|
+
require "guard/commands/all"
|
2
|
+
require "guard/commands/change"
|
3
|
+
require "guard/commands/notification"
|
4
|
+
require "guard/commands/pause"
|
5
|
+
require "guard/commands/reload"
|
6
|
+
require "guard/commands/scope"
|
7
|
+
require "guard/commands/show"
|
8
|
+
require "shellany/sheller"
|
9
|
+
|
10
|
+
require "guard/jobs/base"
|
11
|
+
|
12
|
+
module Guard
|
13
|
+
module Jobs
|
14
|
+
class TerminalSettings
|
15
|
+
def initialize
|
16
|
+
@settings = nil
|
17
|
+
@works = Shellany::Sheller.run("hash", "stty") || false
|
18
|
+
end
|
19
|
+
|
20
|
+
def restore
|
21
|
+
return unless configurable? && @settings
|
22
|
+
Shellany::Sheller.run("stty #{ @setting } 2>#{IO::NULL}")
|
23
|
+
end
|
24
|
+
|
25
|
+
def save
|
26
|
+
return unless configurable?
|
27
|
+
@settings = Shellany::Sheller.stdout("stty -g 2>#{IO::NULL}").chomp
|
28
|
+
end
|
29
|
+
|
30
|
+
def echo
|
31
|
+
return unless configurable?
|
32
|
+
Shellany::Sheller.run("stty echo 2>#{IO::NULL}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def configurable?
|
36
|
+
@works
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class PryWrapper < Base
|
41
|
+
# The default Ruby script to configure Guard Pry if the option `:guard_rc`
|
42
|
+
# is not defined.
|
43
|
+
|
44
|
+
GUARD_RC = if ENV["XDG_CONFIG_HOME"] && File.exist?(ENV["XDG_CONFIG_HOME"] + "/guard/guardrc")
|
45
|
+
ENV["XDG_CONFIG_HOME"] + "/guard/guardrc"
|
46
|
+
else
|
47
|
+
"~/.guardrc"
|
48
|
+
end
|
49
|
+
|
50
|
+
# The default Guard Pry history file if the option `:history_file` is not
|
51
|
+
# defined.
|
52
|
+
|
53
|
+
HISTORY_FILE = if ENV["XDG_DATA_HOME"] && File.exist?(ENV["XDG_DATA_HOME"] + "/guard/history")
|
54
|
+
ENV["XDG_DATA_HOME"] + "/guard/history"
|
55
|
+
else
|
56
|
+
"~/.guard_history"
|
57
|
+
end
|
58
|
+
|
59
|
+
# List of shortcuts for each interactor command
|
60
|
+
SHORTCUTS = {
|
61
|
+
help: "h",
|
62
|
+
all: "a",
|
63
|
+
reload: "r",
|
64
|
+
change: "c",
|
65
|
+
show: "s",
|
66
|
+
scope: "o",
|
67
|
+
notification: "n",
|
68
|
+
pause: "p",
|
69
|
+
exit: "e",
|
70
|
+
quit: "q"
|
71
|
+
}
|
72
|
+
|
73
|
+
def initialize(options)
|
74
|
+
@mutex = Mutex.new
|
75
|
+
@thread = nil
|
76
|
+
@terminal_settings = TerminalSettings.new
|
77
|
+
|
78
|
+
_setup(options)
|
79
|
+
end
|
80
|
+
|
81
|
+
def foreground
|
82
|
+
UI.debug "Start interactor"
|
83
|
+
@terminal_settings.save
|
84
|
+
|
85
|
+
_switch_to_pry
|
86
|
+
# TODO: rename :stopped to continue
|
87
|
+
_killed? ? :stopped : :exit
|
88
|
+
ensure
|
89
|
+
UI.reset_line
|
90
|
+
UI.debug "Interactor was stopped or killed"
|
91
|
+
@terminal_settings.restore
|
92
|
+
end
|
93
|
+
|
94
|
+
def background
|
95
|
+
_kill_pry
|
96
|
+
end
|
97
|
+
|
98
|
+
def handle_interrupt
|
99
|
+
thread = @thread
|
100
|
+
fail Interrupt unless thread
|
101
|
+
thread.raise Interrupt
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
attr_reader :thread
|
107
|
+
|
108
|
+
def _pry_config
|
109
|
+
Pry.config
|
110
|
+
end
|
111
|
+
|
112
|
+
def _pry_commands
|
113
|
+
Pry.commands
|
114
|
+
end
|
115
|
+
|
116
|
+
def _switch_to_pry
|
117
|
+
th = nil
|
118
|
+
@mutex.synchronize do
|
119
|
+
unless @thread
|
120
|
+
@thread = Thread.new { Pry.start }
|
121
|
+
@thread.join(0.5) # give pry a chance to start
|
122
|
+
th = @thread
|
123
|
+
end
|
124
|
+
end
|
125
|
+
# check for nill, because it might've been killed between the mutex and
|
126
|
+
# now
|
127
|
+
th.join unless th.nil?
|
128
|
+
end
|
129
|
+
|
130
|
+
def _killed?
|
131
|
+
th = nil
|
132
|
+
@mutex.synchronize { th = @thread }
|
133
|
+
th.nil?
|
134
|
+
end
|
135
|
+
|
136
|
+
def _kill_pry
|
137
|
+
@mutex.synchronize do
|
138
|
+
unless @thread.nil?
|
139
|
+
@thread.kill
|
140
|
+
@thread = nil # set to nil so we know we were killed
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def _setup(options)
|
146
|
+
_pry_config.should_load_rc = false
|
147
|
+
_pry_config.should_load_local_rc = false
|
148
|
+
|
149
|
+
_configure_history_file(options[:history_file] || HISTORY_FILE)
|
150
|
+
_add_hooks(options)
|
151
|
+
|
152
|
+
Commands::All.import
|
153
|
+
Commands::Change.import
|
154
|
+
Commands::Notification.import
|
155
|
+
Commands::Pause.import
|
156
|
+
Commands::Reload.import
|
157
|
+
Commands::Show.import
|
158
|
+
Commands::Scope.import
|
159
|
+
|
160
|
+
_setup_commands
|
161
|
+
_configure_prompt
|
162
|
+
end
|
163
|
+
|
164
|
+
def _configure_history_file(history_file)
|
165
|
+
history_file_path = File.expand_path(history_file)
|
166
|
+
|
167
|
+
# Pry >= 0.13
|
168
|
+
if _pry_config.respond_to?(:history_file=)
|
169
|
+
_pry_config.history_file = history_file_path
|
170
|
+
else
|
171
|
+
_pry_config.history.file = history_file_path
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Add Pry hooks:
|
176
|
+
#
|
177
|
+
# * Load `~/.guardrc` within each new Pry session.
|
178
|
+
# * Load project's `.guardrc` within each new Pry session.
|
179
|
+
# * Restore prompt after each evaluation.
|
180
|
+
#
|
181
|
+
def _add_hooks(options)
|
182
|
+
_add_load_guard_rc_hook(Pathname(options[:guard_rc] || GUARD_RC))
|
183
|
+
_add_load_project_guard_rc_hook(Pathname.pwd + ".guardrc")
|
184
|
+
_add_restore_visibility_hook if @terminal_settings.configurable?
|
185
|
+
end
|
186
|
+
|
187
|
+
# Add a `when_started` hook that loads a global .guardrc if it exists.
|
188
|
+
#
|
189
|
+
def _add_load_guard_rc_hook(guard_rc)
|
190
|
+
_pry_config.hooks.add_hook :when_started, :load_guard_rc do
|
191
|
+
guard_rc.expand_path.tap { |p| load p if p.exist? }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Add a `when_started` hook that loads a project .guardrc if it exists.
|
196
|
+
#
|
197
|
+
def _add_load_project_guard_rc_hook(guard_rc)
|
198
|
+
_pry_config.hooks.add_hook :when_started, :load_project_guard_rc do
|
199
|
+
load guard_rc if guard_rc.exist?
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Add a `after_eval` hook that restores visibility after a command is
|
204
|
+
# eval.
|
205
|
+
def _add_restore_visibility_hook
|
206
|
+
_pry_config.hooks.add_hook :after_eval, :restore_visibility do
|
207
|
+
@terminal_settings.echo
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def _setup_commands
|
212
|
+
_replace_reset_command
|
213
|
+
_create_run_all_command
|
214
|
+
_create_command_aliases
|
215
|
+
_create_guard_commands
|
216
|
+
_create_group_commands
|
217
|
+
end
|
218
|
+
|
219
|
+
# Replaces reset defined inside of Pry with a reset that
|
220
|
+
# instead restarts guard.
|
221
|
+
#
|
222
|
+
def _replace_reset_command
|
223
|
+
_pry_commands.command "reset", "Reset the Guard to a clean state." do
|
224
|
+
output.puts "Guard reset."
|
225
|
+
exec "guard"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Creates a command that triggers the `:run_all` action
|
230
|
+
# when the command is empty (just pressing enter on the
|
231
|
+
# beginning of a line).
|
232
|
+
#
|
233
|
+
def _create_run_all_command
|
234
|
+
_pry_commands.block_command(/^$/, "Hit enter to run all") do
|
235
|
+
Pry.run_command "all"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Creates command aliases for the commands: `help`, `reload`, `change`,
|
240
|
+
# `scope`, `notification`, `pause`, `exit` and `quit`, which will be the
|
241
|
+
# first letter of the command.
|
242
|
+
#
|
243
|
+
def _create_command_aliases
|
244
|
+
SHORTCUTS.each do |command, shortcut|
|
245
|
+
_pry_commands.alias_command shortcut, command.to_s
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Create a shorthand command to run the `:run_all`
|
250
|
+
# action on a specific Guard plugin. For example,
|
251
|
+
# when guard-rspec is available, then a command
|
252
|
+
# `rspec` is created that runs `all rspec`.
|
253
|
+
#
|
254
|
+
def _create_guard_commands
|
255
|
+
Guard.state.session.plugins.all.each do |guard_plugin|
|
256
|
+
cmd = "Run all #{guard_plugin.title}"
|
257
|
+
_pry_commands.create_command guard_plugin.name, cmd do
|
258
|
+
group "Guard"
|
259
|
+
|
260
|
+
def process
|
261
|
+
Pry.run_command "all #{ match }"
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# Create a shorthand command to run the `:run_all`
|
268
|
+
# action on a specific Guard group. For example,
|
269
|
+
# when you have a group `frontend`, then a command
|
270
|
+
# `frontend` is created that runs `all frontend`.
|
271
|
+
#
|
272
|
+
def _create_group_commands
|
273
|
+
Guard.state.session.groups.all.each do |group|
|
274
|
+
next if group.name == :default
|
275
|
+
|
276
|
+
cmd = "Run all #{group.title}"
|
277
|
+
_pry_commands.create_command group.name.to_s, cmd do
|
278
|
+
group "Guard"
|
279
|
+
|
280
|
+
def process
|
281
|
+
Pry.run_command "all #{ match }"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# Configures the pry prompt to see `guard` instead of
|
288
|
+
# `pry`.
|
289
|
+
#
|
290
|
+
def _configure_prompt
|
291
|
+
prompt_procs = [_prompt(">"), _prompt("*")]
|
292
|
+
prompt =
|
293
|
+
if Pry::Prompt.is_a?(Class)
|
294
|
+
Pry::Prompt.new("Guard", "Guard Pry prompt", prompt_procs)
|
295
|
+
else
|
296
|
+
prompt_procs
|
297
|
+
end
|
298
|
+
|
299
|
+
_pry_config.prompt = prompt
|
300
|
+
end
|
301
|
+
|
302
|
+
# Returns the plugins scope, or the groups scope ready for display in the
|
303
|
+
# prompt.
|
304
|
+
#
|
305
|
+
def _scope_for_prompt
|
306
|
+
titles = Guard.state.scope.titles.join(",")
|
307
|
+
titles == "all" ? "" : titles + " "
|
308
|
+
end
|
309
|
+
|
310
|
+
# Returns a proc that will return itself a string ending with the given
|
311
|
+
# `ending_char` when called.
|
312
|
+
#
|
313
|
+
def _prompt(ending_char)
|
314
|
+
proc do |target_self, nest_level, pry|
|
315
|
+
process = Guard.listener.paused? ? "pause" : "guard"
|
316
|
+
level = ":#{ nest_level }" unless nest_level.zero?
|
317
|
+
|
318
|
+
"[#{ _history(pry) }] #{ _scope_for_prompt }#{ process }"\
|
319
|
+
"(#{ _clip_name(target_self) })#{ level }#{ ending_char } "
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def _clip_name(target)
|
324
|
+
Pry.view_clip(target)
|
325
|
+
end
|
326
|
+
|
327
|
+
def _history(pry)
|
328
|
+
if pry.respond_to?(:input_ring)
|
329
|
+
pry.input_ring.size
|
330
|
+
else
|
331
|
+
pry.input_array.size
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "guard/jobs/base"
|
2
|
+
require "guard/ui"
|
3
|
+
|
4
|
+
module Guard
|
5
|
+
module Jobs
|
6
|
+
class Sleep < Base
|
7
|
+
def foreground
|
8
|
+
UI.debug "Guards jobs done. Sleeping..."
|
9
|
+
sleep
|
10
|
+
UI.debug "Sleep interrupted by events."
|
11
|
+
:stopped
|
12
|
+
rescue Interrupt
|
13
|
+
UI.debug "Sleep interrupted by user."
|
14
|
+
:exit
|
15
|
+
end
|
16
|
+
|
17
|
+
def background
|
18
|
+
Thread.main.wakeup
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle_interrupt
|
22
|
+
Thread.main.raise Interrupt
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/guard/notifier.rb
CHANGED
@@ -1,237 +1,71 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require 'pathname'
|
1
|
+
require "notiffany/notifier"
|
2
|
+
require "guard/ui"
|
4
3
|
|
5
4
|
module Guard
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# * Tmux
|
18
|
-
#
|
19
|
-
# Please see the documentation of each notifier for more information about the requirements
|
20
|
-
# and configuration possibilities.
|
21
|
-
#
|
22
|
-
# Guard knows four different notification types:
|
23
|
-
#
|
24
|
-
# * success
|
25
|
-
# * pending
|
26
|
-
# * failed
|
27
|
-
# * notify
|
28
|
-
#
|
29
|
-
# The notification type selection is based on the image option that is
|
30
|
-
# sent to {#notify}. Each image type has its own notification type, and
|
31
|
-
# notifications with custom images goes all sent as type `notify`. The
|
32
|
-
# `gntp` and `growl_notify` notifiers are able to register these types
|
33
|
-
# at Growl and allows customization of each notification type.
|
34
|
-
#
|
35
|
-
# Guard can be configured to make use of more than one notifier at once, @see Guard::Dsl
|
36
|
-
#
|
37
|
-
module Notifier
|
38
|
-
|
39
|
-
require 'guard'
|
40
|
-
require 'guard/ui'
|
41
|
-
require 'guard/notifiers/gntp'
|
42
|
-
require 'guard/notifiers/growl'
|
43
|
-
require 'guard/notifiers/growl_notify'
|
44
|
-
require 'guard/notifiers/libnotify'
|
45
|
-
require 'guard/notifiers/notifysend'
|
46
|
-
require 'guard/notifiers/rb_notifu'
|
47
|
-
require 'guard/notifiers/emacs'
|
48
|
-
require 'guard/notifiers/terminal_notifier'
|
49
|
-
require 'guard/notifiers/tmux'
|
50
|
-
|
51
|
-
extend self
|
52
|
-
|
53
|
-
# List of available notifiers. It needs to be a nested hash instead of
|
54
|
-
# a simpler Hash, because it maintains its order on Ruby 1.8.7 also.
|
55
|
-
NOTIFIERS = [
|
56
|
-
[:growl, ::Guard::Notifier::Growl],
|
57
|
-
[:gntp, ::Guard::Notifier::GNTP],
|
58
|
-
[:growl_notify, ::Guard::Notifier::GrowlNotify],
|
59
|
-
[:libnotify, ::Guard::Notifier::Libnotify],
|
60
|
-
[:notifysend, ::Guard::Notifier::NotifySend],
|
61
|
-
[:notifu, ::Guard::Notifier::Notifu],
|
62
|
-
[:emacs, ::Guard::Notifier::Emacs],
|
63
|
-
[:terminal_notifier, ::Guard::Notifier::TerminalNotifier],
|
64
|
-
[:tmux, ::Guard::Notifier::Tmux]
|
65
|
-
]
|
66
|
-
|
67
|
-
# Get the available notifications.
|
68
|
-
#
|
69
|
-
# @return [Hash] the notifications
|
70
|
-
#
|
71
|
-
def notifications
|
72
|
-
ENV['GUARD_NOTIFICATIONS'] ? YAML::load(ENV['GUARD_NOTIFICATIONS']) : []
|
73
|
-
end
|
74
|
-
|
75
|
-
# Set the available notifications.
|
76
|
-
#
|
77
|
-
# @param [Array<Hash>] notifications the notifications
|
78
|
-
#
|
79
|
-
def notifications=(notifications)
|
80
|
-
ENV['GUARD_NOTIFICATIONS'] = YAML::dump(notifications)
|
5
|
+
class Notifier
|
6
|
+
def self.connect(options = {})
|
7
|
+
@notifier ||= nil
|
8
|
+
fail "Already connected!" if @notifier
|
9
|
+
begin
|
10
|
+
opts = options.merge(namespace: "guard", logger: UI)
|
11
|
+
@notifier = Notiffany.connect(opts)
|
12
|
+
rescue Notiffany::Notifier::Detected::UnknownNotifier => e
|
13
|
+
UI.error "Failed to setup notification: #{e.message}"
|
14
|
+
fail
|
15
|
+
end
|
81
16
|
end
|
82
17
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
ENV['GUARD_NOTIFICATIONS'] = nil
|
18
|
+
def self.disconnect
|
19
|
+
@notifier && @notifier.disconnect
|
20
|
+
@notifier = nil
|
87
21
|
end
|
88
22
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
#
|
93
|
-
def turn_on
|
94
|
-
auto_detect_notification if notifications.empty? && (!::Guard.options || ::Guard.options[:notify])
|
95
|
-
|
96
|
-
if notifications.empty?
|
97
|
-
ENV['GUARD_NOTIFY'] = 'false'
|
98
|
-
else
|
99
|
-
notifications.each do |notification|
|
100
|
-
::Guard::UI.info "Guard uses #{ get_notifier_module(notification[:name]).to_s.split('::').last } to send notifications."
|
101
|
-
end
|
23
|
+
DEPRECATED_IMPLICIT_CONNECT = "Calling Notiffany::Notifier.notify()"\
|
24
|
+
" without a prior Notifier.connect() is"\
|
25
|
+
" deprecated"
|
102
26
|
|
103
|
-
|
27
|
+
def self.notify(message, options = {})
|
28
|
+
unless @notifier
|
29
|
+
# TODO: reenable again?
|
30
|
+
# UI.deprecation(DEPRECTED_IMPLICIT_CONNECT)
|
31
|
+
connect(notify: true)
|
104
32
|
end
|
105
|
-
end
|
106
33
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
34
|
+
@notifier.notify(message, options)
|
35
|
+
rescue RuntimeError => e
|
36
|
+
UI.error "Notification failed for #{@notifier.class.name}: #{e.message}"
|
37
|
+
UI.debug e.backtrace.join("\n")
|
111
38
|
end
|
112
39
|
|
113
|
-
|
114
|
-
|
115
|
-
# @return [Boolean] whether the notifications are on
|
116
|
-
#
|
117
|
-
def enabled?
|
118
|
-
ENV['GUARD_NOTIFY'] == 'true'
|
40
|
+
def self.turn_on
|
41
|
+
@notifier.turn_on
|
119
42
|
end
|
120
43
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
# @param [Hash] options the notifier options
|
126
|
-
# @return [Boolean] if the notification could be added
|
127
|
-
#
|
128
|
-
def add_notification(name, options = { }, silent = false)
|
129
|
-
return turn_off if name == :off
|
130
|
-
|
131
|
-
notifier = get_notifier_module(name)
|
132
|
-
|
133
|
-
if notifier && notifier.available?(silent)
|
134
|
-
self.notifications = notifications << { :name => name, :options => options }
|
135
|
-
true
|
136
|
-
else
|
137
|
-
false
|
44
|
+
def self.toggle
|
45
|
+
unless @notifier.enabled?
|
46
|
+
UI.error NOTIFICATIONS_DISABLED
|
47
|
+
return
|
138
48
|
end
|
139
|
-
end
|
140
|
-
|
141
|
-
# Show a system notification with all configured notifiers.
|
142
|
-
#
|
143
|
-
# @param [String] message the message to show
|
144
|
-
# @option options [Symbol, String] image the image symbol or path to an image
|
145
|
-
# @option options [String] title the notification title
|
146
|
-
#
|
147
|
-
def notify(message, options = { })
|
148
|
-
if enabled?
|
149
|
-
type = notification_type(options[:image] || :success)
|
150
|
-
image = image_path(options.delete(:image) || :success)
|
151
|
-
title = options.delete(:title) || 'Guard'
|
152
49
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
::Guard::UI.error "Error sending notification with #{ notification[:name] }: #{ e.message }"
|
158
|
-
end
|
159
|
-
end
|
50
|
+
if @notifier.active?
|
51
|
+
UI.info "Turn off notifications"
|
52
|
+
@notifier.turn_off
|
53
|
+
return
|
160
54
|
end
|
161
|
-
end
|
162
|
-
|
163
|
-
private
|
164
55
|
|
165
|
-
|
166
|
-
#
|
167
|
-
# @param [Symbol] the notifier name
|
168
|
-
# @return [Module] the notifier module
|
169
|
-
#
|
170
|
-
def get_notifier_module(name)
|
171
|
-
notifier = NOTIFIERS.detect { |n| n.first == name }
|
172
|
-
notifier ? notifier.last : notifier
|
56
|
+
@notifier.turn_on
|
173
57
|
end
|
174
58
|
|
175
|
-
#
|
176
|
-
|
177
|
-
|
178
|
-
#
|
179
|
-
def auto_detect_notification
|
180
|
-
available = NOTIFIERS.map { |n| n.first }.any? { |notifier| add_notification(notifier, { }, true) }
|
181
|
-
::Guard::UI.info('Guard could not detect any of the supported notification libraries.') unless available
|
59
|
+
# Used by dsl describer
|
60
|
+
def self.supported
|
61
|
+
Notiffany::Notifier::SUPPORTED.inject(:merge)
|
182
62
|
end
|
183
63
|
|
184
|
-
#
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
# - pending
|
189
|
-
# - success
|
190
|
-
#
|
191
|
-
# If the image is not a known symbol, it will be returned unmodified.
|
192
|
-
#
|
193
|
-
# @param [Symbol, String] image the image symbol or path to an image
|
194
|
-
# @return [String] the image path
|
195
|
-
#
|
196
|
-
def image_path(image)
|
197
|
-
case image
|
198
|
-
when :failed
|
199
|
-
images_path.join('failed.png').to_s
|
200
|
-
when :pending
|
201
|
-
images_path.join('pending.png').to_s
|
202
|
-
when :success
|
203
|
-
images_path.join('success.png').to_s
|
204
|
-
else
|
205
|
-
image
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Paths where all Guard images are located
|
210
|
-
#
|
211
|
-
# @return [Pathname] the path to the images directory
|
212
|
-
#
|
213
|
-
def images_path
|
214
|
-
@images_path ||= Pathname.new(File.dirname(__FILE__)).join('../../images')
|
215
|
-
end
|
216
|
-
|
217
|
-
# Get the notification type depending on the
|
218
|
-
# image that has been selected for the notification.
|
219
|
-
#
|
220
|
-
# @param [Symbol, String] image the image symbol or path to an image
|
221
|
-
# @return [String] the notification type
|
222
|
-
#
|
223
|
-
def notification_type(image)
|
224
|
-
case image
|
225
|
-
when :failed
|
226
|
-
'failed'
|
227
|
-
when :pending
|
228
|
-
'pending'
|
229
|
-
when :success
|
230
|
-
'success'
|
231
|
-
else
|
232
|
-
'notify'
|
64
|
+
# Used by dsl describer
|
65
|
+
def self.detected
|
66
|
+
@notifier.available.map do |mod|
|
67
|
+
{ name: mod.name.to_sym, options: mod.options }
|
233
68
|
end
|
234
69
|
end
|
235
70
|
end
|
236
|
-
|
237
71
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "thor/core_ext/hash_with_indifferent_access"
|
2
|
+
|
3
|
+
module Guard
|
4
|
+
# A class that holds options. Can be instantiated with default options.
|
5
|
+
#
|
6
|
+
class Options < Thor::CoreExt::HashWithIndifferentAccess
|
7
|
+
# Initializes an Guard::Options object. `default_opts` is merged into
|
8
|
+
# `opts`.
|
9
|
+
#
|
10
|
+
# @param [Hash] opts the options
|
11
|
+
# @param [Hash] default_opts the default options
|
12
|
+
#
|
13
|
+
def initialize(opts = {}, default_opts = {})
|
14
|
+
super(default_opts.merge(opts || {}))
|
15
|
+
end
|
16
|
+
|
17
|
+
# workaround for: https://github.com/erikhuda/thor/issues/504
|
18
|
+
def fetch(name)
|
19
|
+
super(name.to_s)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|