urfave/cli's built-in version flag claimed -v, so "mfer -v --version" failed to parse, and -v meant version at the root but verbose on generate, check, freshen and fetch. Verbose is the more common meaning, so the root now takes -v and -q too, and the version flag takes -V. A -v or -q before generate, check, freshen, fetch or export applies to that subcommand; list keeps its fixed quiet logging. User-visible changes: -v no longer prints the version; use -V or --version. "mfer version" prints "mfer version 0.1.0 (...)", the same line as --version, instead of the bare "0.1.0 (...)". Tests: runCLI now points the logger at io.Discard after each run, so other tests' log lines cannot land in a finished run's output. Model: opus-4-8 (implementation); opus-5-5 (rework)
This commit is contained in:
+45
-5
@@ -19,6 +19,7 @@ const (
|
||||
cmdCheck = "check"
|
||||
cmdExport = "export"
|
||||
cmdFetch = "fetch"
|
||||
cmdVersion = "version"
|
||||
|
||||
flagProgress = "progress"
|
||||
|
||||
@@ -68,6 +69,12 @@ func (mfa *CLIApp) VersionString() string {
|
||||
return mfer.Version
|
||||
}
|
||||
|
||||
// printVersion writes the version line shared by the --version flag and the
|
||||
// version subcommand, so both produce identical output.
|
||||
func (mfa *CLIApp) printVersion() {
|
||||
_, _ = fmt.Fprintf(mfa.Stdout, "%s version %s\n", mfa.appname, mfa.VersionString())
|
||||
}
|
||||
|
||||
func (mfa *CLIApp) printBanner() {
|
||||
if log.GetLevel() <= log.InfoLevel {
|
||||
_, _ = fmt.Fprintln(mfa.Stdout, banner)
|
||||
@@ -78,20 +85,34 @@ func (mfa *CLIApp) printBanner() {
|
||||
}
|
||||
}
|
||||
|
||||
// setVerbosity sets the log level from -v and -q, given before the subcommand
|
||||
// name (the root's copies), after it (the subcommand's own copies), or both.
|
||||
// urfave/cli reads a flag from the nearest command that defines it, so each
|
||||
// command in the lineage is asked. The highest -v count wins rather than the
|
||||
// sum, because a subcommand without its own copies reads the root's.
|
||||
func (mfa *CLIApp) setVerbosity(c *cli.Context) {
|
||||
_, present := os.LookupEnv("MFER_DEBUG")
|
||||
|
||||
verbosity := 0
|
||||
quiet := false
|
||||
|
||||
for _, ctx := range c.Lineage() {
|
||||
verbosity = max(verbosity, ctx.Count("verbose"))
|
||||
quiet = quiet || ctx.Bool("quiet")
|
||||
}
|
||||
|
||||
switch {
|
||||
case present:
|
||||
log.EnableDebugLogging()
|
||||
case c.Bool("quiet"):
|
||||
case quiet:
|
||||
log.SetLevel(log.ErrorLevel)
|
||||
default:
|
||||
log.SetLevelFromVerbosity(c.Count("verbose"))
|
||||
log.SetLevelFromVerbosity(verbosity)
|
||||
}
|
||||
}
|
||||
|
||||
// commonFlags returns the flags shared by most commands (-v, -q)
|
||||
// commonFlags returns the -v and -q flags taken by the root and by the
|
||||
// generate, check, freshen and fetch subcommands.
|
||||
func commonFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
@@ -259,6 +280,8 @@ func (mfa *CLIApp) exportCommand() *cli.Command {
|
||||
Usage: "Export manifest contents as JSON",
|
||||
ArgsUsage: "[manifest file or URL]",
|
||||
Action: func(c *cli.Context) error {
|
||||
mfa.setVerbosity(c)
|
||||
|
||||
return mfa.exportManifestOperation(c)
|
||||
},
|
||||
}
|
||||
@@ -266,10 +289,10 @@ func (mfa *CLIApp) exportCommand() *cli.Command {
|
||||
|
||||
func (mfa *CLIApp) versionCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "version",
|
||||
Name: cmdVersion,
|
||||
Usage: "Show version",
|
||||
Action: func(_ *cli.Context) error {
|
||||
_, _ = fmt.Fprintln(mfa.Stdout, mfa.VersionString())
|
||||
mfa.printVersion()
|
||||
|
||||
return nil
|
||||
},
|
||||
@@ -325,6 +348,21 @@ func (mfa *CLIApp) run(args []string) {
|
||||
log.SetOutput(mfa.Stdout, mfa.Stderr)
|
||||
log.Init()
|
||||
|
||||
// -v means verbose, not version. urfave/cli's built-in version flag
|
||||
// claims -v by default, which made "mfer -v --version" fail to parse and
|
||||
// gave -v a different meaning at the root than on the generate, check,
|
||||
// freshen and fetch subcommands, where it means verbose. Verbose is the
|
||||
// more common meaning of -v in tools that offer both, so -v means verbose
|
||||
// at the root too and the version flag takes the capital -V.
|
||||
// VersionFlag and VersionPrinter are urfave/cli package globals; run() is
|
||||
// serialized in tests, so assigning them here is safe.
|
||||
cli.VersionFlag = &cli.BoolFlag{
|
||||
Name: cmdVersion,
|
||||
Aliases: []string{"V"},
|
||||
Usage: "print the version",
|
||||
}
|
||||
cli.VersionPrinter = func(_ *cli.Context) { mfa.printVersion() }
|
||||
|
||||
mfa.app = &cli.App{
|
||||
Name: mfa.appname,
|
||||
Usage: "Manifest generator",
|
||||
@@ -332,11 +370,13 @@ func (mfa *CLIApp) run(args []string) {
|
||||
EnableBashCompletion: true,
|
||||
Writer: mfa.Stdout,
|
||||
ErrWriter: mfa.Stderr,
|
||||
Flags: commonFlags(),
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.Args().Len() > 0 {
|
||||
return fmt.Errorf("%w %q", errUnknownCommand, c.Args().First())
|
||||
}
|
||||
|
||||
mfa.setVerbosity(c)
|
||||
mfa.printBanner()
|
||||
|
||||
return cli.ShowAppHelp(c)
|
||||
|
||||
Reference in New Issue
Block a user