ruby-progress 1.3.4 → 1.3.6

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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env sh
2
- # Example: start a worm daemon, send a job, wait for result, then stop.
2
+ # Example: start a worm in background mode, do some work, then stop it with a message.
3
3
  # This script assumes you're running from the project root and have a working
4
4
  # `bin/prg` script in the repository.
5
5
 
@@ -8,18 +8,16 @@ set -eu
8
8
  PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
9
9
  PRG_BIN="$PROJECT_ROOT/bin/prg"
10
10
 
11
- echo "Starting worm daemon (named 'example')..."
12
- # prg detaches in daemon mode so no & needed
13
- $PRG_BIN worm --daemon-as example --message "Example daemon"
11
+ echo "Starting worm in background mode (named 'example')..."
12
+ # Use --no-detach to keep it visible in the current terminal for demos
13
+ $PRG_BIN worm --daemon-as example --no-detach --message "Example running..." &
14
14
 
15
- sleep 0.2
15
+ sleep 0.5
16
16
 
17
- echo "Sending job and waiting for result..."
18
- $PRG_BIN job send --daemon-name example --command "echo hello; sleep 0.1" --wait --timeout 10
19
-
20
- sleep 0.1
17
+ echo "Doing some work..."
18
+ sleep 2
21
19
 
22
20
  echo "Stopping daemon with success message..."
23
- $PRG_BIN worm --stop-success "Example finished" --stop-checkmark --daemon-name example
21
+ $PRG_BIN job send --daemon-name example --message "Example finished" --checkmark
24
22
 
25
23
  echo "Done."
@@ -5,7 +5,7 @@ require 'optparse'
5
5
  module RubyProgress
6
6
  module FillCLI
7
7
  # Option parsing extracted to reduce module length in FillCLI
8
- # rubocop:disable Metrics/AbcSize, Metrics/BlockLength
8
+ # rubocop:disable Metrics/AbcSize
9
9
  module Options
10
10
  # rubocop :disable Metrics/MethodLength
11
11
  def self.parse_cli_options
@@ -146,10 +146,6 @@ module RubyProgress
146
146
  options[:daemon_name] = name
147
147
  end
148
148
 
149
- opts.on('--no-detach', 'When used with --daemon/--daemon-as: run background child but do not fully detach from the terminal') do
150
- options[:no_detach] = true
151
- end
152
-
153
149
  opts.on('--pid-file FILE', 'PID file location (default: /tmp/ruby-progress/fill.pid)') do |file|
154
150
  options[:pid_file] = file
155
151
  end
@@ -266,6 +262,6 @@ module RubyProgress
266
262
  opts.to_s
267
263
  end
268
264
  end
269
- # rubocop:enable Metrics/AbcSize, Metrics/BlockLength
265
+ # rubocop:enable Metrics/AbcSize
270
266
  end
271
267
  end
@@ -1,159 +1,198 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # CLI: prg job
4
-
5
- # Provides the `prg job send` helper to enqueue commands into a daemon's
6
- # job directory. This file contains a minimal implementation used by tests.
3
+ # CLI: prg job [subcommand]
4
+ # Send control messages to backgrounded progress indicators.
7
5
 
8
6
  require 'optparse'
9
7
  require 'json'
10
- require 'securerandom'
11
8
  require 'fileutils'
12
9
  require_relative '../daemon'
13
10
 
14
- # Job CLI helpers
11
+ # JobCLI - sends control messages to backgrounded progress indicators
15
12
  #
16
- # Exposed as `prg job send`.
13
+ # Usage:
14
+ # prg job stop --daemon-name mytask [--message "Done!"] [--checkmark]
15
+ # prg job advance --daemon-name mytask [--amount 10]
16
+ # prg job status --daemon-name mytask
17
17
  module JobCLI
18
- # JobCLI
19
- #
20
- # Small CLI module that exposes `prg job send` for enqueuing jobs into the
21
- # daemon job directory. This is intentionally minimal: it writes a single
22
- # JSON file atomically and optionally waits for a result file created by
23
- # the daemon's job processor.
24
- # Simple CLI for submitting jobs to a running daemon job directory.
25
- # Usage: prg job send --pid-file /tmp/... --command "echo hi" [--wait]
26
- class Options
27
- def self.parse(argv)
28
- options = { wait: false }
29
- opt = OptionParser.new do |o|
30
- o.banner = 'Usage: prg job send [options]'
31
- o.on('--pid-file PATH', 'Path to daemon pid file') do |v|
32
- options[:pid_file] = v
33
- end
34
- o.on('--daemon-name NAME', 'Daemon name (maps to /tmp/ruby-progress/NAME.pid)') do |v|
35
- options[:daemon_name] = v
36
- end
37
- o.on('--command CMD', 'Command to run') do |v|
38
- options[:command] = v
39
- end
40
- o.on('--stdin', 'Read command from stdin (overrides --command)') do
41
- options[:stdin] = true
42
- end
43
- o.on('--advance', 'Send an advance action (no value)') do
44
- options[:action] = 'advance'
45
- end
46
- o.on('--percent N', Integer, 'Send a percent action with value N') do |v|
47
- options[:action] = 'percent'
48
- options[:value] = v
49
- end
50
- o.on('--complete', 'Send a complete action (no value)') do
51
- options[:action] = 'complete'
52
- end
53
- o.on('--cancel', 'Send a cancel action (no value)') do
54
- options[:action] = 'cancel'
55
- end
56
- o.on('--action ACTION', 'Send a custom action name') do |v|
57
- options[:action] = v
58
- end
59
- o.on('--value VAL', 'Value for the action (string or number)') do |v|
60
- options[:value] = v
61
- end
62
- o.on('--wait', 'Wait for result file and print it') do
63
- options[:wait] = true
64
- end
65
- o.on('--timeout SECONDS', Integer, 'Timeout seconds for wait') do |v|
66
- options[:timeout] = v
67
- end
68
- end
18
+ def self.run(argv = ARGV)
19
+ if argv.empty?
20
+ print_help
21
+ exit 1
22
+ end
69
23
 
70
- rest = opt.parse(argv)
71
- options[:command] ||= rest.join(' ') unless rest.empty?
72
- options
24
+ subcommand = argv.shift
25
+
26
+ case subcommand
27
+ when 'stop'
28
+ stop(argv)
29
+ when 'advance'
30
+ advance(argv)
31
+ when 'status'
32
+ status(argv)
33
+ when 'send'
34
+ # Backward compatibility: 'send' is now 'stop'
35
+ warn "Warning: 'prg job send' is deprecated. Use 'prg job stop' instead."
36
+ stop(argv)
37
+ when '--help', '-h'
38
+ print_help
39
+ else
40
+ warn "Error: Unknown subcommand '#{subcommand}'"
41
+ print_help
42
+ exit 1
73
43
  end
74
44
  end
75
45
 
76
- def self.send(argv = ARGV)
77
- opts = Options.parse(argv)
78
-
79
- # Resolve pid file
80
- pid_file = if opts[:pid_file]
81
- opts[:pid_file]
82
- elsif opts[:daemon_name]
83
- "/tmp/ruby-progress/#{opts[:daemon_name]}.pid"
84
- else
85
- RubyProgress::Daemon.default_pid_file
86
- end
87
-
88
- job_dir = RubyProgress::Daemon.job_dir_for_pid(pid_file)
89
- FileUtils.mkdir_p(job_dir)
90
-
91
- cmd = if opts[:stdin]
92
- $stdin.read
93
- else
94
- opts[:command]
95
- end
96
-
97
- is_action = !opts[:action].nil? && opts[:action] != false
98
-
99
- if is_action
100
- if cmd && !cmd.strip.empty?
101
- warn 'Cannot specify both --command/--stdin and an action flag'
102
- exit 1
103
- end
46
+ def self.print_help
47
+ puts 'Usage: prg job [subcommand] [options]'
48
+ puts
49
+ puts 'Subcommands:'
50
+ puts ' stop Stop a running progress indicator'
51
+ puts ' advance Advance a fill progress bar'
52
+ puts ' status Check status of a running indicator'
53
+ puts
54
+ puts 'Common Options:'
55
+ puts ' --daemon-name NAME Name of the daemon to control'
56
+ puts ' --pid-file PATH Path to daemon PID file'
57
+ puts
58
+ puts 'Examples:'
59
+ puts ' prg job stop --daemon-name mytask --message "Complete!"'
60
+ puts ' prg job advance --daemon-name mybar --amount 10'
61
+ puts ' prg job status --daemon-name mytask'
62
+ end
63
+
64
+ def self.resolve_pid_file(opts)
65
+ if opts[:pid_file]
66
+ opts[:pid_file]
67
+ elsif opts[:daemon_name]
68
+ "/tmp/ruby-progress/#{opts[:daemon_name]}.pid"
104
69
  else
105
- unless cmd && !cmd.strip.empty?
106
- warn 'No command specified. Use --command, --stdin, or pass an action flag.'
107
- exit 1
108
- end
70
+ RubyProgress::Daemon.default_pid_file
71
+ end
72
+ end
73
+
74
+ def self.stop(argv)
75
+ opts = parse_stop_options(argv)
76
+ pid_file = resolve_pid_file(opts)
77
+
78
+ unless File.exist?(pid_file)
79
+ warn "PID file #{pid_file} not found. Is the daemon running?"
80
+ exit 1
109
81
  end
110
82
 
111
- job_id = SecureRandom.uuid
112
- tmp = File.join(job_dir, "#{job_id}.json.tmp")
113
- final = File.join(job_dir, "#{job_id}.json")
114
-
115
- payload = build_payload(opts, job_id, cmd)
116
-
117
- File.write(tmp, JSON.dump(payload))
118
- FileUtils.mv(tmp, final)
119
-
120
- if opts[:wait]
121
- timeout = opts[:timeout] || 10
122
- start = Time.now
123
- result_path = "#{final}.processing.result"
124
- loop do
125
- if File.exist?(result_path)
126
- puts File.read(result_path)
127
- break
128
- end
129
- if Time.now - start > timeout
130
- warn 'Timed out waiting for result'
131
- exit 2
132
- end
133
- sleep 0.1
83
+ RubyProgress::Daemon.stop_daemon_by_pid_file(
84
+ pid_file,
85
+ message: opts[:message],
86
+ checkmark: opts[:checkmark] || false,
87
+ error: opts[:error] || false
88
+ )
89
+
90
+ # Don't output confirmation - the daemon itself shows the completion message
91
+ end
92
+
93
+ def self.advance(argv)
94
+ opts = parse_advance_options(argv)
95
+ pid_file = resolve_pid_file(opts)
96
+
97
+ unless File.exist?(pid_file)
98
+ warn "PID file #{pid_file} not found. Is the daemon running?"
99
+ exit 1
100
+ end
101
+
102
+ # Write advance command to control message file
103
+ cmf = RubyProgress::Daemon.control_message_file(pid_file)
104
+ control_data = {
105
+ action: 'advance',
106
+ amount: opts[:amount] || 1,
107
+ total: opts[:total]
108
+ }.compact
109
+
110
+ File.write(cmf, JSON.generate(control_data))
111
+
112
+ # Send signal to daemon to check for messages
113
+ pid = File.read(pid_file).strip.to_i
114
+ begin
115
+ Process.kill('USR2', pid)
116
+ rescue Errno::ESRCH
117
+ # Process doesn't exist
118
+ end
119
+
120
+ # Silent operation for script-friendly usage
121
+ end
122
+
123
+ def self.status(argv)
124
+ opts = parse_status_options(argv)
125
+ pid_file = resolve_pid_file(opts)
126
+
127
+ RubyProgress::Daemon.show_status(pid_file)
128
+ end
129
+
130
+ def self.parse_stop_options(argv)
131
+ options = {}
132
+ opt = OptionParser.new do |o|
133
+ o.banner = 'Usage: prg job stop [options]'
134
+ o.on('--pid-file PATH', 'Path to daemon PID file') do |v|
135
+ options[:pid_file] = v
136
+ end
137
+ o.on('--daemon-name NAME', 'Daemon name (maps to /tmp/ruby-progress/NAME.pid)') do |v|
138
+ options[:daemon_name] = v
139
+ end
140
+ o.on('--message MSG', 'Optional completion message to display') do |v|
141
+ options[:message] = v
142
+ end
143
+ o.on('--checkmark', 'Display a checkmark on completion') do
144
+ options[:checkmark] = true
145
+ end
146
+ o.on('--error', 'Mark completion as error state') do
147
+ options[:error] = true
134
148
  end
135
- else
136
- puts job_id
137
149
  end
150
+
151
+ opt.parse(argv)
152
+ options
138
153
  end
139
154
 
140
- # Build the JSON payload for a job based on parsed options.
141
- def self.build_payload(opts, job_id, cmd)
142
- payload = { 'id' => job_id }
155
+ def self.parse_advance_options(argv)
156
+ options = {}
157
+ opt = OptionParser.new do |o|
158
+ o.banner = 'Usage: prg job advance [options]'
159
+ o.on('--pid-file PATH', 'Path to daemon PID file') do |v|
160
+ options[:pid_file] = v
161
+ end
162
+ o.on('--daemon-name NAME', 'Daemon name (maps to /tmp/ruby-progress/NAME.pid)') do |v|
163
+ options[:daemon_name] = v
164
+ end
165
+ o.on('--amount N', Integer, 'Amount to advance (default: 1)') do |v|
166
+ options[:amount] = v
167
+ end
168
+ o.on('--total N', Integer, 'Update total if needed') do |v|
169
+ options[:total] = v
170
+ end
171
+ end
143
172
 
144
- is_action = !opts[:action].nil? && opts[:action] != false
173
+ opt.parse(argv)
174
+ options
175
+ end
145
176
 
146
- if is_action
147
- payload['action'] = opts[:action]
148
- if opts.key?(:value)
149
- val = opts[:value]
150
- payload['value'] = val.to_i if val.is_a?(String) && val =~ /^\d+$/
151
- payload['value'] ||= val
177
+ def self.parse_status_options(argv)
178
+ options = {}
179
+ opt = OptionParser.new do |o|
180
+ o.banner = 'Usage: prg job status [options]'
181
+ o.on('--pid-file PATH', 'Path to daemon PID file') do |v|
182
+ options[:pid_file] = v
183
+ end
184
+ o.on('--daemon-name NAME', 'Daemon name (maps to /tmp/ruby-progress/NAME.pid)') do |v|
185
+ options[:daemon_name] = v
152
186
  end
153
- else
154
- payload['command'] = cmd
155
187
  end
156
188
 
157
- payload
189
+ opt.parse(argv)
190
+ options
191
+ end
192
+
193
+ # Backward compatibility
194
+ def self.send(argv = ARGV)
195
+ warn "Warning: 'JobCLI.send' is deprecated. Use 'JobCLI.stop' instead."
196
+ stop(argv)
158
197
  end
159
198
  end
@@ -8,6 +8,14 @@ require_relative '../output_capture'
8
8
 
9
9
  # Enhanced Ripple CLI with unified flags (extracted from bin/prg)
10
10
  module RippleCLI
11
+ def self.resolve_pid_file(options, name_key = :daemon_name)
12
+ return options[:pid_file] if options[:pid_file]
13
+
14
+ return "/tmp/ruby-progress/#{options[name_key]}.pid" if options[name_key]
15
+
16
+ RubyProgress::Daemon.default_pid_file
17
+ end
18
+
11
19
  def self.run
12
20
  trap('INT') do
13
21
  RubyProgress::Utils.show_cursor
@@ -18,11 +26,11 @@ module RippleCLI
18
26
 
19
27
  # Daemon/status/stop handling (process these without requiring text)
20
28
  if options[:status]
21
- pid_file = options[:pid_file] || RubyProgress::Daemon.default_pid_file
29
+ pid_file = resolve_pid_file(options, :status_name)
22
30
  RubyProgress::Daemon.show_status(pid_file)
23
31
  exit
24
32
  elsif options[:stop]
25
- pid_file = options[:pid_file] || RubyProgress::Daemon.default_pid_file
33
+ pid_file = resolve_pid_file(options, :stop_name)
26
34
  stop_msg = options[:stop_error] || options[:stop_success]
27
35
  is_error = !options[:stop_error].nil?
28
36
  RubyProgress::Daemon.stop_daemon_by_pid_file(
@@ -33,13 +41,8 @@ module RippleCLI
33
41
  )
34
42
  exit
35
43
  elsif options[:daemon]
36
- # For daemon mode, detach so shell has no tracked job unless the user
37
- # requested a non-detaching background child via --no-detach.
38
- if options[:no_detach]
39
- PrgCLI.backgroundize
40
- else
41
- PrgCLI.daemonize
42
- end
44
+ # Background without detaching so ripple remains visible in current terminal
45
+ PrgCLI.backgroundize
43
46
 
44
47
  # For daemon mode, default message if none provided
45
48
  text = options[:message] || ARGV.join(' ')
@@ -125,7 +128,7 @@ module RippleCLI
125
128
  end
126
129
 
127
130
  def self.run_daemon_mode(text, options)
128
- pid_file = options[:pid_file] || RubyProgress::Daemon.default_pid_file
131
+ pid_file = resolve_pid_file(options, :daemon_name)
129
132
  FileUtils.mkdir_p(File.dirname(pid_file))
130
133
  File.write(pid_file, Process.pid.to_s)
131
134
  begin
@@ -139,9 +142,6 @@ module RippleCLI
139
142
  Signal.trap('TERM') { stop_requested = true }
140
143
  Signal.trap('HUP') { stop_requested = true }
141
144
 
142
- job_dir = RubyProgress::Daemon.job_dir_for_pid(pid_file)
143
- job_thread = Thread.new { process_daemon_jobs_for_rippler(job_dir, rippler, options) }
144
-
145
145
  rippler.advance until stop_requested
146
146
  ensure
147
147
  RubyProgress::Utils.clear_line
@@ -184,51 +184,9 @@ module RippleCLI
184
184
  end
185
185
 
186
186
  # stop job thread and cleanup
187
- job_thread&.kill
188
187
  FileUtils.rm_f(pid_file)
189
188
  end
190
189
  end
191
190
 
192
- def self.process_daemon_jobs_for_rippler(job_dir, rippler, options)
193
- RubyProgress::Daemon.process_jobs(job_dir) do |job|
194
- jid = job['id'] || SecureRandom.uuid
195
- log_path = begin
196
- File.join(File.dirname(job_dir), "#{jid}.log")
197
- rescue StandardError
198
- nil
199
- end
200
-
201
- oc = RubyProgress::OutputCapture.new(
202
- command: job['command'],
203
- lines: options[:output_lines] || 3,
204
- position: options[:output_position] || :above,
205
- log_path: log_path
206
- )
207
- oc.start
208
-
209
- rippler.instance_variable_set(:@output_capture, oc)
210
- oc.wait
211
- captured = oc.lines.join("\n")
212
- exit_status = oc.exit_status
213
- rippler.instance_variable_set(:@output_capture, nil)
214
-
215
- success = exit_status.to_i.zero?
216
- if job['message']
217
- RubyProgress::Utils.display_completion(
218
- job['message'],
219
- success: success,
220
- show_checkmark: job['checkmark'] || false,
221
- output_stream: :stdout,
222
- icons: { success: options[:success_icon], error: options[:error_icon] }
223
- )
224
- end
225
-
226
- { 'exit_status' => exit_status, 'output' => captured, 'log_path' => log_path }
227
- rescue StandardError
228
- # ignore per-job errors; process_jobs will write result
229
- nil
230
- end
231
- end
232
-
233
191
  # Options parsing moved to ripple_options.rb
234
192
  end
@@ -106,8 +106,9 @@ module RippleCLI
106
106
  options[:daemon] = true
107
107
  end
108
108
 
109
- opts.on('--no-detach', 'When used with --daemon: run background child but do not fully detach from the terminal') do
110
- options[:no_detach] = true
109
+ opts.on('--daemon-as NAME', 'Run in daemon mode with custom name (creates /tmp/ruby-progress/NAME.pid)') do |name|
110
+ options[:daemon] = true
111
+ options[:daemon_name] = name
111
112
  end
112
113
 
113
114
  opts.on('--pid-file FILE', 'Write process ID to file (default: /tmp/ruby-progress/progress.pid)') do |file|
@@ -118,10 +119,20 @@ module RippleCLI
118
119
  options[:stop] = true
119
120
  end
120
121
 
122
+ opts.on('--stop-id NAME', 'Stop daemon by name (automatically implies --stop)') do |name|
123
+ options[:stop] = true
124
+ options[:stop_name] = name
125
+ end
126
+
121
127
  opts.on('--status', 'Show daemon status (running/not running)') do
122
128
  options[:status] = true
123
129
  end
124
130
 
131
+ opts.on('--status-id NAME', 'Show daemon status by name') do |name|
132
+ options[:status] = true
133
+ options[:status_name] = name
134
+ end
135
+
125
136
  opts.on('--stop-success MESSAGE', 'When stopping, show this success message') do |msg|
126
137
  options[:stop_success] = msg
127
138
  end
@@ -135,7 +146,7 @@ module RippleCLI
135
146
  opts.separator ''
136
147
  opts.separator 'Daemon notes:'
137
148
  opts.separator ' - Do not append &; prg detaches itself and returns immediately.'
138
- opts.separator ' - Use --status/--stop with optional --pid-file to control it.'
149
+ opts.separator ' - Use --daemon-as NAME for named daemons, or --stop-id/--status-id for named control.'
139
150
 
140
151
  opts.separator ''
141
152
  opts.separator 'General:'
@@ -8,6 +8,11 @@ require_relative 'twirl_runner'
8
8
  # Twirl CLI (extracted from bin/prg)
9
9
  module TwirlCLI
10
10
  def self.run
11
+ trap('INT') do
12
+ RubyProgress::Utils.show_cursor
13
+ exit
14
+ end
15
+
11
16
  options = TwirlCLI::Options.parse_cli_options
12
17
 
13
18
  if options[:status]
@@ -26,7 +31,9 @@ module TwirlCLI
26
31
  )
27
32
  exit
28
33
  elsif options[:daemon]
29
- PrgCLI.daemonize
34
+ # Background without detaching so spinner remains visible in current terminal
35
+ PrgCLI.backgroundize
36
+
30
37
  TwirlRunner.run_daemon_mode(options)
31
38
  elsif options[:command]
32
39
  TwirlRunner.run_with_command(options)
@@ -92,10 +92,6 @@ module TwirlCLI
92
92
  options[:daemon] = true
93
93
  end
94
94
 
95
- opts.on('--no-detach', 'When used with --daemon/--daemon-as: run background child but do not fully detach from the terminal') do
96
- options[:no_detach] = true
97
- end
98
-
99
95
  opts.on('--daemon-as NAME', 'Run in daemon mode with custom name (creates /tmp/ruby-progress/NAME.pid)') do |name|
100
96
  options[:daemon] = true
101
97
  options[:daemon_name] = name
@@ -46,6 +46,11 @@ module TwirlRunner
46
46
 
47
47
  spinner_thread.kill
48
48
  RubyProgress::Utils.clear_line
49
+ rescue Interrupt
50
+ spinner_thread&.kill
51
+ RubyProgress::Utils.clear_line
52
+ RubyProgress::Utils.show_cursor
53
+ exit 130
49
54
  ensure
50
55
  RubyProgress::Utils.show_cursor
51
56
  end
@@ -74,6 +79,10 @@ module TwirlRunner
74
79
  begin
75
80
  RubyProgress::Utils.hide_cursor
76
81
  loop { spinner.animate }
82
+ rescue Interrupt
83
+ RubyProgress::Utils.clear_line
84
+ RubyProgress::Utils.show_cursor
85
+ exit 130
77
86
  ensure
78
87
  RubyProgress::Utils.show_cursor
79
88
  if options[:success] || options[:checkmark]
@@ -104,41 +113,6 @@ module TwirlRunner
104
113
  begin
105
114
  RubyProgress::Utils.hide_cursor
106
115
 
107
- # Start job processor thread for twirl
108
- job_dir = RubyProgress::Daemon.job_dir_for_pid(pid_file)
109
- job_thread = Thread.new do
110
- RubyProgress::Daemon.process_jobs(job_dir) do |job|
111
- oc = RubyProgress::OutputCapture.new(
112
- command: job['command'],
113
- lines: options[:output_lines] || 3,
114
- position: options[:output_position] || :above,
115
- stream: options[:stdout] || options[:stdout_live]
116
- )
117
- oc.start
118
-
119
- spinner.instance_variable_set(:@output_capture, oc)
120
- oc.wait
121
- captured = oc.lines.join("\n")
122
- exit_status = oc.exit_status
123
- spinner.instance_variable_set(:@output_capture, nil)
124
-
125
- success = exit_status.to_i.zero?
126
- if job['message']
127
- RubyProgress::Utils.display_completion(
128
- job['message'],
129
- success: success,
130
- show_checkmark: job['checkmark'] || false,
131
- output_stream: :stdout,
132
- icons: { success: options[:success_icon], error: options[:error_icon] }
133
- )
134
- end
135
-
136
- { 'exit_status' => exit_status, 'output' => captured }
137
- rescue StandardError
138
- # ignore
139
- end
140
- end
141
-
142
116
  spinner.animate until stop_requested
143
117
  ensure
144
118
  RubyProgress::Utils.clear_line
@@ -172,7 +146,6 @@ module TwirlRunner
172
146
  end
173
147
  end
174
148
 
175
- job_thread&.kill
176
149
  FileUtils.rm_f(pid_file)
177
150
  end
178
151
  end