ruby-progress 1.3.4 → 1.3.5
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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +26 -13
- data/CHANGELOG.md +29 -49
- data/DAEMON_MODE.md +127 -0
- data/Gemfile +7 -1
- data/Gemfile.lock +19 -18
- data/JOB_CLI_REFACTOR.md +67 -0
- data/README.md +90 -94
- data/bin/prg +10 -16
- data/examples/daemon_job_example.sh +8 -10
- data/lib/ruby-progress/cli/fill_options.rb +2 -6
- data/lib/ruby-progress/cli/job_cli.rb +170 -131
- data/lib/ruby-progress/cli/ripple_cli.rb +13 -55
- data/lib/ruby-progress/cli/ripple_options.rb +14 -3
- data/lib/ruby-progress/cli/twirl_cli.rb +3 -1
- data/lib/ruby-progress/cli/twirl_options.rb +0 -4
- data/lib/ruby-progress/cli/twirl_runner.rb +0 -36
- data/lib/ruby-progress/cli/worm_cli.rb +2 -51
- data/lib/ruby-progress/cli/worm_options.rb +0 -6
- data/lib/ruby-progress/cli/worm_runner.rb +7 -1
- data/lib/ruby-progress/daemon.rb +2 -64
- data/lib/ruby-progress/fill_cli.rb +2 -72
- data/lib/ruby-progress/output_capture.rb +7 -2
- data/lib/ruby-progress/utils.rb +11 -6
- data/lib/ruby-progress/version.rb +5 -5
- data/ruby-progress.gemspec +41 -0
- data/scripts/coverage_analysis.rb +49 -0
- data/test_daemon.sh +20 -0
- metadata +6 -15
data/README.md
CHANGED
|
@@ -2,32 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/ruby-progress)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://github.com/ttscoff/ruby-progress/actions/workflows/rspec.yml)
|
|
5
|
+
<!-- [](https://github.com/ttscoff/ruby-progress/actions/workflows/rspec.yml) -->
|
|
6
6
|
[](https://www.ruby-lang.org/)
|
|
7
|
-
[](#) -->
|
|
8
8
|
|
|
9
9
|
This repository contains three different Ruby progress indicator projects: **Ripple**, **Worm**, and **Twirl**. All provide animated terminal progress indicators with different visual styles and features.
|
|
10
10
|
|
|
11
11
|
## Table of Contents
|
|
12
12
|
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
- [
|
|
22
|
-
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
|
|
28
|
-
- [
|
|
29
|
-
- [
|
|
30
|
-
- [
|
|
13
|
+
- [Ruby Progress Indicators](#ruby-progress-indicators)
|
|
14
|
+
- [Table of Contents](#table-of-contents)
|
|
15
|
+
- [Unified Interface](#unified-interface)
|
|
16
|
+
- [Global Options](#global-options)
|
|
17
|
+
- [Stopping a backgrounded progress indicator](#stopping-a-backgrounded-progress-indicator)
|
|
18
|
+
- [Job Control Subcommands](#job-control-subcommands)
|
|
19
|
+
- [Example: background mode demo](#example-background-mode-demo)
|
|
20
|
+
- [Ripple](#ripple)
|
|
21
|
+
- [Ripple Features](#ripple-features)
|
|
22
|
+
- [Ripple Usage](#ripple-usage)
|
|
23
|
+
- [Ripple CLI examples](#ripple-cli-examples)
|
|
24
|
+
- [Ripple Command Line Options](#ripple-command-line-options)
|
|
25
|
+
- [Ripple Library Usage](#ripple-library-usage)
|
|
26
|
+
- [Twirl](#twirl)
|
|
27
|
+
- [Twirl Features](#twirl-features)
|
|
28
|
+
- [Twirl Usage](#twirl-usage)
|
|
29
|
+
- [Command Line](#command-line)
|
|
30
|
+
- [Twirl Command Line Options](#twirl-command-line-options)
|
|
31
|
+
- [Available Spinner Styles](#available-spinner-styles)
|
|
32
|
+
- [Worm](#worm)
|
|
33
|
+
- [Worm Features](#worm-features)
|
|
34
|
+
- [Worm Usage](#worm-usage)
|
|
35
|
+
- [Command Line](#command-line-1)
|
|
36
|
+
- [Daemon mode (background indicator)](#daemon-mode-background-indicator)
|
|
37
|
+
- [Worm Command Line Options](#worm-command-line-options)
|
|
38
|
+
- [Worm Library Usage](#worm-library-usage)
|
|
39
|
+
- [Animation Styles](#animation-styles)
|
|
40
|
+
- [Circles](#circles)
|
|
41
|
+
- [Blocks](#blocks)
|
|
42
|
+
- [Geometric](#geometric)
|
|
43
|
+
- [Custom Styles](#custom-styles)
|
|
44
|
+
- [Direction Control](#direction-control)
|
|
45
|
+
- [Requirements](#requirements)
|
|
46
|
+
- [Installation](#installation)
|
|
47
|
+
- [As a Gem (Recommended)](#as-a-gem-recommended)
|
|
48
|
+
- [From Source](#from-source)
|
|
49
|
+
- [Development](#development)
|
|
50
|
+
- [Universal Utilities](#universal-utilities)
|
|
51
|
+
- [Terminal Control](#terminal-control)
|
|
52
|
+
- [Completion Messages](#completion-messages)
|
|
53
|
+
- [Contributing](#contributing)
|
|
54
|
+
- [License](#license)
|
|
31
55
|
|
|
32
56
|
## Unified Interface
|
|
33
57
|
|
|
@@ -78,114 +102,86 @@ Notes:
|
|
|
78
102
|
- The indicator clears its line on shutdown and prints the final message to STDOUT.
|
|
79
103
|
- `--stop-pid` is still supported for backward compatibility, but `--stop [--pid-file FILE]` is preferred.
|
|
80
104
|
|
|
81
|
-
###
|
|
105
|
+
### Stopping a backgrounded progress indicator
|
|
82
106
|
|
|
83
|
-
When running a
|
|
107
|
+
When running a backgrounded progress indicator (for example `prg worm --daemon`), you can send control signals using the `prg job` command with subcommands.
|
|
84
108
|
|
|
85
|
-
|
|
109
|
+
#### Job Control Subcommands
|
|
110
|
+
|
|
111
|
+
**Stop a running daemon:**
|
|
86
112
|
|
|
87
113
|
```bash
|
|
88
|
-
#
|
|
89
|
-
prg job
|
|
114
|
+
# Send a stop signal to the default daemon
|
|
115
|
+
prg job stop
|
|
116
|
+
|
|
117
|
+
# Send a stop signal to a named daemon (uses /tmp/ruby-progress/<name>.pid)
|
|
118
|
+
prg job stop --daemon-name mytask
|
|
90
119
|
|
|
91
|
-
#
|
|
92
|
-
prg job
|
|
120
|
+
# Send a stop signal with a completion message
|
|
121
|
+
prg job stop --daemon-name mytask --message "Deployment complete!"
|
|
93
122
|
|
|
94
|
-
#
|
|
95
|
-
|
|
123
|
+
# Send a stop signal with a checkmark
|
|
124
|
+
prg job stop --daemon-name mytask --message "Build successful" --checkmark
|
|
96
125
|
|
|
97
|
-
#
|
|
98
|
-
prg job
|
|
126
|
+
# Send a stop signal indicating an error
|
|
127
|
+
prg job stop --daemon-name mytask --message "Build failed" --error
|
|
99
128
|
```
|
|
100
129
|
|
|
101
|
-
|
|
130
|
+
**Check daemon status:**
|
|
102
131
|
|
|
103
132
|
```bash
|
|
104
|
-
#
|
|
105
|
-
prg job
|
|
133
|
+
# Check if a daemon is running
|
|
134
|
+
prg job status --daemon-name mytask
|
|
106
135
|
|
|
107
|
-
#
|
|
108
|
-
prg job
|
|
136
|
+
# Check status using a PID file
|
|
137
|
+
prg job status --pid-file /tmp/ruby-progress/mytask.pid
|
|
138
|
+
```
|
|
109
139
|
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
# Start a named fill worker (non-detaching so animation remains visible)
|
|
113
|
-
prg fill --daemon-as demo --no-detach --output-lines 3 --output-position top
|
|
140
|
+
**Advance a progress indicator:**
|
|
114
141
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
prg job
|
|
118
|
-
prg job send --daemon-name demo --percent 100 --wait
|
|
119
|
-
```
|
|
142
|
+
```bash
|
|
143
|
+
# Advance progress by 1 (for indicators that support it)
|
|
144
|
+
prg job advance --daemon-name mytask
|
|
120
145
|
|
|
121
|
-
#
|
|
122
|
-
prg job
|
|
146
|
+
# Advance by a specific amount
|
|
147
|
+
prg job advance --daemon-name mytask --amount 10
|
|
123
148
|
```
|
|
124
149
|
|
|
125
|
-
|
|
150
|
+
**Backward Compatibility:**
|
|
126
151
|
|
|
127
|
-
|
|
152
|
+
The legacy `prg job send` command is still supported but deprecated. It functions identically to `prg job stop`:
|
|
128
153
|
|
|
129
154
|
```bash
|
|
130
|
-
#
|
|
131
|
-
prg
|
|
155
|
+
# This still works but shows a deprecation warning
|
|
156
|
+
prg job send --daemon-name mytask --message "Complete!"
|
|
132
157
|
```
|
|
133
158
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
- Jobs are written as JSON files into the daemon's job directory, which is derived from the daemon PID file. For example, a PID file `/tmp/ruby-progress/mytask.pid` maps to the job directory `/tmp/ruby-progress/mytask.jobs`.
|
|
137
|
-
- The CLI writes the job atomically by first writing a `*.json.tmp` temporary file and then renaming it to `*.json`.
|
|
138
|
-
- The daemon's job processor claims jobs atomically by renaming the job file to `*.processing`, writes a `*.processing.result` JSON file when finished, and moves processed jobs to `processed-*`.
|
|
139
|
-
|
|
140
|
-
This mechanism allows you to submit many commands to a single running indicator and have their output shown in reserved terminal rows while the animation continues.
|
|
141
|
-
|
|
142
|
-
## Job result schema
|
|
159
|
+
Alternatively, you can use the built-in `--stop` flags on the progress commands:
|
|
143
160
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
- `status` - `"done"` or `"error"`
|
|
148
|
-
- `time` - epoch seconds when the job finished (integer)
|
|
149
|
-
|
|
150
|
-
Depending on the job handler, additional keys may be present:
|
|
151
|
-
|
|
152
|
-
- `exit_status` - the numeric process exit status (integer or nil if unknown)
|
|
153
|
-
- `output` - a string with the last captured lines of output (if available)
|
|
154
|
-
- `error` - an error message when `status` is `error`
|
|
155
|
-
|
|
156
|
-
Example:
|
|
161
|
+
```bash
|
|
162
|
+
# Stop a named daemon with a success message
|
|
163
|
+
prg worm --stop-id demo --stop-success 'Task completed'
|
|
157
164
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
"id": "8a1f6c1e-4b7a-4f2c-b0a8-9e9f1c2f1a2b",
|
|
161
|
-
"status": "done",
|
|
162
|
-
"time": 1634044800,
|
|
163
|
-
"exit_status": 0,
|
|
164
|
-
"output": "Step 1 completed\nStep 2 completed"
|
|
165
|
-
}
|
|
165
|
+
# Stop with an error message
|
|
166
|
+
prg worm --stop-id demo --stop-error 'Task failed'
|
|
166
167
|
```
|
|
167
168
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
## Example: start a daemon and send a job (simple)
|
|
171
|
-
|
|
172
|
-
Below is an example script that demonstrates starting a worm daemon, sending a job, waiting for the result, and stopping the daemon.
|
|
173
|
-
---
|
|
169
|
+
## Example: background mode demo
|
|
174
170
|
|
|
175
|
-
|
|
171
|
+
Below is an example script that demonstrates starting a backgrounded progress indicator, doing work, and stopping it with a message.
|
|
176
172
|
|
|
177
173
|
```bash
|
|
178
|
-
# Start a named worm worker that
|
|
179
|
-
prg worm --daemon-as demo
|
|
174
|
+
# Start a named worm worker that runs in the background
|
|
175
|
+
prg worm --daemon-as demo
|
|
180
176
|
|
|
181
|
-
#
|
|
182
|
-
|
|
177
|
+
# Do some work in your script...
|
|
178
|
+
sleep 2
|
|
183
179
|
|
|
184
180
|
# Stop the worker with a success message
|
|
185
|
-
prg
|
|
181
|
+
prg job stop --daemon-name demo --message "Demo finished" --checkmark
|
|
186
182
|
```
|
|
187
183
|
|
|
188
|
-
Note
|
|
184
|
+
**Note:** Daemon mode automatically backgrounds the process using `Process.fork` and `Process.detach`, so you don't need to append `&`. The process detaches cleanly without shell job notifications.
|
|
189
185
|
|
|
190
186
|
## Ripple
|
|
191
187
|
|
data/bin/prg
CHANGED
|
@@ -24,14 +24,8 @@ module PrgCLI
|
|
|
24
24
|
# Handle `job` subcommands early
|
|
25
25
|
if ARGV[0] && ARGV[0].downcase == 'job'
|
|
26
26
|
ARGV.shift
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
when 'send'
|
|
30
|
-
JobCLI.send(ARGV)
|
|
31
|
-
else
|
|
32
|
-
puts 'job subcommands: send'
|
|
33
|
-
exit 1
|
|
34
|
-
end
|
|
27
|
+
JobCLI.run(ARGV)
|
|
28
|
+
exit
|
|
35
29
|
end
|
|
36
30
|
# Early scan: detect --ends flag and validate its argument before dispatching
|
|
37
31
|
if (i = ARGV.index('--ends')) && ARGV[i + 1]
|
|
@@ -151,16 +145,16 @@ module PrgCLI
|
|
|
151
145
|
# Spawn a background child but do NOT fully detach from the controlling
|
|
152
146
|
# terminal. This keeps the child attached to the same TTY so animations
|
|
153
147
|
# remain visible, while the parent exits immediately allowing the caller
|
|
154
|
-
# (shell or script) to continue.
|
|
155
|
-
# background worker (e.g. `--daemon-as NAME --no-detach`).
|
|
148
|
+
# (shell or script) to continue.
|
|
156
149
|
def self.backgroundize
|
|
157
150
|
pid = fork
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
#
|
|
151
|
+
if pid
|
|
152
|
+
# Parent: detach child and exit silently
|
|
153
|
+
Process.detach(pid)
|
|
154
|
+
exit(0)
|
|
155
|
+
end
|
|
156
|
+
# Child: create new process group but keep stdin/stdout/stderr
|
|
157
|
+
Process.setsid
|
|
164
158
|
end
|
|
165
159
|
|
|
166
160
|
# Attempt to stop processes for the given subcommand. Return true if any
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
|
-
# Example: start a worm
|
|
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
|
|
12
|
-
#
|
|
13
|
-
$PRG_BIN worm --daemon-as example --message "Example
|
|
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.
|
|
15
|
+
sleep 0.5
|
|
16
16
|
|
|
17
|
-
echo "
|
|
18
|
-
|
|
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
|
|
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
|
|
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
|
|
265
|
+
# rubocop:enable Metrics/AbcSize
|
|
270
266
|
end
|
|
271
267
|
end
|