Skip to content

Commit 372ceed

Browse files
authored
Merge pull request #694 from bashly-framework/add/evented-watch-support
Add support for evented file watcher
2 parents 9e5a61f + 3d7cac5 commit 372ceed

File tree

7 files changed

+101
-34
lines changed

7 files changed

+101
-34
lines changed

.rubocop.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ AllCops:
1212
SuggestExtensions: false
1313
Exclude:
1414
- dev/**/*
15+
- spec/fixtures/**/*
1516

1617
# The `ConfigValidator` class is a DSL, let it be
1718
Metrics/AbcSize: { Exclude: [lib/bashly/config_validator.rb] }
@@ -43,3 +44,8 @@ RSpec/ExampleLength:
4344
- 'spec/bashly/integration/**/*'
4445
- 'spec/bashly/libraries/render*'
4546
- 'spec/bashly/script/command_spec.rb'
47+
48+
# Allow `puts` in some specs
49+
RSpec/Output:
50+
Exclude:
51+
- spec/bashly/integration/**/*

lib/bashly/libraries/settings/settings.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,17 @@ enable_env_var_names_array: always
159159
enable_sourcing: development
160160

161161

162+
#-------------------------------------------------------------------------------
163+
# DEVELOPER OPTIONS
164+
#-------------------------------------------------------------------------------
165+
166+
# When true, use filesystem evented watching instead of polling
167+
watch_evented: false
168+
169+
# File change detection latency (seconds)
170+
watch_latency: 1.0
171+
172+
162173
#-------------------------------------------------------------------------------
163174
# SCRIPTING OPTIONS
164175
#-------------------------------------------------------------------------------

lib/bashly/settings.rb

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,15 @@ class << self
2828
:target_dir,
2929
:usage_colors,
3030
:var_aliases,
31+
:watch_evented,
32+
:watch_latency,
3133
:word_wrap
3234
)
3335

36+
def all_lib_dirs
37+
@all_lib_dirs = [full_lib_dir] + extra_lib_dirs
38+
end
39+
3440
def commands_dir
3541
@commands_dir ||= get :commands_dir
3642
end
@@ -89,6 +95,17 @@ def env=(value)
8995
@env = value&.to_sym
9096
end
9197

98+
def extra_lib_dirs
99+
@extra_lib_dirs ||= begin
100+
dirs = get :extra_lib_dirs
101+
case dirs
102+
when Array then dirs
103+
when String then dirs.split(',').map(&:strip)
104+
else []
105+
end
106+
end
107+
end
108+
92109
def formatter
93110
@formatter ||= get :formatter
94111
end
@@ -109,21 +126,6 @@ def lib_dir
109126
@lib_dir ||= get :lib_dir
110127
end
111128

112-
def extra_lib_dirs
113-
@extra_lib_dirs ||= begin
114-
dirs = get :extra_lib_dirs
115-
case dirs
116-
when Array then dirs
117-
when String then dirs.split(',').map(&:strip)
118-
else []
119-
end
120-
end
121-
end
122-
123-
def all_lib_dirs
124-
@all_lib_dirs = [full_lib_dir] + extra_lib_dirs
125-
end
126-
127129
def partials_extension
128130
@partials_extension ||= get :partials_extension
129131
end
@@ -174,6 +176,14 @@ def var_aliases
174176
@var_aliases ||= get :var_aliases
175177
end
176178

179+
def watch_evented
180+
@watch_evented ||= get :watch_evented
181+
end
182+
183+
def watch_latency
184+
@watch_latency ||= get :watch_latency
185+
end
186+
177187
def word_wrap
178188
@word_wrap ||= get :word_wrap
179189
end

lib/bashly/watch.rb

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@ module Bashly
55
class Watch
66
attr_reader :dirs, :options
77

8-
DEFAULT_OPTIONS = {
9-
force_polling: true,
10-
latency: 1.0,
11-
}.freeze
12-
138
def initialize(*dirs, **options)
14-
@options = DEFAULT_OPTIONS.merge(options).freeze
9+
@options = default_options.merge(options).freeze
1510
@dirs = dirs.empty? ? ['.'] : dirs
1611
end
1712

@@ -24,10 +19,20 @@ def on_change(&)
2419

2520
private
2621

27-
def build_listener
28-
listen.to(*dirs, **options) do |modified, added, removed|
29-
yield changes(modified, added, removed)
30-
end
22+
def default_options
23+
{
24+
force_polling: force_polling?,
25+
latency: latency,
26+
}
27+
end
28+
29+
def force_polling?
30+
!Settings.watch_evented
31+
end
32+
33+
def latency
34+
value = Settings.watch_latency.to_f
35+
value.positive? ? value : 0.1
3136
end
3237

3338
def start(&block)
@@ -42,16 +47,22 @@ def stop
4247
@listener = nil
4348
end
4449

45-
def changes(modified, added, removed)
46-
{ modified:, added:, removed: }
47-
end
48-
4950
def wait
5051
sleep
5152
rescue ::Interrupt => e
5253
raise Bashly::Interrupt, cause: e
5354
end
5455

56+
def build_listener
57+
listen.to(*dirs, **options) do |modified, added, removed|
58+
yield changes(modified, added, removed)
59+
end
60+
end
61+
62+
def changes(modified, added, removed)
63+
{ modified:, added:, removed: }
64+
end
65+
5566
def listen = Listen
5667
end
5768
end

schemas/settings.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,18 @@
289289
}
290290
]
291291
},
292+
"watch_evented": {
293+
"title": "watch evented",
294+
"description": "Whether to use evented file system watch instead of the default polling\nhttps://bashly.dev/usage/settings/#watch_evented",
295+
"type": "boolean",
296+
"default": false
297+
},
298+
"watch_latency": {
299+
"title": "watch latency",
300+
"description": "The latency in seconds for the file system changes watcher\nhttps://bashly.dev/usage/settings/#watch_latency",
301+
"type": "number",
302+
"default": 1
303+
},
292304
"usage_colors": {
293305
"title": "usage colors",
294306
"description": "Enable and configure colorful output for --help\nhttps://bashly.dev/usage/settings/#usage_colors",

spec/bashly/watch_spec.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,14 @@
4545
let(:options) { { latency: 0.25 } }
4646

4747
it 'passes them through to Listen' do
48-
expect(listen).to receive(:to).with(
49-
'lib',
50-
'spec',
51-
**described_class::DEFAULT_OPTIONS, **options
52-
)
48+
expect(listen).to receive(:to) do |*passed_dirs, **passed_options|
49+
expect(passed_dirs).to eq(dirs)
50+
expect(passed_options[:latency]).to eq(options[:latency])
51+
expect(passed_options).to have_key(:force_polling)
52+
53+
# instead of rspec's 'and_return' which cannot be used with a block
54+
listener
55+
end
5356

5457
subject.on_change { |_| nil }
5558
end

support/schema/settings.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,20 @@ properties:
237237
The name of the environment variable (case sensitive) that, if set, will reveal private commands, flags and environment variables
238238
https://bashly.dev/usage/settings/#private_reveal_key
239239
oneOf: *optional_string
240+
watch_evented:
241+
title: watch evented
242+
description: |-
243+
Whether to use evented file system watch instead of the default polling
244+
https://bashly.dev/usage/settings/#watch_evented
245+
type: boolean
246+
default: false
247+
watch_latency:
248+
title: watch latency
249+
description: |-
250+
The latency in seconds for the file system changes watcher
251+
https://bashly.dev/usage/settings/#watch_latency
252+
type: number
253+
default: 1.0
240254
usage_colors:
241255
title: usage colors
242256
description: |-

0 commit comments

Comments
 (0)