Write gen DIR's manifest to DIR/index.mf (closes #178)
check / check (push) Waiting to run

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. 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
This commit is contained in:
2026-10-07 21:09:06 +00:00
parent e35cd4a045
commit 23df19763f
6 changed files with 200 additions and 10 deletions
+30 -5
View File
@@ -88,9 +88,34 @@ func (mfa *CLIApp) collectInputPaths(args cli.Args) ([]string, error) {
return paths, nil
}
// buildScannerOptions constructs scanner options from the CLI flags.
func (mfa *CLIApp) buildScannerOptions(cmd *cli.Command) *mfer.ScannerOptions {
output := cmd.String("output")
// outputPath returns the file gen writes the manifest to: the one --output
// names, or else index.mf in the directory the only argument names, or
// beside the file it names, or else in the current directory.
func (mfa *CLIApp) outputPath(cmd *cli.Command) string {
if output := cmd.String("output"); output != "" {
return output
}
if cmd.Args().Len() != 1 {
return defaultManifestName
}
arg := cmd.Args().First()
// A path that does not exist is refused when it is enumerated.
info, err := mfa.Fs.Stat(arg)
if err == nil && !info.IsDir() {
return filepath.Join(filepath.Dir(arg), defaultManifestName)
}
return filepath.Join(arg, defaultManifestName)
}
// buildScannerOptions constructs scanner options from the CLI flags and
// the path the manifest is written to.
func (mfa *CLIApp) buildScannerOptions(
cmd *cli.Command, output string,
) *mfer.ScannerOptions {
opts := &mfer.ScannerOptions{
IncludeDotfiles: cmd.Bool("include-dotfiles"),
FollowSymLinks: cmd.Bool("follow-symlinks"),
@@ -207,7 +232,8 @@ func (mfa *CLIApp) generateManifestOperation(
) error {
log.Debug("generateManifestOperation()")
s := mfer.NewScannerWithOptions(mfa.buildScannerOptions(cmd))
outputPath := mfa.outputPath(cmd)
s := mfer.NewScannerWithOptions(mfa.buildScannerOptions(cmd, outputPath))
// Phase 1: Enumeration - collect paths and stat files
err := mfa.runEnumeratePhase(cmd, s)
@@ -218,7 +244,6 @@ func (mfa *CLIApp) generateManifestOperation(
showProgress := cmd.Bool("progress")
// Check if output file exists
outputPath := cmd.String("output")
if exists, _ := afero.Exists(mfa.Fs, outputPath); exists && !cmd.Bool("force") {
return fmt.Errorf("output file %s %w", outputPath, errOutputExists)
}