1 Commits
Author SHA1 Message Date
sneak a2fdb0b55d Rewrite README.md sentence by sentence for a newcomer
check / check (push) Canceled after 0s
The old README was one dense specification: long sentences, lists
chained with commas, exceptions ahead of the rules, and release
history in the user text. This rewrite leads with what the program is
and how to use it, then gives a reference for the settings, each
subcommand, the database, the output formats, the progress display
and the exit codes. Non-goals come before the reference; the
constraints, the entrypoints and the build come last. Every statement
was checked against the code on next and against the built binary on
small trees. The section names the code comments cite are kept. Five
comments in main_test.go cite Settings, and one each in scan_test.go,
trees_test.go and exclude_test.go cites what the README now says.
TODO.md records the step.

Model: fable-5-1
2026-10-26 16:15:49 +00:00
2 changed files with 13 additions and 14 deletions
+9 -10
View File
@@ -365,7 +365,7 @@ default. An operand may be a directory or a regular file.
- No other case keeps an operand under another. An operand reached through a
symlinked directory below the outer operand is dropped too, without a line.
The outer operand's walk does not follow the symlink, so no file under the
inner operand is scanned. The records that an earlier scan left under it are
inner operand is scanned. The records an earlier scan left under it are
deleted.
- An operand that is neither a regular file nor a directory is not scanned.
`scan` prints a warning naming the path and what it is. It counts the operand
@@ -466,8 +466,8 @@ walk practical on large or busy storage pools.
operand at the path given, even when that path runs through a symlinked
directory. Such an operand can lead to the database files, and the walk
passes over them there as well. The walk prints no line for the database
files and does not count them as skipped. A record that an earlier scan left
for one of them is deleted.
files and does not count them as skipped. A record an earlier scan left for
one of them is deleted.
- By default the walk enters directories on other filesystems than its
operand's. With `-x`, it never enters a directory on a different filesystem
@@ -556,8 +556,7 @@ walk practical on large or busy storage pools.
- A file or directory that disappears while the scan runs is not an error. The
scan prints no line for it and does not count it as skipped. A path gone when
the walk reaches it gets no record, and so does a file gone when the hash
phase opens it. The records that an earlier scan left at or below it are
deleted.
phase opens it. The records an earlier scan left at or below it are deleted.
#### Concurrency
@@ -669,8 +668,8 @@ Four bytes are written as escapes:
Every other byte is written unchanged, including bytes that are not valid UTF-8,
the usual text encoding. Undoing the four escapes gives back the stored path.
Grouping and ordering use the stored path. The warnings about skipped paths that
`scan` prints are escaped the same way, so each stays one line.
Grouping and ordering use the stored path. The warnings that `scan` prints are
escaped the same way, so each warning stays one line.
The summary line on stderr gives:
@@ -1038,9 +1037,9 @@ On a terminal:
- the elapsed time;
- the time remaining.
On a terminal 80 columns wide, no line is cut short, even hours into a scan
of millions of files. A terminal made narrower during a phase is fitted at
the next draw.
On a terminal narrower than about 75 columns, a line is cut short only hours
into a scan of millions of files. A terminal made narrower during a phase is
fitted at the next draw.
- A warning printed during a phase lands on a line of its own, never inside the
display. So does every line written to stdout when stdout and stderr are the
+4 -4
View File
@@ -773,8 +773,8 @@ func TestBuildVersion(t *testing.T) {
func TestRunVersionWriteFailureIsFatal(t *testing.T) {
t.Parallel()
// README §Error handling: a failed write to stdout is a fatal error,
// exit 1, reported on stderr starting with "sfdupes:".
// README §Error handling: a stdout write failure exits 1, reported
// in one line on stderr.
var stderr bytes.Buffer
code := run([]string{"--version"}, failingWriter{}, &stderr)
@@ -1445,8 +1445,8 @@ func TestRunReportsDuringScan(t *testing.T) {
}
func TestRunStdoutClosedIsFatal(t *testing.T) {
// README §Error handling: a failed write to stdout is a fatal error,
// exit 1, reported on stderr starting with "sfdupes:".
// README §Error handling: a stdout write failure exits 1, reported
// in one line on stderr.
for _, name := range []string{cmdReport, cmdTrees, cmdInfo} {
t.Run(name, func(t *testing.T) {
t.Setenv(databaseEnv, testDBPath(t))