Class: Ibex::Watch::Runner
- Inherits:
-
Object
- Object
- Ibex::Watch::Runner
- Defined in:
- lib/ibex/watch/runner.rb,
sig/ibex/watch/runner.rbs
Overview
Polls source fingerprints, debounces changes, and publishes stable builds.
Constant Summary collapse
- DEFAULT_INTERVAL =
0.25- DEFAULT_DEBOUNCE =
0.05
Instance Method Summary collapse
- #build_once(before) ⇒ [ SourceSnapshot, bool ]
- #debounce(changed) ⇒ SourceSnapshot
- #failed_build(before, error) ⇒ [ SourceSnapshot, bool ]
-
#initialize(paths:, build:, publish:, failure_paths:, stderr:, clock:, sleeper:, iteration_hook:, interval: DEFAULT_INTERVAL, debounce: DEFAULT_DEBOUNCE) ⇒ Runner
constructor
rubocop:disable Layout/LineLength.
- #normalize_paths(paths) ⇒ Array[String]
- #report_failure(error) ⇒ void
- #report_failure_once(error, snapshot) ⇒ void
- #run ⇒ Integer
- #stop_status(event) ⇒ Integer?
- #wait_for_change(snapshot) ⇒ SourceSnapshot
- #with_signal_handlers { ... } ⇒ Integer
Constructor Details
#initialize(paths:, build:, publish:, failure_paths:, stderr:, clock:, sleeper:, iteration_hook:, interval: DEFAULT_INTERVAL, debounce: DEFAULT_DEBOUNCE) ⇒ Runner
rubocop:disable Layout/LineLength
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/ibex/watch/runner.rb', line 13 def initialize(paths:, build:, publish:, failure_paths:, stderr:, clock:, sleeper:, iteration_hook:, interval: DEFAULT_INTERVAL, debounce: DEFAULT_DEBOUNCE) @fixed_paths = normalize_paths(paths) @successful_paths = [] #: Array[String] @paths = @fixed_paths @build = build @publish = publish @failure_paths = failure_paths @stderr = stderr @clock = clock @sleeper = sleeper @iteration_hook = iteration_hook @interval = interval @debounce = debounce @signal_status = nil #: Integer? @requested_status = nil #: Integer? @last_failure_message = nil #: String? @last_failure_snapshot = nil #: SourceSnapshot? @iteration = 0 end |
Instance Method Details
#build_once(before) ⇒ [ SourceSnapshot, bool ]
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/ibex/watch/runner.rb', line 65 def build_once(before) @iteration += 1 result = @build.call @paths = normalize_paths(@fixed_paths + result.source_paths + result.attempted_paths) rendered = SourceSnapshot.new(@paths) return [rendered, true] unless rendered.unchanged_since?(before) return [rendered, false] if @signal_status @publish.call(result, rendered, -> { @signal_status.nil? }) @last_failure_message = nil @last_failure_snapshot = nil @successful_paths = @paths - @fixed_paths published = SourceSnapshot.new(@paths) [published, published != rendered] rescue GenerationTransaction::SourceChanged [SourceSnapshot.new(@paths), true] rescue GenerationTransaction::Error => e raise if e.rollback_failed failed_build(before, e) rescue Ibex::Error, SystemCallError, SystemStackError => e failed_build(before, e) end |
#debounce(changed) ⇒ SourceSnapshot
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/ibex/watch/runner.rb', line 106 def debounce(changed) loop do @clock.call @sleeper.call(@debounce) return changed if @signal_status settled = SourceSnapshot.new(@paths) return settled if settled == changed changed = settled end end |
#failed_build(before, error) ⇒ [ SourceSnapshot, bool ]
125 126 127 128 129 130 131 132 |
# File 'lib/ibex/watch/runner.rb', line 125 def failed_build(before, error) previous_paths = @paths @paths = normalize_paths(@fixed_paths + @successful_paths + @failure_paths.call) current = SourceSnapshot.new(@paths) retry_build = @paths != previous_paths || !current.unchanged_since?(before) report_failure_once(error, current) [current, retry_build] end |
#normalize_paths(paths) ⇒ Array[String]
155 156 157 |
# File 'lib/ibex/watch/runner.rb', line 155 def normalize_paths(paths) paths.map { |path| File.(path) }.uniq.sort end |
#report_failure(error) ⇒ void
This method returns an undefined value.
120 121 122 |
# File 'lib/ibex/watch/runner.rb', line 120 def report_failure(error) @stderr.puts(error.) end |
#report_failure_once(error, snapshot) ⇒ void
This method returns an undefined value.
135 136 137 138 139 140 |
# File 'lib/ibex/watch/runner.rb', line 135 def report_failure_once(error, snapshot) duplicate = @last_failure_message == error. && @last_failure_snapshot == snapshot report_failure(error) unless duplicate @last_failure_message = error. @last_failure_snapshot = snapshot end |
#run ⇒ Integer
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/ibex/watch/runner.rb', line 36 def run with_signal_handlers do snapshot = SourceSnapshot.new(@paths) loop do status = stop_status(:before_build) return status if status snapshot, retry_build = build_once(snapshot) status = stop_status(:after_build) return status if status if retry_build snapshot = debounce(snapshot) status = @signal_status || @requested_status return status if status next end snapshot = wait_for_change(snapshot) status = @signal_status || @requested_status return status if status end end end |
#stop_status(event) ⇒ Integer?
143 144 145 146 147 148 149 150 151 152 |
# File 'lib/ibex/watch/runner.rb', line 143 def stop_status(event) return @signal_status if @signal_status result = @iteration_hook.call(event, @iteration, @paths.dup) @requested_status = result if result.is_a?(Integer) @requested_status = 0 if result == :stop return @requested_status if @requested_status nil end |
#wait_for_change(snapshot) ⇒ SourceSnapshot
90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/ibex/watch/runner.rb', line 90 def wait_for_change(snapshot) loop do @sleeper.call(@interval) return snapshot if @signal_status status = stop_status(:poll) return snapshot if status changed = SourceSnapshot.new(@paths) next if changed == snapshot return debounce(changed) end end |
#with_signal_handlers { ... } ⇒ Integer
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/ibex/watch/runner.rb', line 160 def with_signal_handlers previous = {} #: Hash[String, untyped] if Thread.current == Thread.main previous["INT"] = Signal.trap("INT") { @signal_status = 130 } previous["TERM"] = Signal.trap("TERM") { @signal_status = 143 } end yield ensure previous&.each { |signal, handler| Signal.trap(signal, handler) } end |