Make scan paths required operands; add -x/--one-file-system
All checks were successful
check / check (push) Successful in 4s
All checks were successful
check / check (push) Successful in 4s
scan now takes one or more PATH operands (directories or regular files) via cobra flags instead of the -root flag with its /srv default; invoking scan with no operand is a usage error and a nonexistent operand is fatal. Filesystem boundaries are crossed by default; the new -x/--one-file-system flag (GNU du/rsync convention) stops the walk at each operand's filesystem, implemented by comparing lstat device IDs with build-tagged helpers for darwin's int32 Dev. Verified against a real mounted disk image: default crosses, -x does not, --one-file-system is identical to -x.
This commit is contained in:
91
scan_test.go
91
scan_test.go
@@ -129,7 +129,7 @@ func TestWalkPass(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
paths, errs := walkPass(dir)
|
||||
paths, errs := walkPass([]string{dir}, false)
|
||||
if errs != 0 {
|
||||
t.Fatalf("errs = %d, want 0", errs)
|
||||
}
|
||||
@@ -141,6 +141,93 @@ func TestWalkPass(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalkPassMultipleRoots(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rootA := t.TempDir()
|
||||
rootB := t.TempDir()
|
||||
want := []string{
|
||||
writeFile(t, rootA, "a1", []byte("1")),
|
||||
writeFile(t, rootA, "sub/a2", []byte("2")),
|
||||
writeFile(t, rootB, "b1", []byte("3")),
|
||||
}
|
||||
|
||||
paths, errs := walkPass([]string{rootA, rootB}, false)
|
||||
if errs != 0 {
|
||||
t.Fatalf("errs = %d, want 0", errs)
|
||||
}
|
||||
|
||||
// Operands are walked in the order given.
|
||||
if !slices.Equal(paths, want) {
|
||||
t.Fatalf("paths = %q, want %q", paths, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalkPassFileAndSymlinkOperands(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := t.TempDir()
|
||||
f := writeFile(t, dir, "plain", []byte("data"))
|
||||
|
||||
link := filepath.Join(dir, "link")
|
||||
|
||||
err := os.Symlink(f, link)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// A regular-file operand is emitted as itself.
|
||||
paths, errs := walkPass([]string{f}, false)
|
||||
if errs != 0 || !slices.Equal(paths, []string{f}) {
|
||||
t.Fatalf("file operand: paths = %q, errs = %d", paths, errs)
|
||||
}
|
||||
|
||||
// A symlink operand is not followed and yields nothing.
|
||||
paths, errs = walkPass([]string{link}, false)
|
||||
if errs != 0 || len(paths) != 0 {
|
||||
t.Fatalf("symlink operand: paths = %q, errs = %d", paths, errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalkPassOneFilesystemSameFS(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Everything in one filesystem: -x must not skip anything.
|
||||
dir := t.TempDir()
|
||||
want := []string{
|
||||
writeFile(t, dir, "a", []byte("a")),
|
||||
writeFile(t, dir, "sub/deep/b", []byte("b")),
|
||||
}
|
||||
|
||||
paths, errs := walkPass([]string{dir}, true)
|
||||
if errs != 0 {
|
||||
t.Fatalf("errs = %d, want 0", errs)
|
||||
}
|
||||
|
||||
slices.Sort(paths)
|
||||
|
||||
if !slices.Equal(paths, want) {
|
||||
t.Fatalf("paths = %q, want %q", paths, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceOf(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
dev1, ok1 := deviceOf(dir)
|
||||
|
||||
dev2, ok2 := deviceOf(dir)
|
||||
if !ok1 || !ok2 || dev1 != dev2 {
|
||||
t.Fatalf("deviceOf unstable: %d/%v vs %d/%v", dev1, ok1, dev2, ok2)
|
||||
}
|
||||
|
||||
if _, ok := deviceOf(filepath.Join(dir, "missing")); ok {
|
||||
t.Fatal("deviceOf reported ok for a missing path")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatPass(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -234,7 +321,7 @@ func buildSmokeTree(t *testing.T) string {
|
||||
func scanToRecords(t *testing.T, dir string) []scanRec {
|
||||
t.Helper()
|
||||
|
||||
paths, walkErrs := walkPass(dir)
|
||||
paths, walkErrs := walkPass([]string{dir}, false)
|
||||
if walkErrs != 0 {
|
||||
t.Fatalf("walk errors: %d", walkErrs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user