add ProgressIndicatorSpinner, for work of unknown duration - #10081
Merged
Conversation
The other progress indicators either count (percent) or just emit a message. For work whose duration or size is not known in advance, neither fits: what we want to show is "borg is still working, at this", and that is a spinner. It is pull-based on purpose: no thread, no timer, nothing runs while the caller is not calling. show() is rate limited by BORG_PROGRESS_FPS, so calling it very often is cheap. On a terminal, the frame and the message are repainted in place, in borg green. Without a terminal (or with --log-json) there is nothing to animate, so only message changes are logged, as "progress_message" - same as ProgressIndicatorMessage does it, so frontends need no changes. The frames are all East Asian Width "Neutral", so they take exactly one cell and the message never shifts column. If the output encoding can not represent them (or BORG_SPINNER=ascii), the classic ASCII frames are used instead. BORG_SPINNER=off never animates.
ThomasWaldmann
force-pushed
the
spinner
branch
from
August 11, 2026 22:49
57ad725 to
acf222a
Compare
Member
Author
|
@mr-raj12 use it where appropriate. I think it can be used to give life-signs at a finer granularity than what we had yet (because it stays in one place, it is fps rate limited). No more "is borg hanging?" questions... |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #10081 +/- ##
==========================================
- Coverage 86.70% 86.66% -0.04%
==========================================
Files 98 98
Lines 17174 17275 +101
Branches 2609 2621 +12
==========================================
+ Hits 14890 14971 +81
- Misses 1586 1604 +18
- Partials 698 700 +2 ☔ View full report in Codecov by Harness. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The other progress indicators either count (
ProgressIndicatorPercent) or just emit a message (ProgressIndicatorMessage). For work whose duration or size is not known in advance, neither fits: what we want to show is "borg is still working, at this" — and that is a spinner.How it behaves
show()is rate limited byBORG_PROGRESS_FPSinternally, so calling it a million times a second costs onetime.monotonic()per call.#22D045on truecolor terminals, else the terminal's own bright green — the nearest xterm-256 entry drops the red channel and reads too acid). The message is truncated to the terminal width, because a wrapped line could not be repainted in place. The cursor is hidden at the first paint and switched back on infinish().--log-json: an animation would be pointless, so nothing is repainted — only message changes are logged, asprogress_message, exactly likeProgressIndicatorMessagedoes it. So a logfile gets one line per phase rather than one per frame, and frontends need no changes.--quietsilences it, like the other indicators.Frames
All frames are East Asian Width "Neutral", so they occupy exactly one cell and the message after the spinner never shifts column:
square(default)cubeboxedasciiIf the output encoding can not represent the fancy frames, the ASCII ones are used automatically.
New environment variable
BORG_SPINNER=offnever animates,BORG_SPINNER=asciiforces the ASCII frames. Documented in theenvironmenthelp topic (and thus in the docs). Colour follows the usualNO_COLOR/COLORTERMconventions.Notes
Cache.close()) are single-call phases where nothing would animate; wiring it up where there is a real loop is a separate change.--quiet, non-tty logging, and a stream that goes away mid-run.