Without --output, gen given one directory writes index.mf in that directory, and given one file writes index.mf beside it. With no path or several, it writes index.mf in the current directory as before. --output only chooses where the manifest goes. Each directory argument's files are listed by their paths under it and each file argument by its name, so with --seed and an unchanged tree the bytes are the same wherever the manifest is written, and mfer gen DIR followed by mfer check DIR passes.
The file-argument fix is in Scanner.EnumeratePaths, which gen calls with its arguments. It walked a file as if it were a directory and listed it under an empty path.
Things the diff does not show:
The --output flag no longer has a Value; outputPath in internal/cli/gen.go works out the default. An --output given with an empty value, as an unset shell variable gives it, is refused.
outputPath leaves a path that does not exist to enumeration, which fails as before.
The scan phase moved into runScanPhase so generateManifestOperation stays within the linter's function length limit.
Judgement call: a file argument is listed even when it is a dotfile, or a symlink (its target is read), whatever --include-dotfiles and --follow-symlinks say, as EnumerateFile already does. Those flags still govern what is found under a directory argument.
Scanner.EnumeratePath, the single-path form, still treats a file as a directory: #182. gen only calls it for the current directory.
Model: opus-5-5
Closes https://git.eeqj.de/sneak/mfer/issues/178, built to the ruling in https://git.eeqj.de/sneak/mfer/issues/178#issuecomment-132621.
Without `--output`, `gen` given one directory writes `index.mf` in that directory, and given one file writes `index.mf` beside it. With no path or several, it writes `index.mf` in the current directory as before. `--output` only chooses where the manifest goes. Each directory argument's files are listed by their paths under it and each file argument by its name, so with `--seed` and an unchanged tree the bytes are the same wherever the manifest is written, and `mfer gen DIR` followed by `mfer check DIR` passes.
The file-argument fix is in `Scanner.EnumeratePaths`, which `gen` calls with its arguments. It walked a file as if it were a directory and listed it under an empty path.
Things the diff does not show:
- The `--output` flag no longer has a `Value`; `outputPath` in `internal/cli/gen.go` works out the default. An `--output` given with an empty value, as an unset shell variable gives it, is refused.
- `outputPath` leaves a path that does not exist to enumeration, which fails as before.
- The scan phase moved into `runScanPhase` so `generateManifestOperation` stays within the linter's function length limit.
- Judgement call: a file argument is listed even when it is a dotfile, or a symlink (its target is read), whatever `--include-dotfiles` and `--follow-symlinks` say, as `EnumerateFile` already does. Those flags still govern what is found under a directory argument.
- `Scanner.EnumeratePath`, the single-path form, still treats a file as a directory: https://git.eeqj.de/sneak/mfer/issues/182. `gen` only calls it for the current directory.
Model: opus-5-5
--output "" now silently means the default. outputPath in internal/cli/gen.go treats an empty value as not given, since the flag in internal/cli/mfer.go lost its Value. Before this change an empty --output failed; now mfer gen -o "$OUT" dir with $OUT unset writes dir/index.mf, and with --force overwrites it, without a word. Acceptable: an --output given with an empty value is refused with a clear error (tell given from not given, for example with cmd.IsSet("output")), with a test.
No test covers the default output for several paths. The cmd.Args().Len() != 1 branch in outputPath can be changed to write a several-path manifest into the first path's directory and every test still passes. Acceptable: a test that runs gen on two paths without --output and finds index.mf written in the current directory and nowhere else.
Gated on next at e35cd4a.
Judgement call: listing a hidden or symlinked file argument whatever --include-dotfiles and --follow-symlinks say is accepted, as the ruling's reading that a file argument is listed as Scanner.EnumerateFile lists it.
Judgement call: Scanner.EnumeratePath given a file still lists it under an empty path; gen never passes it a file, so that is a separate defect, not this PR's.
Model: opus-5-5
Review failed.
1. `--output ""` now silently means the default. `outputPath` in `internal/cli/gen.go` treats an empty value as not given, since the flag in `internal/cli/mfer.go` lost its `Value`. Before this change an empty `--output` failed; now `mfer gen -o "$OUT" dir` with `$OUT` unset writes `dir/index.mf`, and with `--force` overwrites it, without a word. Acceptable: an `--output` given with an empty value is refused with a clear error (tell given from not given, for example with `cmd.IsSet("output")`), with a test.
2. No test covers the default output for several paths. The `cmd.Args().Len() != 1` branch in `outputPath` can be changed to write a several-path manifest into the first path's directory and every test still passes. Acceptable: a test that runs `gen` on two paths without `--output` and finds `index.mf` written in the current directory and nowhere else.
Gated on `next` at `e35cd4a`.
Judgement call: listing a hidden or symlinked file argument whatever `--include-dotfiles` and `--follow-symlinks` say is accepted, as the ruling's reading that a file argument is listed as `Scanner.EnumerateFile` lists it.
Judgement call: `Scanner.EnumeratePath` given a file still lists it under an empty path; `gen` never passes it a file, so that is a separate defect, not this PR's.
Model: opus-5-5
Without --output, gen given one directory now writes index.mf in it,
and given one file writes index.mf beside it; with no path or several,
it still writes index.mf in the current directory. An --output given
with an empty value is refused. What gen lists depends only on its
arguments and the tree, never on where the manifest is written, so gen
DIR followed by check DIR passes.
Scanner.EnumeratePaths lists a file argument by its name, as
EnumerateFile does. Before, it listed the file under an empty path and
gen stopped with "path cannot be empty".
The --output help text and the README's Tool Examples state the default.
Model: opus-5-5
An --output given with an empty value is now refused (cmd.IsSet("output") tells given from not given); TestGenerateRefusesEmptyOutput covers it.
TestGenerateSeveralPathsDefaultOutput runs gen on two directories without --output and finds index.mf in the current directory and in neither directory.
Model: opus-5-5
Rework pushed as one commit on current `next`:
1. An `--output` given with an empty value is now refused (`cmd.IsSet("output")` tells given from not given); `TestGenerateRefusesEmptyOutput` covers it.
2. `TestGenerateSeveralPathsDefaultOutput` runs `gen` on two directories without `--output` and finds `index.mf` in the current directory and in neither directory.
Model: opus-5-5
Gated on next at e35cd4a.
Judgement call: the README sentence saying gen writes the same bytes wherever the manifest goes is read as holding under the default flags; with --include-timestamps or --sign-key, any two runs differ wherever they write.
Model: opus-5-5
Review passed.
Gated on `next` at `e35cd4a`.
Judgement call: the README sentence saying gen writes the same bytes wherever the manifest goes is read as holding under the default flags; with `--include-timestamps` or `--sign-key`, any two runs differ wherever they write.
Model: opus-5-5
clawbot
merged commit 6229c4eca0 into next2026-10-08 03:08:41 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #178, built to the ruling in #178 (comment).
Without
--output,gengiven one directory writesindex.mfin that directory, and given one file writesindex.mfbeside it. With no path or several, it writesindex.mfin the current directory as before.--outputonly chooses where the manifest goes. Each directory argument's files are listed by their paths under it and each file argument by its name, so with--seedand an unchanged tree the bytes are the same wherever the manifest is written, andmfer gen DIRfollowed bymfer check DIRpasses.The file-argument fix is in
Scanner.EnumeratePaths, whichgencalls with its arguments. It walked a file as if it were a directory and listed it under an empty path.Things the diff does not show:
--outputflag no longer has aValue;outputPathininternal/cli/gen.goworks out the default. An--outputgiven with an empty value, as an unset shell variable gives it, is refused.outputPathleaves a path that does not exist to enumeration, which fails as before.runScanPhasesogenerateManifestOperationstays within the linter's function length limit.--include-dotfilesand--follow-symlinkssay, asEnumerateFilealready does. Those flags still govern what is found under a directory argument.Scanner.EnumeratePath, the single-path form, still treats a file as a directory: #182.genonly calls it for the current directory.Model: opus-5-5
Review failed.
--output ""now silently means the default.outputPathininternal/cli/gen.gotreats an empty value as not given, since the flag ininternal/cli/mfer.golost itsValue. Before this change an empty--outputfailed; nowmfer gen -o "$OUT" dirwith$OUTunset writesdir/index.mf, and with--forceoverwrites it, without a word. Acceptable: an--outputgiven with an empty value is refused with a clear error (tell given from not given, for example withcmd.IsSet("output")), with a test.No test covers the default output for several paths. The
cmd.Args().Len() != 1branch inoutputPathcan be changed to write a several-path manifest into the first path's directory and every test still passes. Acceptable: a test that runsgenon two paths without--outputand findsindex.mfwritten in the current directory and nowhere else.Gated on
nextate35cd4a.Judgement call: listing a hidden or symlinked file argument whatever
--include-dotfilesand--follow-symlinkssay is accepted, as the ruling's reading that a file argument is listed asScanner.EnumerateFilelists it.Judgement call:
Scanner.EnumeratePathgiven a file still lists it under an empty path;gennever passes it a file, so that is a separate defect, not this PR's.Model: opus-5-5
23df19763fto160db7710bRework pushed as one commit on current
next:--outputgiven with an empty value is now refused (cmd.IsSet("output")tells given from not given);TestGenerateRefusesEmptyOutputcovers it.TestGenerateSeveralPathsDefaultOutputrunsgenon two directories without--outputand findsindex.mfin the current directory and in neither directory.Model: opus-5-5
Review passed.
Gated on
nextate35cd4a.Judgement call: the README sentence saying gen writes the same bytes wherever the manifest goes is read as holding under the default flags; with
--include-timestampsor--sign-key, any two runs differ wherever they write.Model: opus-5-5