1 Commits
Author SHA1 Message Date
sneak 997cd6d7a6 Never report index.mf at the top of the base as unlisted in check (closes #229)
check / check (push) Canceled after 0s
gen and fetch write the manifest as index.mf at the top of the tree.
check left out only the manifest file it was given, so given a URL, or a
manifest stored elsewhere, it reported that index.mf as not in the
manifest, and --no-extra-files failed a tree fetch had just verified.
check now drops that one report for index.mf at the top of the base
directory. A manifest that lists index.mf still has it checked, and
index.mf in a subdirectory or fetch's leftover .index.mf.tmp are still
reported. The change is in package cli, which owns the default manifest
name; the Checker in package mfer is unchanged.

Model: opus-5-5
2026-10-15 20:07:45 +00:00
3 changed files with 18 additions and 50 deletions
+8 -5
View File
@@ -13,11 +13,14 @@ The structure of these files can be found
schema `mfer/mf.proto` for exact field numbers and types. Both are included in schema `mfer/mf.proto` for exact field numbers and types. Both are included in
the [project repository](https://git.eeqj.de/sneak/mfer). the [project repository](https://git.eeqj.de/sneak/mfer).
Releases are git tags named by [SemVer](https://semver.org), starting with The current version is pre-1.0 and while the repo was published in 2022, there
`v1.0.0`. No file in the tree records a version number. `mfer version` prints has not yet been any versioned release. [SemVer](https://semver.org) will be
the revision the build stamped into the binary, which for `make build` and the used for releases.
Docker image is the output of `git describe` on the checkout they build. A
binary built without that stamp, as A version is a git tag, and no file in the tree records a version number.
`mfer version` prints the revision the build stamped into the binary, which for
`make build` and the Docker image is the output of `git describe` on the
checkout they build. A binary built without that stamp, as
`go install sneak.berlin/go/mfer/cmd/mfer@<tag>` builds it, prints the module `go install sneak.berlin/go/mfer/cmd/mfer@<tag>` builds it, prints the module
version Go records in it instead. A program that imports the `mfer` package version Go records in it instead. A program that imports the `mfer` package
finds the version it was built against in its own build information finds the version it was built against in its own build information
+2 -2
View File
@@ -197,8 +197,8 @@ func countCheckFailures(
// manifest, and anything the search cannot read: each is a failure, logged // manifest, and anything the search cannot read: each is a failure, logged
// at error level, under --no-extra-files, otherwise a warning. index.mf at // at error level, under --no-extra-files, otherwise a warning. index.mf at
// the top of the base directory is never reported as absent from the // the top of the base directory is never reported as absent from the
// manifest, even when check is given another manifest or a URL, since gen // manifest, since gen and fetch write the manifest there, even when check
// and fetch write the manifest there. // is given another manifest or a URL.
func findExtraFiles( func findExtraFiles(
ctx context.Context, cmd *cli.Command, chk *mfer.Checker, failures *int64, ctx context.Context, cmd *cli.Command, chk *mfer.Checker, failures *int64,
) error { ) error {
+8 -43
View File
@@ -1192,10 +1192,9 @@ func TestCheckURLManifestWithoutTempDirectory(t *testing.T) {
// TestCheckNeverReportsIndexMfAtTopOfBase checks a tree holding index.mf at // TestCheckNeverReportsIndexMfAtTopOfBase checks a tree holding index.mf at
// its top, where gen and fetch write the manifest, against a manifest that // its top, where gen and fetch write the manifest, against a manifest that
// does not list it, given by URL and by a path outside the tree: check never // does not list it, given by URL and by a path outside the tree: the check
// reports it, and passes with and without --no-extra-files. index.mf in a // passes under --no-extra-files. index.mf in a subdirectory, and the temp
// subdirectory, and the temp file fetch saves index.mf through, are still // file fetch saves index.mf through, are still reported.
// reported.
func TestCheckNeverReportsIndexMfAtTopOfBase(t *testing.T) { func TestCheckNeverReportsIndexMfAtTopOfBase(t *testing.T) {
t.Parallel() t.Parallel()
@@ -1221,22 +1220,16 @@ func TestCheckNeverReportsIndexMfAtTopOfBase(t *testing.T) {
require.NoError(t, os.WriteFile( require.NoError(t, os.WriteFile(
filepath.Join(base, defaultManifestName), manifest, 0o600)) filepath.Join(base, defaultManifestName), manifest, 0o600))
check := func(flags ...string) (int, string) { check := func() (int, string) {
opts := testOpts(slices.Concat( opts := testOpts([]string{
[]string{testApp, cmdCheck}, flags, testApp, cmdCheck, testFlagNoExtra, testFlagBase, base, manifestArg,
[]string{testFlagBase, base, manifestArg}, }, afero.NewOsFs())
), afero.NewOsFs())
return runCLI(opts), testStderr(t, opts) return runCLI(opts), testStderr(t, opts)
} }
exitCode, stderr := check() exitCode, stderr := check()
assert.Equal(t, 0, exitCode, "stderr: %s", stderr) assert.Equal(t, 0, exitCode, "stderr: %s", stderr)
assert.NotContains(t, stderr, "EXTRA: "+defaultManifestName)
exitCode, stderr = check(testFlagNoExtra)
assert.Equal(t, 0, exitCode, "stderr: %s", stderr)
assert.NotContains(t, stderr, "EXTRA: "+defaultManifestName)
reported := []string{ reported := []string{
testSubdir + "/" + defaultManifestName, testSubdir + "/" + defaultManifestName,
@@ -1250,9 +1243,8 @@ func TestCheckNeverReportsIndexMfAtTopOfBase(t *testing.T) {
os.WriteFile(filepath.Join(base, path), manifest, 0o600)) os.WriteFile(filepath.Join(base, path), manifest, 0o600))
} }
exitCode, stderr = check(testFlagNoExtra) exitCode, stderr = check()
assert.Equal(t, 1, exitCode, "stderr: %s", stderr) assert.Equal(t, 1, exitCode, "stderr: %s", stderr)
assert.NotContains(t, stderr, "EXTRA: "+defaultManifestName)
for _, path := range reported { for _, path := range reported {
assert.Contains(t, stderr, "EXTRA: "+path) assert.Contains(t, stderr, "EXTRA: "+path)
@@ -1331,33 +1323,6 @@ func TestCheckWithUnlistableDirectory(t *testing.T) {
assert.Contains(t, testStderr(t, opts), "unlisted.txt") assert.Contains(t, testStderr(t, opts), "unlisted.txt")
} }
// TestCheckReportsUnreadableIndexMfAtTopOfBase has a directory named
// index.mf at the top of the base that cannot be listed. check leaves out
// only the report that index.mf is not in the manifest, so it reports the
// error and fails under --no-extra-files.
func TestCheckReportsUnreadableIndexMfAtTopOfBase(t *testing.T) {
t.Parallel()
unreadable := filepath.Join(testDir, defaultManifestName)
mem := afero.NewMemMapFs()
require.NoError(t, mem.MkdirAll(unreadable, 0o755))
writeTestFile(t, mem, testFile1, "hello")
opts := testOpts([]string{
testApp, cmdGenerate, "-q", "-o", testManifest, testDir,
}, mem)
require.Equal(t, 0, runCLI(opts), "stderr: %s", testStderr(t, opts))
fs := unlistableDirFs{Fs: mem, dir: unreadable}
opts = testOpts([]string{
testApp, cmdCheck, testFlagNoExtra, testFlagBase, testDir, testManifest,
}, fs)
assert.Equal(t, 1, runCLI(opts), "stderr: %s", testStderr(t, opts))
assert.Contains(t, testStderr(t, opts), "ERROR: "+defaultManifestName)
}
func TestGenerateAtomicWriteNoTempFileOnSuccess(t *testing.T) { func TestGenerateAtomicWriteNoTempFileOnSuccess(t *testing.T) {
t.Parallel() t.Parallel()