Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9e0a37b14 |
No files matched your search
@@ -112,10 +112,18 @@ 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"). As the file `/etc/cron.d/sfdupes`:
|
walk").
|
||||||
|
|
||||||
|
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 /usr/local/bin/sfdupes scan /srv 2>>/var/log/sfdupes.log || tail -n 3 /var/log/sfdupes.log
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
- 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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
- The usage line of `scan` no longer ends in `[flags]`. It is the line
|
- `README.md` says what a disk that is not mounted does to the database. The
|
||||||
`README.md` shows under "Subcommands" (2026-11-11,
|
daily `cron` line runs `scan` only when `mountpoint` reports `/srv` as mounted
|
||||||
https://git.eeqj.de/sneak/sfdupes/issues/169)
|
(2026-11-11, https://git.eeqj.de/sneak/sfdupes/issues/175)
|
||||||
- `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,
|
||||||
|
|||||||
@@ -215,13 +215,10 @@ 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...",
|
||||||
// The Use line already names every flag, so cobra must not
|
Short: short,
|
||||||
// append its generic "[flags]" to it.
|
Long: short + ".\n\n" + defaultExcludesHelp(runtime.GOOS),
|
||||||
DisableFlagsInUseLine: true,
|
Args: cobra.MinimumNArgs(1),
|
||||||
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)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -714,34 +714,6 @@ 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()
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user