From b60cb5a0bdc1dae6823d93feb429cf3321c69968 Mon Sep 17 00:00:00 2001 From: sneak Date: Thu, 8 Oct 2026 01:24:00 +0000 Subject: [PATCH] List a file given to Scanner.EnumeratePath by its name (closes #182) EnumeratePath treated its argument as a directory: given a file, it listed it under an empty path and ToManifest stopped with "path cannot be empty". It now hands its one path to EnumeratePaths, which lists a directory's files by their paths under it and a file by its name, as EnumerateFile does. EnumeratePath's own resolution of a directory named through a symlink goes with it, since EnumeratePaths does the same. Model: opus-5-5 --- mfer/scanner.go | 24 +++--------------------- mfer/scanner_test.go | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/mfer/scanner.go b/mfer/scanner.go index d8be7bc..5326bde 100644 --- a/mfer/scanner.go +++ b/mfer/scanner.go @@ -139,33 +139,15 @@ func (s *Scanner) EnumerateFile(filePath string) error { return s.enumerateFileWithInfo(filepath.Base(abs), basePath, info, nil) } -// EnumeratePath walks a directory path and adds all files to the scanner. +// EnumeratePath adds inputPath, a directory or a file, to the scanner as +// EnumeratePaths adds each of its paths. // If progress is non-nil, status updates are sent as files are discovered. // The progress channel is closed when the method returns. func (s *Scanner) EnumeratePath( inputPath string, progress chan<- EnumerateStatus, ) error { - if progress != nil { - defer close(progress) - } - - abs, err := filepath.Abs(inputPath) - if err != nil { - return err - } - - // The walk does not follow a symlink at its top, so a directory named - // through one is resolved first. If that fails, the directory is walked - // as named and the walk reports the problem. - resolved, err := filepath.EvalSymlinks(abs) - if err == nil { - abs = resolved - } - - afs := afero.NewReadOnlyFs(afero.NewBasePathFs(s.fs, abs)) - - return s.enumerateFS(afs, abs, progress) + return s.EnumeratePaths(progress, inputPath) } // EnumeratePaths adds to the scanner the files under each directory path, diff --git a/mfer/scanner_test.go b/mfer/scanner_test.go index 1ceb6b7..a598596 100644 --- a/mfer/scanner_test.go +++ b/mfer/scanner_test.go @@ -118,6 +118,27 @@ func TestScannerEnumeratePathWithProgress(t *testing.T) { assert.Equal(t, FileSize(6), final.BytesFound) } +// TestScannerEnumeratePathFile gives EnumeratePath a file: it is listed +// by its name, as EnumerateFile lists it, and the manifest can be built. +func TestScannerEnumeratePathFile(t *testing.T) { + t.Parallel() + + fs := afero.NewMemMapFs() + require.NoError(t, fs.MkdirAll("/dir", 0o755)) + require.NoError(t, afero.WriteFile(fs, "/dir/one.txt", []byte("1"), 0o644)) + + s := NewScannerWithOptions(&ScannerOptions{Fs: fs}) + require.NoError(t, s.EnumeratePath("/dir/one.txt", nil)) + + var buf bytes.Buffer + require.NoError(t, s.ToManifest(context.Background(), &buf, nil)) + + m, err := NewManifestFromReader(&buf) + require.NoError(t, err) + require.Len(t, m.Files(), 1) + assert.Equal(t, "one.txt", m.Files()[0].GetPath()) +} + func TestScannerEnumeratePaths(t *testing.T) { t.Parallel()