Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ab30f183d |
@@ -289,9 +289,12 @@ are now tracked only in the [issues](https://git.eeqj.de/sneak/mfer/issues).
|
||||
else the directory holding the manifest, or the current directory for a
|
||||
manifest given by URL. So `mfer check /media/drive` checks a drive against
|
||||
the `index.mf` at its root, from any directory
|
||||
- warns about each file under the base directory that the manifest does not
|
||||
list, hidden files included; with `--no-extra-files` each one is a failure
|
||||
instead
|
||||
- warns about each regular file under the base directory that the manifest
|
||||
does not list, hidden files included, and each symlink there to a regular
|
||||
file, which gen lists only with `--follow-symlinks`; with
|
||||
`--no-extra-files` each one is a failure instead. A named pipe, socket or
|
||||
device, a symlink to a directory and a broken symlink are never reported,
|
||||
since gen cannot list them
|
||||
- `mfer freshen` / `mfer freshen .`
|
||||
- rewrites `index.mf` to list the files now under the directory holding it,
|
||||
or under the one `--base` names, hashing only the files that are new or
|
||||
|
||||
@@ -960,6 +960,53 @@ func TestCheckWarnsAboutUnlistedFiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckReportsUnlistedSymlinkToFileOnly makes a tree holding a symlink
|
||||
// to a directory, one to a file and a broken one. gen lists the symlink to
|
||||
// the file only with --follow-symlinks, and never lists the other two, so
|
||||
// check --no-extra-files passes on the manifest gen --follow-symlinks writes
|
||||
// and fails only on the symlink to the file on the one plain gen writes.
|
||||
func TestCheckReportsUnlistedSymlinkToFileOnly(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
genFlags []string
|
||||
exitCode int
|
||||
extras []string // what check reports as not in the manifest
|
||||
}{
|
||||
"gen --follow-symlinks": {[]string{"--follow-symlinks"}, 0, nil},
|
||||
"plain gen": {nil, 1, []string{"filelink"}},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := t.TempDir()
|
||||
fs := afero.NewOsFs()
|
||||
writeTestTree(t, fs, dir)
|
||||
require.NoError(t, os.Symlink(testSubdir, filepath.Join(dir, "dirlink")))
|
||||
require.NoError(t, os.Symlink(testFileTxt, filepath.Join(dir, "filelink")))
|
||||
require.NoError(t,
|
||||
os.Symlink("nowhere", filepath.Join(dir, "brokenlink")))
|
||||
|
||||
opts := testOpts(slices.Concat(
|
||||
[]string{testApp, cmdGenerate, "-q"}, tc.genFlags, []string{dir},
|
||||
), fs)
|
||||
require.Equal(t, 0, runCLI(opts), "stderr: %s", testStderr(t, opts))
|
||||
|
||||
opts = testOpts([]string{testApp, cmdCheck, testFlagNoExtra, dir}, fs)
|
||||
exitCode := runCLI(opts)
|
||||
stderr := testStderr(t, opts)
|
||||
|
||||
assert.Equal(t, tc.exitCode, exitCode, "stderr: %s", stderr)
|
||||
assert.Equal(t, len(tc.extras),
|
||||
strings.Count(stderr, "not in manifest"), stderr)
|
||||
|
||||
for _, extra := range tc.extras {
|
||||
assert.Contains(t, stderr, "EXTRA: "+extra)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckNeverReportsManifest keeps the manifest inside the checked tree,
|
||||
// under several names and path spellings, and names the tree both directly
|
||||
// and through a symlink: the manifest is never reported, even under
|
||||
|
||||
+13
-10
@@ -264,11 +264,12 @@ func (c *Checker) Check(
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindExtraFiles walks the filesystem and reports files not in the manifest,
|
||||
// hidden files and directories included. The manifest file itself is not
|
||||
// reported. Anything the search cannot read, such as a directory that cannot
|
||||
// be listed, is reported with StatusError and the search goes on. Results are
|
||||
// sent to the results channel. The channel is closed when done.
|
||||
// FindExtraFiles walks the filesystem and reports the regular files, and
|
||||
// symlinks to them, that are not in the manifest, hidden files and
|
||||
// directories included. The manifest file itself is not reported. Anything
|
||||
// the search cannot read, such as a directory that cannot be listed, is
|
||||
// reported with StatusError and the search goes on. Results are sent to the
|
||||
// results channel. The channel is closed when done.
|
||||
func (c *Checker) FindExtraFiles(ctx context.Context, results chan<- Result) error {
|
||||
if results != nil {
|
||||
defer close(results)
|
||||
@@ -318,11 +319,6 @@ func (c *Checker) FindExtraFiles(ctx context.Context, results chan<- Result) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// gen never lists a named pipe, a socket or a device.
|
||||
if info.Mode()&(os.ModeNamedPipe|os.ModeSocket|os.ModeDevice) != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// A symlink is compared by what it points to, so a manifest reached
|
||||
// through one is not reported either.
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
@@ -332,6 +328,13 @@ func (c *Checker) FindExtraFiles(ctx context.Context, results chan<- Result) err
|
||||
}
|
||||
}
|
||||
|
||||
// gen lists regular files and symlinks to them only, so a named
|
||||
// pipe, a socket, a device, a symlink to a directory and a broken
|
||||
// symlink are never reported.
|
||||
if !info.Mode().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Skip the manifest file itself, however its path is spelled
|
||||
if os.SameFile(info, c.manifestInfo) {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user