Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ad3993055 | ||
|
|
a4d76af8fe |
@@ -33,6 +33,10 @@
|
||||
under its operand, and counts their sizes in the size census, instead of
|
||||
deleting them (2026-10-14, https://git.eeqj.de/sneak/sfdupes/issues/99)
|
||||
|
||||
- on a terminal, a warning for the last file of a phase no longer erases the
|
||||
phase's finished bar: the bar is drawn again below the warning (2026-10-14,
|
||||
https://git.eeqj.de/sneak/sfdupes/issues/102)
|
||||
|
||||
- `scan` records mtime to the nanosecond, as whole seconds in `mtime` plus
|
||||
`mtime_nsec`, and compares it at that resolution, so a same-size rewrite
|
||||
within the same second is re-hashed (2026-10-07,
|
||||
|
||||
@@ -139,6 +139,13 @@ func (p *progress) warnf(format string, args ...any) {
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stderr, msg)
|
||||
|
||||
// The library never draws a finished bar again, so the warning for
|
||||
// a pass's last item would erase it for good: draw its last frame
|
||||
// again below the warning.
|
||||
if p.bar != nil && p.bar.IsFinished() {
|
||||
fmt.Fprint(os.Stderr, p.bar.String())
|
||||
}
|
||||
}
|
||||
|
||||
// finish terminates the pass's display. A bar whose pass stopped short
|
||||
|
||||
@@ -187,3 +187,25 @@ func TestBarStoppedShortKeepsCount(t *testing.T) {
|
||||
t.Errorf("terminal shows %q, want a count of 2 of 10", shown)
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarningAfterLastItemKeepsBar checks that a warning printed after
|
||||
// a pass's last item, as for a failed read of the last file, leaves the
|
||||
// pass's finished bar on the terminal below the warning.
|
||||
//
|
||||
//nolint:paralleltest // captureStderr replaces the process-wide os.Stderr
|
||||
func TestWarningAfterLastItemKeepsBar(t *testing.T) {
|
||||
stderr := captureStderr(t)
|
||||
p := &progress{
|
||||
label: "hash", total: 2, start: time.Now(),
|
||||
bar: newBar("hash", 2),
|
||||
}
|
||||
|
||||
p.increment()
|
||||
p.increment()
|
||||
p.warnf("warning")
|
||||
p.finish()
|
||||
|
||||
if shown := lastFrame(stderr()); !strings.Contains(shown, "(2/2,") {
|
||||
t.Errorf("terminal shows %q, want a count of 2 of 2", shown)
|
||||
}
|
||||
}
|
||||
|
||||
+18
-5
@@ -1138,20 +1138,28 @@ func TestSubdirJobStatError(t *testing.T) {
|
||||
// TestScanOneFilesystemKeepsOtherFilesystemRecords checks that with -x a
|
||||
// record below a directory the walk does not enter, because it is on
|
||||
// another filesystem than its operand, counts as outside the operands:
|
||||
// it is not deleted, and its size joins the size census. The walk starts
|
||||
// from an operand device that no directory here is on, so no second
|
||||
// real filesystem is needed; the phases after it run as runPhases runs
|
||||
// them.
|
||||
// it is not deleted, and its size joins the size census. The record of
|
||||
// a gone file that is not below that directory is still deleted, even
|
||||
// when its path begins with the directory's name. The walk starts from
|
||||
// an operand device that no directory here is on, so no second real
|
||||
// filesystem is needed; the phases after it run as runPhases runs them.
|
||||
func TestScanOneFilesystemKeepsOtherFilesystemRecords(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := t.TempDir()
|
||||
db := openTestDB(t)
|
||||
|
||||
// A scan without -x records the file below mnt.
|
||||
// A scan without -x records the file below mnt, and mnt2, which is
|
||||
// beside mnt, not below it.
|
||||
mounted := writeFile(t, dir, "mnt/f", pattern(1, 100))
|
||||
gone := writeFile(t, dir, "mnt2", pattern(3, 50))
|
||||
syncTree(t, db, dir)
|
||||
|
||||
err := os.Remove(gone)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The same size as mnt/f, so it is hashed only if mnt/f's size is
|
||||
// in the census.
|
||||
added := writeFile(t, dir, "added", pattern(2, 100))
|
||||
@@ -1198,6 +1206,11 @@ func TestScanOneFilesystemKeepsOtherFilesystemRecords(t *testing.T) {
|
||||
t.Errorf("%s not hashed: the census lacks the size of %s",
|
||||
added, mounted)
|
||||
}
|
||||
|
||||
if slices.Contains(recordPaths(recs), gone) {
|
||||
t.Errorf("record for %s kept: the file is gone and not below mnt",
|
||||
gone)
|
||||
}
|
||||
}
|
||||
|
||||
// buildSmokeTree recreates the README smoke-test filesystem layout
|
||||
|
||||
Reference in New Issue
Block a user