Default the manifest to index.mf and keep it out of its own listing (closes #100)
check / check (push) Failing after 1s
check / check (push) Failing after 1s
mfer gen now writes index.mf instead of .index.mf, the name fetch requests and the README calls the standard filename. Given a directory, check, freshen, list and export look only for index.mf; .index.mf is no longer recognized. Because index.mf is not hidden, gen and freshen leave out of their own listing the manifest they write and a temp file an interrupted run left beside it, matched by file identity (os.SameFile) however the path is spelled. The scanner takes these as a plain ExcludePaths list; manifestTempPath alone names the temp file, for both writes, both skips and the tests. Model: opus-5-5
This commit was merged in pull request #136.
This commit is contained in:
@@ -21,6 +21,8 @@ const (
|
||||
testExistsFile = "exists.txt"
|
||||
testManifestPath = "/manifest.mf"
|
||||
testDataDir = "/data"
|
||||
// testDataManifestPath is a manifest kept inside the checked tree.
|
||||
testDataManifestPath = testDataDir + "/index.mf"
|
||||
)
|
||||
|
||||
func TestStatusString(t *testing.T) {
|
||||
@@ -464,7 +466,7 @@ func TestFindExtraFilesSkipsManifestAndDotfiles(t *testing.T) {
|
||||
manifestFiles := map[string][]byte{
|
||||
testFile1: []byte("in manifest"),
|
||||
}
|
||||
createTestManifest(t, fs, "/data/.index.mf", manifestFiles)
|
||||
createTestManifest(t, fs, testDataManifestPath, manifestFiles)
|
||||
createFilesOnDisk(t, fs, map[string][]byte{
|
||||
testFile1: []byte("in manifest"),
|
||||
})
|
||||
@@ -476,7 +478,7 @@ func TestFindExtraFilesSkipsManifestAndDotfiles(t *testing.T) {
|
||||
require.NoError(t, afero.WriteFile(fs, "/data/extra.txt", []byte("extra"), 0o644))
|
||||
|
||||
chk, err := NewChecker(&CheckerOptions{
|
||||
ManifestPath: "/data/.index.mf",
|
||||
ManifestPath: testDataManifestPath,
|
||||
BasePath: testDataDir,
|
||||
Fs: fs,
|
||||
})
|
||||
@@ -491,7 +493,7 @@ func TestFindExtraFilesSkipsManifestAndDotfiles(t *testing.T) {
|
||||
extras = append(extras, r)
|
||||
}
|
||||
|
||||
// Should only report extra.txt, not .hidden, .config/settings, or .index.mf
|
||||
// Should only report extra.txt, not .hidden, .config/settings, or index.mf
|
||||
for _, e := range extras {
|
||||
t.Logf("extra: %s", e.Path)
|
||||
}
|
||||
@@ -656,7 +658,7 @@ func TestFindExtraFilesSkipsDotfiles(t *testing.T) {
|
||||
files := map[string][]byte{
|
||||
testFile1: []byte("in manifest"),
|
||||
}
|
||||
createTestManifest(t, fs, "/data/.index.mf", files)
|
||||
createTestManifest(t, fs, testDataManifestPath, files)
|
||||
createFilesOnDisk(t, fs, files)
|
||||
|
||||
// Add dotfiles and manifest file on disk
|
||||
@@ -666,7 +668,7 @@ func TestFindExtraFilesSkipsDotfiles(t *testing.T) {
|
||||
afero.WriteFile(fs, "/data/.git/config", []byte("git config"), 0o644))
|
||||
|
||||
chk, err := NewChecker(&CheckerOptions{
|
||||
ManifestPath: "/data/.index.mf",
|
||||
ManifestPath: testDataManifestPath,
|
||||
BasePath: testDataDir,
|
||||
Fs: fs,
|
||||
})
|
||||
@@ -695,11 +697,11 @@ func TestFindExtraFilesSkipsManifestFile(t *testing.T) {
|
||||
files := map[string][]byte{
|
||||
testFile1: []byte("content"),
|
||||
}
|
||||
createTestManifest(t, fs, "/data/index.mf", files)
|
||||
createTestManifest(t, fs, testDataManifestPath, files)
|
||||
createFilesOnDisk(t, fs, files)
|
||||
|
||||
chk, err := NewChecker(&CheckerOptions{
|
||||
ManifestPath: "/data/index.mf",
|
||||
ManifestPath: testDataManifestPath,
|
||||
BasePath: testDataDir,
|
||||
Fs: fs,
|
||||
})
|
||||
|
||||
+22
-1
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -57,6 +58,8 @@ type ScannerOptions struct {
|
||||
SigningOptions *SigningOptions
|
||||
// Seed, if set, derives a deterministic UUID from this seed.
|
||||
Seed string
|
||||
// ExcludePaths lists files to leave out of the listing, matched with os.SameFile.
|
||||
ExcludePaths []string
|
||||
}
|
||||
|
||||
// FileEntry represents a file that has been enumerated.
|
||||
@@ -75,6 +78,7 @@ type Scanner struct {
|
||||
totalBytes FileSize // cached sum of all file sizes
|
||||
options *ScannerOptions
|
||||
fs afero.Fs
|
||||
excluded []fs.FileInfo // the files named in ExcludePaths that exist
|
||||
}
|
||||
|
||||
// NewScanner creates a new Scanner with default options.
|
||||
@@ -93,11 +97,22 @@ func NewScannerWithOptions(opts *ScannerOptions) *Scanner {
|
||||
fs = afero.NewOsFs()
|
||||
}
|
||||
|
||||
return &Scanner{
|
||||
s := &Scanner{
|
||||
files: make([]*FileEntry, 0),
|
||||
options: opts,
|
||||
fs: fs,
|
||||
}
|
||||
|
||||
// A path that cannot be stat'd, normally because no file is there,
|
||||
// needs no leaving out.
|
||||
for _, p := range opts.ExcludePaths {
|
||||
info, err := s.fs.Stat(p)
|
||||
if err == nil {
|
||||
s.excluded = append(s.excluded, info)
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// EnumerateFile adds a single file to the scanner, calling stat() to get metadata.
|
||||
@@ -435,6 +450,12 @@ func (s *Scanner) enumerateFileWithInfo(
|
||||
info = realInfo
|
||||
}
|
||||
|
||||
for _, excluded := range s.excluded {
|
||||
if os.SameFile(info, excluded) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
entry := &FileEntry{
|
||||
Path: RelFilePath(cleanPath),
|
||||
AbsPath: AbsFilePath(absPath),
|
||||
|
||||
Reference in New Issue
Block a user