Compare commits

..
Author SHA1 Message Date
sneak b7e6ff9df1 scan: drop the stray [flags] from the usage line (closes #169)
check / check (push) Successful in 2m41s
The scan Use string already names every flag, so cobra no longer appends
its generic [flags]. A test checks the usage line in the help and in the
usage error against the one README.md shows.

Model: opus-5-5
2026-11-11 03:55:16 +00:00
4 changed files with 40 additions and 17 deletions

No files matched your search

+2 -10
View File
@@ -112,18 +112,10 @@ docker run --rm -v /var/lib/sfdupes:/var/lib/sfdupes sfdupes report > dupes.tsv
Run `scan` as root, so that it can read every file. `scan` warns about a Run `scan` as root, so that it can read every file. `scan` warns about a
directory it cannot read, and about a new or changed file it cannot read. It directory it cannot read, and about a new or changed file it cannot read. It
skips the path and deletes the records at or below it (see "Rules for the skips the path and deletes the records at or below it (see "Rules for the
walk"). walk"). As the file `/etc/cron.d/sfdupes`:
A disk that is not mounted leaves an empty directory at its mount point. `scan`
finds no files there, deletes every record under it and exits 0. The next scan
with the disk mounted reads every file on it again. So the line below runs
`scan` only when `mountpoint` reports `/srv` as mounted. Otherwise it prints
`a disk is not mounted; scan of /srv skipped`, which `cron` mails, and scans
nothing. For each other disk mounted below `/srv`, add `&& mountpoint -q` and
its mount point after the first test. As the file `/etc/cron.d/sfdupes`:
``` ```
30 3 * * * root if mountpoint -q /srv; then /usr/local/bin/sfdupes scan /srv 2>>/var/log/sfdupes.log || tail -n 3 /var/log/sfdupes.log; else echo "a disk is not mounted; scan of /srv skipped"; fi 30 3 * * * root /usr/local/bin/sfdupes scan /srv 2>>/var/log/sfdupes.log || tail -n 3 /var/log/sfdupes.log
``` ```
- The first scan creates `/var/lib/sfdupes/db.sqlite` and its directory. To keep - The first scan creates `/var/lib/sfdupes/db.sqlite` and its directory. To keep
+3 -3
View File
@@ -29,9 +29,9 @@
Newest first. An entry ends with its date and its issue or branch, where those Newest first. An entry ends with its date and its issue or branch, where those
are known. are known.
- `README.md` says what a disk that is not mounted does to the database. The - The usage line of `scan` no longer ends in `[flags]`. It is the line
daily `cron` line runs `scan` only when `mountpoint` reports `/srv` as mounted `README.md` shows under "Subcommands" (2026-11-11,
(2026-11-11, https://git.eeqj.de/sneak/sfdupes/issues/175) https://git.eeqj.de/sneak/sfdupes/issues/169)
- `report` and `trees` leave out empty files. `report` writes no group of size - `report` and `trees` leave out empty files. `report` writes no group of size
0, and `trees` writes no group whose trees hold 0 bytes. An empty file still 0, and `trees` writes no group whose trees hold 0 bytes. An empty file still
counts toward a tree's digest (2026-11-11, counts toward a tree's digest (2026-11-11,
+7 -4
View File
@@ -215,10 +215,13 @@ func newScanCommand() *cobra.Command {
short := "Walk trees and synchronize the scan database" short := "Walk trees and synchronize the scan database"
scanCmd := &cobra.Command{ scanCmd := &cobra.Command{
Use: cmdScan + " [--workers N] [-x] [--no-default-excludes] PATH...", Use: cmdScan + " [--workers N] [-x] [--no-default-excludes] PATH...",
Short: short, // The Use line already names every flag, so cobra must not
Long: short + ".\n\n" + defaultExcludesHelp(runtime.GOOS), // append its generic "[flags]" to it.
Args: cobra.MinimumNArgs(1), DisableFlagsInUseLine: true,
Short: short,
Long: short + ".\n\n" + defaultExcludesHelp(runtime.GOOS),
Args: cobra.MinimumNArgs(1),
PreRunE: func(cmd *cobra.Command, _ []string) error { PreRunE: func(cmd *cobra.Command, _ []string) error {
return checkScanWorkers(cmd, scanWorkers) return checkScanWorkers(cmd, scanWorkers)
}, },
+28
View File
@@ -714,6 +714,34 @@ func TestRunHelp(t *testing.T) {
} }
} }
func TestRunScanUsageLine(t *testing.T) {
t.Parallel()
// README §Subcommands shows this usage line for scan, and the help
// and the usage error both print it.
const want = "\n sfdupes scan [--workers N] [-x] [--no-default-excludes] PATH...\n"
cases := map[string][]string{
"help": {cmdScan, "-h"},
"missing paths": {cmdScan},
}
for name, args := range cases {
t.Run(name, func(t *testing.T) {
t.Parallel()
var stdout, stderr bytes.Buffer
run(args, &stdout, &stderr)
if !strings.Contains(stderr.String(), want) {
t.Errorf("run(%v) stderr = %q, want the usage line %q",
args, stderr.String(), want)
}
})
}
}
func TestRunVersion(t *testing.T) { func TestRunVersion(t *testing.T) {
t.Parallel() t.Parallel()