diff --git a/.rubocop.yml b/.rubocop.yml index 286ec110..c918e5c4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -12,6 +12,7 @@ AllCops: SuggestExtensions: false Exclude: - dev/**/* + - spec/fixtures/**/* # The `ConfigValidator` class is a DSL, let it be Metrics/AbcSize: { Exclude: [lib/bashly/config_validator.rb] } @@ -43,3 +44,8 @@ RSpec/ExampleLength: - 'spec/bashly/integration/**/*' - 'spec/bashly/libraries/render*' - 'spec/bashly/script/command_spec.rb' + +# Allow `puts` in some specs +RSpec/Output: + Exclude: + - spec/bashly/integration/**/* diff --git a/lib/bashly/libraries/settings/settings.yml b/lib/bashly/libraries/settings/settings.yml index 92af221b..d5e82d43 100644 --- a/lib/bashly/libraries/settings/settings.yml +++ b/lib/bashly/libraries/settings/settings.yml @@ -159,6 +159,17 @@ enable_env_var_names_array: always enable_sourcing: development +#------------------------------------------------------------------------------- +# DEVELOPER OPTIONS +#------------------------------------------------------------------------------- + +# When true, use filesystem evented watching instead of polling +watch_evented: false + +# File change detection latency (seconds) +watch_latency: 1.0 + + #------------------------------------------------------------------------------- # SCRIPTING OPTIONS #------------------------------------------------------------------------------- diff --git a/lib/bashly/settings.rb b/lib/bashly/settings.rb index 6bb0b354..6dd018f7 100644 --- a/lib/bashly/settings.rb +++ b/lib/bashly/settings.rb @@ -28,9 +28,15 @@ class << self :target_dir, :usage_colors, :var_aliases, + :watch_evented, + :watch_latency, :word_wrap ) + def all_lib_dirs + @all_lib_dirs = [full_lib_dir] + extra_lib_dirs + end + def commands_dir @commands_dir ||= get :commands_dir end @@ -89,6 +95,17 @@ def env=(value) @env = value&.to_sym end + def extra_lib_dirs + @extra_lib_dirs ||= begin + dirs = get :extra_lib_dirs + case dirs + when Array then dirs + when String then dirs.split(',').map(&:strip) + else [] + end + end + end + def formatter @formatter ||= get :formatter end @@ -109,21 +126,6 @@ def lib_dir @lib_dir ||= get :lib_dir end - def extra_lib_dirs - @extra_lib_dirs ||= begin - dirs = get :extra_lib_dirs - case dirs - when Array then dirs - when String then dirs.split(',').map(&:strip) - else [] - end - end - end - - def all_lib_dirs - @all_lib_dirs = [full_lib_dir] + extra_lib_dirs - end - def partials_extension @partials_extension ||= get :partials_extension end @@ -174,6 +176,14 @@ def var_aliases @var_aliases ||= get :var_aliases end + def watch_evented + @watch_evented ||= get :watch_evented + end + + def watch_latency + @watch_latency ||= get :watch_latency + end + def word_wrap @word_wrap ||= get :word_wrap end diff --git a/lib/bashly/watch.rb b/lib/bashly/watch.rb index a33ba2de..3fdcc6c0 100644 --- a/lib/bashly/watch.rb +++ b/lib/bashly/watch.rb @@ -5,13 +5,8 @@ module Bashly class Watch attr_reader :dirs, :options - DEFAULT_OPTIONS = { - force_polling: true, - latency: 1.0, - }.freeze - def initialize(*dirs, **options) - @options = DEFAULT_OPTIONS.merge(options).freeze + @options = default_options.merge(options).freeze @dirs = dirs.empty? ? ['.'] : dirs end @@ -24,10 +19,20 @@ def on_change(&) private - def build_listener - listen.to(*dirs, **options) do |modified, added, removed| - yield changes(modified, added, removed) - end + def default_options + { + force_polling: force_polling?, + latency: latency, + } + end + + def force_polling? + !Settings.watch_evented + end + + def latency + value = Settings.watch_latency.to_f + value.positive? ? value : 0.1 end def start(&block) @@ -42,16 +47,22 @@ def stop @listener = nil end - def changes(modified, added, removed) - { modified:, added:, removed: } - end - def wait sleep rescue ::Interrupt => e raise Bashly::Interrupt, cause: e end + def build_listener + listen.to(*dirs, **options) do |modified, added, removed| + yield changes(modified, added, removed) + end + end + + def changes(modified, added, removed) + { modified:, added:, removed: } + end + def listen = Listen end end diff --git a/schemas/settings.json b/schemas/settings.json index 1dfc8f55..e05c0852 100644 --- a/schemas/settings.json +++ b/schemas/settings.json @@ -289,6 +289,18 @@ } ] }, + "watch_evented": { + "title": "watch evented", + "description": "Whether to use evented file system watch instead of the default polling\nhttps://bashly.dev/usage/settings/#watch_evented", + "type": "boolean", + "default": false + }, + "watch_latency": { + "title": "watch latency", + "description": "The latency in seconds for the file system changes watcher\nhttps://bashly.dev/usage/settings/#watch_latency", + "type": "number", + "default": 1 + }, "usage_colors": { "title": "usage colors", "description": "Enable and configure colorful output for --help\nhttps://bashly.dev/usage/settings/#usage_colors", diff --git a/spec/bashly/watch_spec.rb b/spec/bashly/watch_spec.rb index c295e577..233681ab 100644 --- a/spec/bashly/watch_spec.rb +++ b/spec/bashly/watch_spec.rb @@ -45,11 +45,14 @@ let(:options) { { latency: 0.25 } } it 'passes them through to Listen' do - expect(listen).to receive(:to).with( - 'lib', - 'spec', - **described_class::DEFAULT_OPTIONS, **options - ) + expect(listen).to receive(:to) do |*passed_dirs, **passed_options| + expect(passed_dirs).to eq(dirs) + expect(passed_options[:latency]).to eq(options[:latency]) + expect(passed_options).to have_key(:force_polling) + + # instead of rspec's 'and_return' which cannot be used with a block + listener + end subject.on_change { |_| nil } end diff --git a/support/schema/settings.yml b/support/schema/settings.yml index c1845a7e..8edbf466 100644 --- a/support/schema/settings.yml +++ b/support/schema/settings.yml @@ -237,6 +237,20 @@ properties: The name of the environment variable (case sensitive) that, if set, will reveal private commands, flags and environment variables https://bashly.dev/usage/settings/#private_reveal_key oneOf: *optional_string + watch_evented: + title: watch evented + description: |- + Whether to use evented file system watch instead of the default polling + https://bashly.dev/usage/settings/#watch_evented + type: boolean + default: false + watch_latency: + title: watch latency + description: |- + The latency in seconds for the file system changes watcher + https://bashly.dev/usage/settings/#watch_latency + type: number + default: 1.0 usage_colors: title: usage colors description: |-