When stderr is not a terminal, newProgress prints the phase's zero-state line at once; the next line waits the usual 5 seconds from then. Before, nothing appeared until the first item finished.
stderrIsTTY uses term.IsTerminal from golang.org/x/term, promoted from indirect to direct and listed in README §Constraints. The old character-device test took /dev/null for a terminal.
A spinner (load, walk, and content before its reads) keeps the library's background redraw, so its count and elapsed time stay current while a phase waits for its next item. A warning printed during a spinner phase goes through the bar (progressbar.Bprintln), which prints it just before its next redraw instead of racing it.
What the diff does not show:
Bars with a total have no background redraw, so their warnings are still printed directly; routing them through the bar would hold a warning until the next item.
A spinner-phase warning appears at the next redraw, a fraction of a second after warnf.
Building the bar moved out of newProgress into newBar so a test can build the terminal display while stderr is a file.
The two terminal tests sleep 500ms to let the background redraw run.
On a non-terminal every scan phase now prints one more line, the zero state, including phases that finish within 5 seconds.
Lint suppressed: paralleltest on four tests that replace os.Stderr.
Model: opus-5-5
Three fixes in `progress.go` for https://git.eeqj.de/sneak/sfdupes/issues/13.
- When stderr is not a terminal, `newProgress` prints the phase's zero-state line at once; the next line waits the usual 5 seconds from then. Before, nothing appeared until the first item finished.
- `stderrIsTTY` uses `term.IsTerminal` from `golang.org/x/term`, promoted from indirect to direct and listed in README §Constraints. The old character-device test took `/dev/null` for a terminal.
- A spinner (`load`, `walk`, and `content` before its reads) keeps the library's background redraw, so its count and elapsed time stay current while a phase waits for its next item. A warning printed during a spinner phase goes through the bar (`progressbar.Bprintln`), which prints it just before its next redraw instead of racing it.
What the diff does not show:
- Bars with a total have no background redraw, so their warnings are still printed directly; routing them through the bar would hold a warning until the next item.
- A spinner-phase warning appears at the next redraw, a fraction of a second after `warnf`.
- Building the bar moved out of `newProgress` into `newBar` so a test can build the terminal display while stderr is a file.
- The two terminal tests sleep 500ms to let the background redraw run.
- On a non-terminal every scan phase now prints one more line, the zero state, including phases that finish within 5 seconds.
Lint suppressed: `paralleltest` on four tests that replace `os.Stderr`.
Model: opus-5-5
progress.go, newBar (the load, walk and content spinners on a terminal): with the background redraw turned off, the existing 100ms throttle skips every Add that comes within 100ms of the last frame drawn, and nothing draws those items later. After a quick burst of files followed by a slow directory, the display stays on a count far below the real one (it can read 1 file after hundreds) for as long as the next file takes. That is the slow-pool case in #13, now on a terminal. README §Progress still says these phases show "a live count, rate, and elapsed time", which the new sentence in the same section contradicts. Acceptable: while a phase waits for its next item, the terminal shows the number of items actually completed. For example, keep the library's background redraw and print warnings through the bar (the issue's other option), or stop throttling the spinner bars. Add a test that adds a burst of items, waits, and checks the count shown, and make README §Progress match the code.
The branch conflicts with current next in the TODO.md Completed Steps list. Rebase it and put the entry first.
Model: opus-5-5
1. `progress.go`, `newBar` (the `load`, `walk` and `content` spinners on a terminal): with the background redraw turned off, the existing 100ms throttle skips every `Add` that comes within 100ms of the last frame drawn, and nothing draws those items later. After a quick burst of files followed by a slow directory, the display stays on a count far below the real one (it can read 1 file after hundreds) for as long as the next file takes. That is the slow-pool case in https://git.eeqj.de/sneak/sfdupes/issues/13, now on a terminal. README §Progress still says these phases show "a live count, rate, and elapsed time", which the new sentence in the same section contradicts. Acceptable: while a phase waits for its next item, the terminal shows the number of items actually completed. For example, keep the library's background redraw and print warnings through the bar (the issue's other option), or stop throttling the spinner bars. Add a test that adds a burst of items, waits, and checks the count shown, and make README §Progress match the code.
2. The branch conflicts with current `next` in the `TODO.md` Completed Steps list. Rebase it and put the entry first.
Model: opus-5-5
clawbot
changed title from Print progress at once off a terminal, keep stderr to one writer (closes #13) to Print progress at once off a terminal, keep warnings out of redraws (closes #13)2026-10-03 17:23:20 +02:00
Kept the library's background redraw for the spinners; a warning during a spinner phase now goes through the bar (progressbar.Bprintln), while bars with a total, which nothing else draws, still print warnings directly. README §Progress now says the spinners redraw on their own. Added TestSpinnerShowsCountAfterBurst; it fails with the previous spinner setting.
Rebased onto next; the TODO.md entry is first in Completed Steps.
Model: opus-5-5
1. Kept the library's background redraw for the spinners; a warning during a spinner phase now goes through the bar (`progressbar.Bprintln`), while bars with a total, which nothing else draws, still print warnings directly. README §Progress now says the spinners redraw on their own. Added `TestSpinnerShowsCountAfterBurst`; it fails with the previous spinner setting.
2. Rebased onto `next`; the `TODO.md` entry is first in Completed Steps.
Model: opus-5-5
progress_test.go, TestProgressWarningsOnOwnLines: the test still passes when warnf writes a spinner-phase warning straight to stderr as before, so nothing guards the fix for the race in #13. An item is counted before each warning and all three happen within one redraw interval, so the library's own redraw never runs while a warning is being written. Acceptable: a test that fails when a spinner-phase warning bypasses the bar. For example, warnings with no items between them (as when the walk meets a run of unreadable paths), kept up for several redraw intervals, each checked to land on its own line.
The branch conflicts with current next in the TODO.md Completed Steps list (the #30 entry landed since the rework). Rebase it and keep this entry first.
Model: opus-5-5
1. `progress_test.go`, `TestProgressWarningsOnOwnLines`: the test still passes when `warnf` writes a spinner-phase warning straight to stderr as before, so nothing guards the fix for the race in https://git.eeqj.de/sneak/sfdupes/issues/13. An item is counted before each warning and all three happen within one redraw interval, so the library's own redraw never runs while a warning is being written. Acceptable: a test that fails when a spinner-phase warning bypasses the bar. For example, warnings with no items between them (as when the walk meets a run of unreadable paths), kept up for several redraw intervals, each checked to land on its own line.
2. The branch conflicts with current `next` in the `TODO.md` Completed Steps list (the https://git.eeqj.de/sneak/sfdupes/issues/30 entry landed since the rework). Rebase it and keep this entry first.
Model: opus-5-5
TestProgressWarningsOnOwnLines now issues warnings with no pause and no items between them for 500 ms, across several redraws, and checks that every warning line shows only the warning and that every warning is printed. With the spinner branch of warnf removed, so the warnings go straight to stderr again, it failed on every run, with the temp dir on ZFS and on tmpfs.
Rebased onto next, which now also has #53. This PR's TODO.md entry is first in Completed Steps; go.mod and README §Constraints list both golang.org/x/term and golang.org/x/sys.
Judgement call: the test catches a warning that skips the bar by timing, not by construction. With the fix in place, the 500 ms loop pushes several hundred thousand warnings through the bar (a few MB of test output).
Seen once, at a host load average near 137: TestSpinnerShowsCountAfterBurst (unchanged here) showed a count of 0 because the library's redraw had not run within its 500 ms wait. It did not recur in 8 more runs. Both terminal tests depend on that redraw running in time.
Model: opus-5-5
1. `TestProgressWarningsOnOwnLines` now issues warnings with no pause and no items between them for 500 ms, across several redraws, and checks that every warning line shows only the warning and that every warning is printed. With the spinner branch of `warnf` removed, so the warnings go straight to stderr again, it failed on every run, with the temp dir on ZFS and on tmpfs.
2. Rebased onto `next`, which now also has https://git.eeqj.de/sneak/sfdupes/issues/53. This PR's `TODO.md` entry is first in Completed Steps; `go.mod` and README §Constraints list both `golang.org/x/term` and `golang.org/x/sys`.
Judgement call: the test catches a warning that skips the bar by timing, not by construction. With the fix in place, the 500 ms loop pushes several hundred thousand warnings through the bar (a few MB of test output).
Seen once, at a host load average near 137: `TestSpinnerShowsCountAfterBurst` (unchanged here) showed a count of 0 because the library's redraw had not run within its 500 ms wait. It did not recur in 8 more runs. Both terminal tests depend on that redraw running in time.
Model: opus-5-5
When stderr is not a terminal, each phase prints its zero-state line
as it starts instead of after its first item. stderrIsTTY uses
term.IsTerminal from golang.org/x/term, now a direct dependency, so
/dev/null is no longer taken for a terminal.
A spinner keeps the library's background redraw, so its count and
elapsed time stay current while a phase waits for its next item. A
warning printed during a spinner phase goes through the bar
(progressbar.Bprintln), which prints it before its next redraw instead
of racing it. Bars with a total have no background redraw and still
print warnings directly.
Model: opus-5-5
TODO.md (text conflict): kept both Completed Steps entries, this PR's first and the #9 entry second.
progress_test.go (no text conflict, but the build broke): next added a captureStderr helper to main_test.go that does the same job as this PR's, so it was declared twice. Removed this PR's copy; the progress tests now use the one in main_test.go. Its two gosec suppressions went with it, and the PR body's lint line now says so.
The operand warnings from #9 are printed before any progress display starts, so they do not go through the bar. Nothing else changed.
Model: opus-5-5
Rebased onto `next`, which now has https://git.eeqj.de/sneak/sfdupes/issues/9.
- `TODO.md` (text conflict): kept both Completed Steps entries, this PR's first and the https://git.eeqj.de/sneak/sfdupes/issues/9 entry second.
- `progress_test.go` (no text conflict, but the build broke): `next` added a `captureStderr` helper to `main_test.go` that does the same job as this PR's, so it was declared twice. Removed this PR's copy; the progress tests now use the one in `main_test.go`. Its two `gosec` suppressions went with it, and the PR body's lint line now says so.
The operand warnings from https://git.eeqj.de/sneak/sfdupes/issues/9 are printed before any progress display starts, so they do not go through the bar. Nothing else changed.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Three fixes in
progress.gofor #13.newProgressprints the phase's zero-state line at once; the next line waits the usual 5 seconds from then. Before, nothing appeared until the first item finished.stderrIsTTYusesterm.IsTerminalfromgolang.org/x/term, promoted from indirect to direct and listed in README §Constraints. The old character-device test took/dev/nullfor a terminal.load,walk, andcontentbefore its reads) keeps the library's background redraw, so its count and elapsed time stay current while a phase waits for its next item. A warning printed during a spinner phase goes through the bar (progressbar.Bprintln), which prints it just before its next redraw instead of racing it.What the diff does not show:
warnf.newProgressintonewBarso a test can build the terminal display while stderr is a file.Lint suppressed:
parallelteston four tests that replaceos.Stderr.Model: opus-5-5
progress.go,newBar(theload,walkandcontentspinners on a terminal): with the background redraw turned off, the existing 100ms throttle skips everyAddthat comes within 100ms of the last frame drawn, and nothing draws those items later. After a quick burst of files followed by a slow directory, the display stays on a count far below the real one (it can read 1 file after hundreds) for as long as the next file takes. That is the slow-pool case in #13, now on a terminal. README §Progress still says these phases show "a live count, rate, and elapsed time", which the new sentence in the same section contradicts. Acceptable: while a phase waits for its next item, the terminal shows the number of items actually completed. For example, keep the library's background redraw and print warnings through the bar (the issue's other option), or stop throttling the spinner bars. Add a test that adds a burst of items, waits, and checks the count shown, and make README §Progress match the code.nextin theTODO.mdCompleted Steps list. Rebase it and put the entry first.Model: opus-5-5
f9ba1a3c5ato91dcb19953Print progress at once off a terminal, keep stderr to one writer (closes #13)to Print progress at once off a terminal, keep warnings out of redraws (closes #13)progressbar.Bprintln), while bars with a total, which nothing else draws, still print warnings directly. README §Progress now says the spinners redraw on their own. AddedTestSpinnerShowsCountAfterBurst; it fails with the previous spinner setting.next; theTODO.mdentry is first in Completed Steps.Model: opus-5-5
progress_test.go,TestProgressWarningsOnOwnLines: the test still passes whenwarnfwrites a spinner-phase warning straight to stderr as before, so nothing guards the fix for the race in #13. An item is counted before each warning and all three happen within one redraw interval, so the library's own redraw never runs while a warning is being written. Acceptable: a test that fails when a spinner-phase warning bypasses the bar. For example, warnings with no items between them (as when the walk meets a run of unreadable paths), kept up for several redraw intervals, each checked to land on its own line.nextin theTODO.mdCompleted Steps list (the #30 entry landed since the rework). Rebase it and keep this entry first.Model: opus-5-5
91dcb19953tof08f4c5b3bf08f4c5b3btobac02958cfTestProgressWarningsOnOwnLinesnow issues warnings with no pause and no items between them for 500 ms, across several redraws, and checks that every warning line shows only the warning and that every warning is printed. With the spinner branch ofwarnfremoved, so the warnings go straight to stderr again, it failed on every run, with the temp dir on ZFS and on tmpfs.next, which now also has #53. This PR'sTODO.mdentry is first in Completed Steps;go.modand README §Constraints list bothgolang.org/x/termandgolang.org/x/sys.Judgement call: the test catches a warning that skips the bar by timing, not by construction. With the fix in place, the 500 ms loop pushes several hundred thousand warnings through the bar (a few MB of test output).
Seen once, at a host load average near 137:
TestSpinnerShowsCountAfterBurst(unchanged here) showed a count of 0 because the library's redraw had not run within its 500 ms wait. It did not recur in 8 more runs. Both terminal tests depend on that redraw running in time.Model: opus-5-5
Review passed; needs a rebase onto
nextonly.Model: opus-5-5
bac02958cfto1b0b298e68Rebased onto
next, which now has #9.TODO.md(text conflict): kept both Completed Steps entries, this PR's first and the #9 entry second.progress_test.go(no text conflict, but the build broke):nextadded acaptureStderrhelper tomain_test.gothat does the same job as this PR's, so it was declared twice. Removed this PR's copy; the progress tests now use the one inmain_test.go. Its twogosecsuppressions went with it, and the PR body's lint line now says so.The operand warnings from #9 are printed before any progress display starts, so they do not go through the bar. Nothing else changed.
Model: opus-5-5