Name the database each command uses on stderr (closes #111)
check / check (push) Canceled after 0s

scan, report and trees now print one line on stderr before anything
else, naming the database and whether its path is the default or comes
from SFDUPES_DATABASE; scan also says when the file is new. report and
trees print it before opening the database, so a missing-database error
follows it. A relative path gets the working directory put in front of
it, with its symlinks resolved as the kernel reports it, and is not
cleaned: a ".." after a symlink names another file than the cleaned
path does. README "Database" lists when scan writes each file.

Unverified: the line on a terminal has no test of its own.

Model: opus-5-5
This commit was merged in pull request #118.
This commit is contained in:
2026-10-16 15:28:02 +02:00
parent 198cefa152
commit 264817c413
9 changed files with 412 additions and 36 deletions
+21 -5
View File
@@ -91,9 +91,11 @@ type fileMeta struct {
// least one other file shares are ever hashed: a size-unique file
// cannot be a duplicate. A file of headTailMin or more gets its content
// hash only when its size, head, and tail match another file's. Flag
// parsing and the at-least-one-operand check are done by cobra. The
// scan holds the lock on the database for its whole run, so a second
// scan fails before it walks the filesystem or opens the database.
// parsing and the at-least-one-operand check are done by cobra. Before
// anything else, the scan names the database on stderr, saying whether
// it is new. The scan holds the lock on the database for its whole
// run, so a second scan fails before it walks the filesystem or opens
// the database.
// Errors are returned rather than exiting, so that the deferred close —
// which takes the database out of WAL mode — always runs, and the lock
// is released after it. When ctx is cancelled, as by the SIGINT or
@@ -104,12 +106,26 @@ type fileMeta struct {
func runScan(ctx context.Context, roots []string, workers int,
oneFS bool,
) error {
roots, err := resolveRoots(roots)
dbPath, source, err := databasePath()
if err != nil {
return err
}
dbPath := databasePath()
// A database file missing now is created by lockScanDatabase below.
what := "database"
_, err = os.Stat(dbPath)
if errors.Is(err, fs.ErrNotExist) {
what = "new database"
}
fmt.Fprintf(os.Stderr, "scan: %s %s (%s)\n", what, escapePath(dbPath),
source)
roots, err = resolveRoots(roots)
if err != nil {
return err
}
lock, err := lockScanDatabase(dbPath)
if err != nil {