guard 1.8.3 → 2.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +68 -10
- data/README.md +54 -33
- data/lib/guard.rb +133 -483
- data/lib/guard/cli.rb +78 -82
- data/lib/guard/commander.rb +121 -0
- data/lib/guard/commands/all.rb +1 -1
- data/lib/guard/commands/reload.rb +1 -1
- data/lib/guard/deprecated_methods.rb +59 -0
- data/lib/guard/deprecator.rb +107 -0
- data/lib/guard/dsl.rb +143 -329
- data/lib/guard/dsl_describer.rb +101 -57
- data/lib/guard/group.rb +27 -8
- data/lib/guard/guard.rb +25 -150
- data/lib/guard/guardfile.rb +35 -85
- data/lib/guard/guardfile/evaluator.rb +245 -0
- data/lib/guard/guardfile/generator.rb +89 -0
- data/lib/guard/interactor.rb +147 -163
- data/lib/guard/notifier.rb +83 -137
- data/lib/guard/notifiers/base.rb +220 -0
- data/lib/guard/notifiers/emacs.rb +39 -37
- data/lib/guard/notifiers/file_notifier.rb +29 -25
- data/lib/guard/notifiers/gntp.rb +68 -75
- data/lib/guard/notifiers/growl.rb +49 -52
- data/lib/guard/notifiers/growl_notify.rb +51 -56
- data/lib/guard/notifiers/libnotify.rb +41 -48
- data/lib/guard/notifiers/notifysend.rb +58 -38
- data/lib/guard/notifiers/rb_notifu.rb +54 -54
- data/lib/guard/notifiers/terminal_notifier.rb +48 -36
- data/lib/guard/notifiers/terminal_title.rb +23 -19
- data/lib/guard/notifiers/tmux.rb +110 -93
- data/lib/guard/options.rb +21 -0
- data/lib/guard/plugin.rb +66 -0
- data/lib/guard/plugin/base.rb +178 -0
- data/lib/guard/plugin/hooker.rb +123 -0
- data/lib/guard/plugin_util.rb +158 -0
- data/lib/guard/rake_task.rb +47 -0
- data/lib/guard/runner.rb +62 -82
- data/lib/guard/setuper.rb +248 -0
- data/lib/guard/ui.rb +24 -80
- data/lib/guard/ui/colors.rb +60 -0
- data/lib/guard/version.rb +1 -2
- data/lib/guard/watcher.rb +30 -30
- data/man/guard.1 +4 -4
- data/man/guard.1.html +6 -4
- metadata +25 -11
- data/lib/guard/hook.rb +0 -120
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/tasklib'
|
5
|
+
|
6
|
+
require 'guard/cli'
|
7
|
+
|
8
|
+
module Guard
|
9
|
+
|
10
|
+
# Provides a method to define a Rake task that
|
11
|
+
# runs the Guard plugins.
|
12
|
+
#
|
13
|
+
class RakeTask < ::Rake::TaskLib
|
14
|
+
|
15
|
+
# Name of the main, top level task
|
16
|
+
attr_accessor :name
|
17
|
+
|
18
|
+
# CLI options
|
19
|
+
attr_accessor :options
|
20
|
+
|
21
|
+
# Initialize the Rake task
|
22
|
+
#
|
23
|
+
# @param [Symbol] name the name of the Rake task
|
24
|
+
# @param [String] options the CLI options
|
25
|
+
# @yield [Guard::RakeTask] the task
|
26
|
+
#
|
27
|
+
def initialize(name = :guard, options = '')
|
28
|
+
@name = name
|
29
|
+
@options = options
|
30
|
+
|
31
|
+
yield self if block_given?
|
32
|
+
|
33
|
+
desc "Starts Guard with options: '#{options}'"
|
34
|
+
task name => ["#{name}:start"]
|
35
|
+
|
36
|
+
namespace(name) do
|
37
|
+
|
38
|
+
desc "Starts Guard with options: '#{options}'"
|
39
|
+
task(:start) do
|
40
|
+
::Guard::CLI.start(options.split)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/guard/runner.rb
CHANGED
@@ -1,56 +1,24 @@
|
|
1
|
+
require 'lumberjack'
|
2
|
+
|
3
|
+
require 'guard/ui'
|
4
|
+
require 'guard/watcher'
|
5
|
+
|
1
6
|
module Guard
|
2
7
|
|
3
|
-
# The runner is responsible for running all methods defined on each
|
8
|
+
# The runner is responsible for running all methods defined on each plugin.
|
4
9
|
#
|
5
10
|
class Runner
|
6
11
|
|
7
|
-
|
8
|
-
require 'guard/ui'
|
9
|
-
require 'guard/watcher'
|
10
|
-
|
11
|
-
require 'lumberjack'
|
12
|
-
|
13
|
-
# Deprecation message for the `run_on_change` method
|
14
|
-
RUN_ON_CHANGE_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
|
15
|
-
Starting with Guard v1.1 the use of the 'run_on_change' method in the '%s' guard is deprecated.
|
16
|
-
|
17
|
-
Please consider replacing that method-call with 'run_on_changes' if the type of change
|
18
|
-
is not important for your usecase or using either 'run_on_modifications' or 'run_on_additions'
|
19
|
-
based on the type of the changes you want to handle.
|
20
|
-
|
21
|
-
For more information on how to update existing guards, please head over to:
|
22
|
-
https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
|
23
|
-
EOS
|
24
|
-
|
25
|
-
# Deprecation message for the `run_on_deletion` method
|
26
|
-
RUN_ON_DELETION_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
|
27
|
-
Starting with Guard v1.1 the use of the 'run_on_deletion' method in the '%s' guard is deprecated.
|
28
|
-
|
29
|
-
Please consider replacing that method-call with 'run_on_removals' for future proofing your code.
|
30
|
-
|
31
|
-
For more information on how to update existing guards, please head over to:
|
32
|
-
https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
|
33
|
-
EOS
|
34
|
-
|
35
|
-
# Displays a warning for each deprecated-method used is any registered guard.
|
36
|
-
#
|
37
|
-
def deprecation_warning
|
38
|
-
::Guard.guards.each do |guard|
|
39
|
-
::Guard::UI.deprecation(RUN_ON_CHANGE_DEPRECATION % guard.class.name) if guard.respond_to?(:run_on_change)
|
40
|
-
::Guard::UI.deprecation(RUN_ON_DELETION_DEPRECATION % guard.class.name) if guard.respond_to?(:run_on_deletion)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Runs a Guard-task on all registered guards.
|
12
|
+
# Runs a Guard-task on all registered plugins.
|
45
13
|
#
|
46
14
|
# @param [Symbol] task the task to run
|
47
15
|
# @param [Hash] scopes either the Guard plugin or the group to run the task on
|
48
16
|
#
|
49
17
|
# @see self.run_supervised_task
|
50
18
|
#
|
51
|
-
def run(task,
|
19
|
+
def run(task, scope = {})
|
52
20
|
Lumberjack.unit_of_work do
|
53
|
-
|
21
|
+
_scoped_plugins(scope) do |guard|
|
54
22
|
run_supervised_task(guard, task) if guard.respond_to?(task)
|
55
23
|
end
|
56
24
|
end
|
@@ -60,7 +28,7 @@ module Guard
|
|
60
28
|
ADDITION_TASKS = [:run_on_additions, :run_on_changes, :run_on_change]
|
61
29
|
REMOVAL_TASKS = [:run_on_removals, :run_on_changes, :run_on_deletion]
|
62
30
|
|
63
|
-
# Runs the appropriate tasks on all registered
|
31
|
+
# Runs the appropriate tasks on all registered plugins
|
64
32
|
# based on the passed changes.
|
65
33
|
#
|
66
34
|
# @param [Array<String>] modified the modified paths.
|
@@ -69,16 +37,16 @@ module Guard
|
|
69
37
|
#
|
70
38
|
def run_on_changes(modified, added, removed)
|
71
39
|
::Guard::UI.clearable
|
72
|
-
|
40
|
+
_scoped_plugins do |guard|
|
73
41
|
modified_paths = ::Guard::Watcher.match_files(guard, modified)
|
74
42
|
added_paths = ::Guard::Watcher.match_files(guard, added)
|
75
43
|
removed_paths = ::Guard::Watcher.match_files(guard, removed)
|
76
44
|
|
77
|
-
::Guard::UI.clear if
|
45
|
+
::Guard::UI.clear if _clearable?(guard, modified_paths, added_paths, removed_paths)
|
78
46
|
|
79
|
-
|
80
|
-
|
81
|
-
|
47
|
+
_run_first_task_found(guard, MODIFICATION_TASKS, modified_paths) unless modified_paths.empty?
|
48
|
+
_run_first_task_found(guard, ADDITION_TASKS, added_paths) unless added_paths.empty?
|
49
|
+
_run_first_task_found(guard, REMOVAL_TASKS, removed_paths) unless removed_paths.empty?
|
82
50
|
end
|
83
51
|
end
|
84
52
|
|
@@ -87,14 +55,14 @@ module Guard
|
|
87
55
|
# When the Group has `:halt_on_fail` disabled, we've to catch `:task_has_failed`
|
88
56
|
# here in order to avoid an uncaught throw error.
|
89
57
|
#
|
90
|
-
# @param [Guard::
|
58
|
+
# @param [Guard::Plugin] guard the Guard to execute
|
91
59
|
# @param [Symbol] task the task to run
|
92
60
|
# @param [Array] args the arguments for the task
|
93
61
|
# @raise [:task_has_failed] when task has failed
|
94
62
|
#
|
95
63
|
def run_supervised_task(guard, task, *args)
|
96
64
|
begin
|
97
|
-
catch
|
65
|
+
catch self.class.stopping_symbol_for(guard) do
|
98
66
|
guard.hook("#{ task }_begin", *args)
|
99
67
|
result = guard.send(task, *args)
|
100
68
|
guard.hook("#{ task }_end", result)
|
@@ -105,7 +73,7 @@ module Guard
|
|
105
73
|
::Guard::UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
|
106
74
|
"\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
|
107
75
|
|
108
|
-
::Guard.
|
76
|
+
::Guard.plugins.delete guard
|
109
77
|
::Guard::UI.info("\n#{ guard.class.name } has just been fired")
|
110
78
|
|
111
79
|
ex
|
@@ -117,28 +85,25 @@ module Guard
|
|
117
85
|
# @note If a Guard group is being run and it has the `:halt_on_fail`
|
118
86
|
# option set, this method returns :no_catch as it will be caught at the
|
119
87
|
# group level.
|
120
|
-
# @see .
|
88
|
+
# @see ._scoped_plugins
|
121
89
|
#
|
122
|
-
# @param [Guard::
|
90
|
+
# @param [Guard::Plugin] guard the Guard plugin to execute
|
123
91
|
# @return [Symbol] the symbol to catch
|
124
92
|
#
|
125
93
|
def self.stopping_symbol_for(guard)
|
126
|
-
|
127
|
-
|
128
|
-
group = ::Guard.groups(guard.group)
|
129
|
-
group.options.fetch(:halt_on_fail, false) ? :no_catch : :task_has_failed
|
94
|
+
guard.group.options[:halt_on_fail] ? :no_catch : :task_has_failed
|
130
95
|
end
|
131
96
|
|
132
|
-
|
97
|
+
private
|
133
98
|
|
134
99
|
# Tries to run the first implemented task by a given guard
|
135
100
|
# from a collection of tasks.
|
136
101
|
#
|
137
|
-
# @param [Guard::
|
102
|
+
# @param [Guard::Plugin] guard the Guard plugin to run the first found task on
|
138
103
|
# @param [Array<Symbol>] tasks the tasks to run the first among
|
139
104
|
# @param [Object] task_param the param to pass to each task
|
140
105
|
#
|
141
|
-
def
|
106
|
+
def _run_first_task_found(guard, tasks, task_param)
|
142
107
|
tasks.each do |task|
|
143
108
|
if guard.respond_to?(task)
|
144
109
|
run_supervised_task(guard, task, task_param)
|
@@ -161,16 +126,16 @@ module Guard
|
|
161
126
|
# @param [Hash] scopes hash with plugins or a groups scope
|
162
127
|
# @yield the task to run
|
163
128
|
#
|
164
|
-
def
|
165
|
-
if
|
166
|
-
|
129
|
+
def _scoped_plugins(scopes = {})
|
130
|
+
if plugins = _current_plugins_scope(scopes)
|
131
|
+
plugins.each do |guard|
|
167
132
|
yield(guard)
|
168
133
|
end
|
169
134
|
else
|
170
|
-
|
135
|
+
_current_groups_scope(scopes).each do |group|
|
171
136
|
current_plugin = nil
|
172
137
|
block_return = catch :task_has_failed do
|
173
|
-
::Guard.
|
138
|
+
::Guard.plugins(group: group.name).each do |guard|
|
174
139
|
current_plugin = guard
|
175
140
|
yield(guard)
|
176
141
|
end
|
@@ -186,12 +151,12 @@ module Guard
|
|
186
151
|
# Logic to know if the UI can be cleared or not in the run_on_changes method
|
187
152
|
# based on the guard and the changes.
|
188
153
|
#
|
189
|
-
# @param [Guard::
|
154
|
+
# @param [Guard::Plugin] guard the Guard plugin where run_on_changes is called
|
190
155
|
# @param [Array<String>] modified_paths the modified paths.
|
191
156
|
# @param [Array<String>] added_paths the added paths.
|
192
157
|
# @param [Array<String>] removed_paths the removed paths.
|
193
158
|
#
|
194
|
-
def
|
159
|
+
def _clearable?(guard, modified_paths, added_paths, removed_paths)
|
195
160
|
(MODIFICATION_TASKS.any? { |task| guard.respond_to?(task) } && !modified_paths.empty?) ||
|
196
161
|
(ADDITION_TASKS.any? { |task| guard.respond_to?(task) } && !added_paths.empty?) ||
|
197
162
|
(REMOVAL_TASKS.any? { |task| guard.respond_to?(task) } && !removed_paths.empty?)
|
@@ -202,15 +167,13 @@ module Guard
|
|
202
167
|
# If no plugins scope is found, then NO plugins are returned.
|
203
168
|
#
|
204
169
|
# @param [Hash] scopes hash with a local plugins or a groups scope
|
205
|
-
# @return [Array<Guard::
|
170
|
+
# @return [Array<Guard::Plugin>] the plugins to scope to
|
206
171
|
#
|
207
|
-
def
|
208
|
-
if
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
::Guard.scope[:plugins]
|
213
|
-
|
172
|
+
def _current_plugins_scope(scope)
|
173
|
+
if plugins = _find_non_empty_plugins_scope(scope)
|
174
|
+
Array(plugins).map do |plugin|
|
175
|
+
plugin.is_a?(Symbol) ? ::Guard.plugin(plugin) : plugin
|
176
|
+
end
|
214
177
|
else
|
215
178
|
nil
|
216
179
|
end
|
@@ -223,16 +186,33 @@ module Guard
|
|
223
186
|
# @param [Hash] scopes hash with a local plugins or a groups scope
|
224
187
|
# @return [Array<Guard::Group>] the groups to scope to
|
225
188
|
#
|
226
|
-
def
|
227
|
-
|
228
|
-
|
189
|
+
def _current_groups_scope(scope)
|
190
|
+
Array(_find_non_empty_groups_scope(scope)).map do |group|
|
191
|
+
group.is_a?(Symbol) ? ::Guard.group(group) : group
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Find the first non empty element in the given possibilities
|
196
|
+
#
|
197
|
+
def _find_non_empty_scope(type, local_scope, *additional_possibilities)
|
198
|
+
[
|
199
|
+
local_scope[:"#{type}s"],
|
200
|
+
local_scope[type.to_sym],
|
201
|
+
::Guard.scope[:"#{type}s"],
|
202
|
+
additional_possibilities.flatten
|
203
|
+
].compact.find { |a| !Array(a).empty? }
|
204
|
+
end
|
229
205
|
|
230
|
-
|
231
|
-
|
206
|
+
# Find the first non empty plugins scope
|
207
|
+
#
|
208
|
+
def _find_non_empty_plugins_scope(scope)
|
209
|
+
_find_non_empty_scope(:plugin, scope)
|
210
|
+
end
|
232
211
|
|
233
|
-
|
234
|
-
|
235
|
-
|
212
|
+
# Find the first non empty groups scope
|
213
|
+
#
|
214
|
+
def _find_non_empty_groups_scope(scope)
|
215
|
+
_find_non_empty_scope(:group, scope, ::Guard.groups)
|
236
216
|
end
|
237
217
|
end
|
238
218
|
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'listen'
|
3
|
+
require 'guard/options'
|
4
|
+
|
5
|
+
module Guard
|
6
|
+
|
7
|
+
module Setuper
|
8
|
+
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
clear: false,
|
11
|
+
notify: true,
|
12
|
+
debug: false,
|
13
|
+
group: [],
|
14
|
+
plugin: [],
|
15
|
+
watchdir: nil,
|
16
|
+
guardfile: nil,
|
17
|
+
no_interactions: false,
|
18
|
+
no_bundler_warning: false,
|
19
|
+
show_deprecations: false,
|
20
|
+
latency: nil,
|
21
|
+
force_polling: false
|
22
|
+
}
|
23
|
+
DEFAULT_GROUPS = [:default]
|
24
|
+
|
25
|
+
# Initializes the Guard singleton:
|
26
|
+
#
|
27
|
+
# * Initialize the internal Guard state;
|
28
|
+
# * Create the interactor when necessary for user interaction;
|
29
|
+
# * Select and initialize the file change listener.
|
30
|
+
#
|
31
|
+
# @option options [Boolean] clear if auto clear the UI should be done
|
32
|
+
# @option options [Boolean] notify if system notifications should be shown
|
33
|
+
# @option options [Boolean] debug if debug output should be shown
|
34
|
+
# @option options [Array<String>] group the list of groups to start
|
35
|
+
# @option options [Array<String>] watchdir the directories to watch
|
36
|
+
# @option options [String] guardfile the path to the Guardfile
|
37
|
+
#
|
38
|
+
# @return [Guard] the Guard singleton
|
39
|
+
#
|
40
|
+
def setup(opts = {})
|
41
|
+
@running = true
|
42
|
+
@lock = Mutex.new
|
43
|
+
@opts = opts
|
44
|
+
@watchdirs = [Dir.pwd]
|
45
|
+
@evaluator = ::Guard::Guardfile::Evaluator.new(opts)
|
46
|
+
@runner = ::Guard::Runner.new
|
47
|
+
|
48
|
+
if options.watchdir
|
49
|
+
# Ensure we have an array
|
50
|
+
@watchdirs = Array(options.watchdir).map { |dir| File.expand_path dir }
|
51
|
+
end
|
52
|
+
|
53
|
+
::Guard::UI.clear(force: true)
|
54
|
+
_setup_debug if options.debug
|
55
|
+
_setup_listener
|
56
|
+
_setup_signal_traps
|
57
|
+
|
58
|
+
reset_groups
|
59
|
+
reset_plugins
|
60
|
+
reset_scope
|
61
|
+
|
62
|
+
evaluate_guardfile
|
63
|
+
|
64
|
+
setup_scope(groups: options.group, plugins: options.plugin)
|
65
|
+
|
66
|
+
_setup_notifier
|
67
|
+
_setup_interactor
|
68
|
+
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
# Lazy initializer for Guard's options hash
|
73
|
+
#
|
74
|
+
def options
|
75
|
+
@options ||= ::Guard::Options.new(@opts || {}, DEFAULT_OPTIONS)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Clear Guard's options hash
|
79
|
+
#
|
80
|
+
def clear_options
|
81
|
+
@options = nil
|
82
|
+
end
|
83
|
+
|
84
|
+
# Initializes the groups array with the default group(s).
|
85
|
+
#
|
86
|
+
# @see DEFAULT_GROUPS
|
87
|
+
#
|
88
|
+
def reset_groups
|
89
|
+
@groups = DEFAULT_GROUPS.map { |name| Group.new(name) }
|
90
|
+
end
|
91
|
+
|
92
|
+
# Initializes the plugins array to an empty array.
|
93
|
+
#
|
94
|
+
# @see Guard.plugins
|
95
|
+
#
|
96
|
+
def reset_plugins
|
97
|
+
@plugins = []
|
98
|
+
end
|
99
|
+
|
100
|
+
# Initializes the scope hash to `{ groups: [], plugins: [] }`.
|
101
|
+
#
|
102
|
+
# @see Guard.setup_scope
|
103
|
+
#
|
104
|
+
def reset_scope
|
105
|
+
@scope = { groups: [], plugins: [] }
|
106
|
+
end
|
107
|
+
|
108
|
+
# Stores the scopes defined by the user via the `--group` / `-g` option (to run
|
109
|
+
# only a specific group) or the `--plugin` / `-P` option (to run only a
|
110
|
+
# specific plugin).
|
111
|
+
#
|
112
|
+
# @see CLI#start
|
113
|
+
# @see Dsl#scope
|
114
|
+
#
|
115
|
+
def setup_scope(new_scope)
|
116
|
+
if new_scope[:groups] && new_scope[:groups].any?
|
117
|
+
scope[:groups] = new_scope[:groups].map { |group| ::Guard.add_group(group) }
|
118
|
+
end
|
119
|
+
|
120
|
+
if new_scope[:plugins] && new_scope[:plugins].any?
|
121
|
+
scope[:plugins] = new_scope[:plugins].map { |plugin| ::Guard.plugin(plugin) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Evaluates the Guardfile content. It displays an error message if no
|
126
|
+
# Guard plugins are instantiated after the Guardfile evaluation.
|
127
|
+
#
|
128
|
+
# @see Guard::Guardfile::Evaluator#evaluate_guardfile
|
129
|
+
#
|
130
|
+
def evaluate_guardfile
|
131
|
+
evaluator.evaluate_guardfile
|
132
|
+
::Guard::UI.error 'No plugins found in Guardfile, please add at least one.' if plugins.empty?
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
# Sets up various debug behaviors:
|
138
|
+
#
|
139
|
+
# * Abort threads on exception;
|
140
|
+
# * Set the logging level to `:debug`;
|
141
|
+
# * Modify the system and ` methods to log themselves before being executed
|
142
|
+
#
|
143
|
+
# @see #_debug_command_execution
|
144
|
+
#
|
145
|
+
def _setup_debug
|
146
|
+
Thread.abort_on_exception = true
|
147
|
+
::Guard::UI.options.level = :debug
|
148
|
+
_debug_command_execution
|
149
|
+
end
|
150
|
+
|
151
|
+
# Initializes the listener and registers a callback for changes.
|
152
|
+
#
|
153
|
+
def _setup_listener
|
154
|
+
listener_callback = lambda do |modified, added, removed|
|
155
|
+
# Convert to relative paths (respective to the watchdir it came from)
|
156
|
+
@watchdirs.each do |watchdir|
|
157
|
+
[modified, added, removed].each do |paths|
|
158
|
+
paths.map! do |path|
|
159
|
+
if path.start_with? watchdir
|
160
|
+
path.sub "#{watchdir}#{File::SEPARATOR}", ''
|
161
|
+
else
|
162
|
+
path
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
evaluator.reevaluate_guardfile if ::Guard::Watcher.match_guardfile?(modified)
|
168
|
+
|
169
|
+
within_preserved_state do
|
170
|
+
runner.run_on_changes(modified, added, removed)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
listener_options = {}
|
175
|
+
%w[latency force_polling].each do |option|
|
176
|
+
listener_options[option.to_sym] = options.send(option) if options.send(option)
|
177
|
+
end
|
178
|
+
|
179
|
+
listen_args = @watchdirs + [listener_options]
|
180
|
+
@listener = Listen.to(*listen_args).change(&listener_callback)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Sets up traps to catch signals used to control Guard.
|
184
|
+
#
|
185
|
+
# Currently two signals are caught:
|
186
|
+
# - `USR1` which pauses listening to changes.
|
187
|
+
# - `USR2` which resumes listening to changes.
|
188
|
+
# - 'INT' which is delegated to Pry if active, otherwise stops Guard.
|
189
|
+
#
|
190
|
+
def _setup_signal_traps
|
191
|
+
unless defined?(JRUBY_VERSION)
|
192
|
+
if Signal.list.keys.include?('USR1')
|
193
|
+
Signal.trap('USR1') { ::Guard.pause unless listener.paused? }
|
194
|
+
end
|
195
|
+
|
196
|
+
if Signal.list.keys.include?('USR2')
|
197
|
+
Signal.trap('USR2') { ::Guard.pause if listener.paused? }
|
198
|
+
end
|
199
|
+
|
200
|
+
if Signal.list.keys.include?('INT')
|
201
|
+
Signal.trap('INT') do
|
202
|
+
if interactor && interactor.thread
|
203
|
+
interactor.thread.raise(Interrupt)
|
204
|
+
else
|
205
|
+
::Guard.stop
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Enables or disables the notifier based on user's configurations.
|
213
|
+
#
|
214
|
+
def _setup_notifier
|
215
|
+
if options.notify && ENV['GUARD_NOTIFY'] != 'false'
|
216
|
+
::Guard::Notifier.turn_on
|
217
|
+
else
|
218
|
+
::Guard::Notifier.turn_off
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Initializes the interactor unless the user has specified not to.
|
223
|
+
#
|
224
|
+
def _setup_interactor
|
225
|
+
unless options.no_interactions || !::Guard::Interactor.enabled
|
226
|
+
@interactor = ::Guard::Interactor.new
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Adds a command logger in debug mode. This wraps common command
|
231
|
+
# execution functions and logs the executed command before execution.
|
232
|
+
#
|
233
|
+
def _debug_command_execution
|
234
|
+
Kernel.send(:alias_method, :original_system, :system)
|
235
|
+
Kernel.send(:define_method, :system) do |command, *args|
|
236
|
+
::Guard::UI.debug "Command execution: #{ command } #{ args.join(' ') }"
|
237
|
+
Kernel.send :original_system, command, *args
|
238
|
+
end
|
239
|
+
|
240
|
+
Kernel.send(:alias_method, :original_backtick, :'`')
|
241
|
+
Kernel.send(:define_method, :'`') do |command|
|
242
|
+
::Guard::UI.debug "Command execution: #{ command }"
|
243
|
+
Kernel.send :original_backtick, command
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
end
|