Show the progress rate over the last 5 seconds, and what a phase is doing after 10 seconds with no item done (closes #125)
check / check (push) Canceled after 0s

The rate was the phase's average, so a burst after a long wait read as
over 1,000 files a second. It now covers the items completed over the
last 5 seconds, or since the line before off a terminal, and falls to 0
while nothing completes; the ETA still comes from the average. Once no
item has completed for 10 seconds, the line says so and what the phase
is doing, a phrase each phase gives where it is defined. A narrow
terminal leaves that out after the rate, keeping the phase, progress,
elapsed time and ETA whole. The tests set the display's clock by hand.

Judgement call: the line reads "no files finished", in the phase's unit.
Judgement call: trees' group phase says "grouping directories".

Model: opus-5-5
This commit is contained in:
2026-10-16 21:01:05 +00:00
parent e9e09effc6
commit 69dbbfc1d7
9 changed files with 403 additions and 99 deletions
+26 -9
View File
@@ -833,17 +833,33 @@ Each display is one line holding:
- a `[m/n] x%` display (items processed / total items, percent); before a phase
has a total, the items processed, or what the phase is waiting for
- current rate (items/s), naming the items the phase counts: files, records,
directories or groups
directories or groups. It covers the items completed over the last 5 seconds,
or, when stderr is not a terminal, since the line before, so it falls to 0
while nothing completes, and a burst of items after a wait shows as a burst
rather than as a steady rate.
- once no item has completed for 10 seconds, how long that has been and what the
phase is doing (see below)
- elapsed time
- estimated time remaining, or `unknown`
- estimated time remaining, or `unknown`. It comes from the phase's average rate
since it started counting, so that it does not swing with each burst.
Example shape (exact layout is flexible, content is not):
```
[3/5] hash: [12345/98765] 12% |████ | 92 files/s elapsed 2:32 eta 17:54
[2/5] walk: [1234567/~1200000] 103%, 5120 files/s, elapsed 4m1s, eta unknown
[3/5] hash: [12345/98765] 12%, 0 files/s, no files finished for 42s, reading files, elapsed 4m1s, eta 28m7s
```
When no item has completed for 10 seconds, as while one large file is read, a
disk is slow or the database is busy, the line says so and what the phase is
doing: `walk` is listing directories; `hash` and the content phase's reads are
reading files; `update` is writing to the database; `load` and the `read` phases
of `trees` and `report` are reading the database; the content phase's checks are
searching the database; `trees`' `group` is grouping directories, and its
`write` is writing the report. A phase still waiting for its total already says
what it waits for, and says nothing more.
Additional requirements:
- On a terminal, a phase with an exact total (every phase but `scan`'s `walk`,
@@ -857,13 +873,14 @@ Additional requirements:
- On a terminal no line reaches the terminal's last column, however narrow the
terminal is. The phase and its place, the progress, the elapsed time and the
ETA are kept whole: a line too wide for the terminal leaves out its rate first
(or what the phase is waiting for), and a bar with no room beside those four
gives way to the spinner. Only when those four alone are too wide, as on a
terminal narrower than about 70 columns hours into a scan of millions of
files, is the line cut short at the terminal's edge, so the end of the ETA is
lost first. A terminal made narrower while a phase runs gets the same: the
next draw erases the line within the new width and fits the line to it, and
the display goes on redrawing in place.
(or what the phase is waiting for), then what it says of 10 seconds with no
item completed, and a bar with no room beside those four gives way to the
spinner. Only when those four alone are too wide, as on a terminal narrower
than about 70 columns hours into a scan of millions of files, is the line cut
short at the terminal's edge, so the end of the ETA is lost first. A terminal
made narrower while a phase runs gets the same: the next draw erases the line
within the new width and fits the line to it, and the display goes on
redrawing in place.
- When stderr is not a terminal (a pipe, a file, `/dev/null`), do not emit ANSI
redraws: print the line the moment each phase starts, every 5 seconds while it
runs (whether or not an item has completed, and never more often), and once