Files
summercms/modules/diary/helponly.go
Jakub Zych 6c606c666b feat(diary): boot list, help and completion requests quietly (quick-261028-rqc)
- helpOnly also counts no command word, list, help, cobra's shell
  completion requests and --help=<bool>, read the way pflag does
- TestHelpOnlyAgreesWithCobra pins the classification against bonfire's
  real dispatch, with the passthrough --help case as the exception
- console and logging docs describe which invocations boot quietly
2026-10-28 21:47:42 +01:00

109 lines
3.5 KiB
Go

package diary
import (
"strconv"
"strings"
)
// The hidden commands of cobra's shell completion (cobra.ShellCompRequestCmd
// and cobra.ShellCompNoDescRequestCmd), named here so diary does not link
// cobra; TestHelpOnlyAgreesWithCobra pins them.
const (
completeRequestCmd = "__complete"
completeNoDescRequestCmd = "__completeNoDesc"
)
// helpOnly reports whether args, a binary's command line without the
// program name, only ask the binary to describe itself, so no command runs:
//
// - there is no command word (the first token before "--" that is neither
// a flag nor the value of --env, bonfire's rule under which Execute
// prints the list): a bare invocation, only global options, -h or
// --help;
// - the command word is list, help or one of cobra's shell completion
// requests (__complete, __completeNoDesc);
// - the help flag is set before "--", also after the command word, the
// way cobra honours it: --help, --help=<bool> read by strconv.ParseBool
// the way pflag does (the last occurrence wins, an unparsable value is
// ignored), or a single-dash cluster that reaches h (-h, -vh, -nh).
//
// It is a tolerant pre-scan of the raw arguments, made before plugins boot,
// and reads them the way bonfire.PeekGlobals does: it stops at "--", skips
// the value of --env and reads a single-dash cluster letter by letter,
// stopping at the first letter that is not a global shorthand (v, q, n, h).
// It never fails. An unknown or misspelled command word is not help-only
// (that is unknowable before boot). It cannot tell a passthrough command
// (whose --help reaches its Run) from another, so "<passthrough> --help"
// counts; the root's OnGlobals hook (ApplyGlobals) restores the console
// levels before that command runs.
func helpOnly(args []string) bool {
help := false
word := ""
scan:
for i := 0; i < len(args); i++ {
a := args[i]
switch {
case a == "--":
break scan
case a == "--env":
i++
case a == "--help":
help = true
case strings.HasPrefix(a, "--help="):
if v, err := strconv.ParseBool(strings.TrimPrefix(a, "--help=")); err == nil {
help = v
}
case len(a) >= 2 && a[0] == '-' && a[1] != '-':
if v, ok := clusterHelp(a[1:]); ok {
help = v
}
case strings.HasPrefix(a, "-"):
case word == "":
word = a
}
}
switch word {
case "", "list", "help", completeRequestCmd, completeNoDescRequestCmd:
return true
}
return help
}
// clusterHelp reads a shorthand cluster (the letters after the dash) the
// way bonfire.PeekGlobals does and reports the help value it sets: ok is
// true when the cluster reaches h before a letter that is not a global
// shorthand, and -h=<bool> (-vh=false) sets the value read by
// strconv.ParseBool.
func clusterHelp(cluster string) (help, ok bool) {
for i := 0; i < len(cluster); i++ {
r := cluster[i]
if i+1 < len(cluster) && cluster[i+1] == '=' {
if r != 'h' {
return help, ok
}
if v, err := strconv.ParseBool(cluster[i+2:]); err == nil {
return v, true
}
return help, ok
}
switch r {
case 'h':
help, ok = true, true
case 'v', 'q', 'n':
default:
return help, ok
}
}
return help, ok
}
// bootQuiet applies the help-only rule of Bootstrap and Setup: with Args
// set, no -v and arguments that only ask for help, the setup is installed
// with Quiet, which raises only the console channels to warn.
func bootQuiet(opts Options) Options {
if opts.Args != nil && opts.Verbosity == 0 && helpOnly(opts.Args) {
opts.Quiet = true
}
return opts
}