mirror of
https://github.com/gravitational/teleport
synced 2024-10-20 01:03:40 +00:00
Improve cli usage when command name is long (#10981)
This commit is contained in:
parent
b2c5c8ecb0
commit
3d7de736e3
|
@ -292,7 +292,55 @@ func InitCLIParser(appName, appHelp string) (app *kingpin.Application) {
|
|||
app.HelpFlag.NoEnvar()
|
||||
|
||||
// set our own help template
|
||||
return app.UsageTemplate(defaultUsageTemplate)
|
||||
return app.UsageTemplate(createUsageTemplate())
|
||||
}
|
||||
|
||||
// createUsageTemplate creates an usage template for kingpin applications.
|
||||
func createUsageTemplate(opts ...func(*usageTemplateOptions)) string {
|
||||
opt := &usageTemplateOptions{
|
||||
commandPrintfWidth: defaultCommandPrintfWidth,
|
||||
}
|
||||
|
||||
for _, optFunc := range opts {
|
||||
optFunc(opt)
|
||||
}
|
||||
return fmt.Sprintf(defaultUsageTemplate, opt.commandPrintfWidth)
|
||||
}
|
||||
|
||||
// UpdateAppUsageTemplate updates usage template for kingpin applications by
|
||||
// pre-parsing the arguments then applying any changes to the usage template if
|
||||
// necessary.
|
||||
func UpdateAppUsageTemplate(app *kingpin.Application, args []string) {
|
||||
// If ParseContext fails, kingpin will not show usage so there is no need
|
||||
// to update anything here. See app.Parse for more details.
|
||||
context, err := app.ParseContext(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
app.UsageTemplate(createUsageTemplate(
|
||||
withCommandPrintfWidth(app, context),
|
||||
))
|
||||
}
|
||||
|
||||
// withCommandPrintfWidth returns an usage template option that
|
||||
// updates command printf width if longer than default.
|
||||
func withCommandPrintfWidth(app *kingpin.Application, context *kingpin.ParseContext) func(*usageTemplateOptions) {
|
||||
return func(opt *usageTemplateOptions) {
|
||||
var commands []*kingpin.CmdModel
|
||||
if context.SelectedCommand != nil {
|
||||
commands = context.SelectedCommand.Model().FlattenedCommands()
|
||||
} else {
|
||||
commands = app.Model().FlattenedCommands()
|
||||
}
|
||||
|
||||
for _, command := range commands {
|
||||
if !command.Hidden && len(command.FullCommand) > opt.commandPrintfWidth {
|
||||
opt.commandPrintfWidth = len(command.FullCommand)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// SplitIdentifiers splits list of identifiers by commas/spaces/newlines. Helpful when
|
||||
|
@ -380,8 +428,19 @@ func needsQuoting(text string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Usage template with compactly formatted commands.
|
||||
var defaultUsageTemplate = `{{define "FormatCommand"}}\
|
||||
// usageTemplateOptions defines options to format the usage template.
|
||||
type usageTemplateOptions struct {
|
||||
// commandPrintfWidth is the width of the command name with padding, for
|
||||
// {{.FullCommand | printf "%%-%ds"}}
|
||||
commandPrintfWidth int
|
||||
}
|
||||
|
||||
// defaultCommandPrintfWidth is the default command printf width.
|
||||
const defaultCommandPrintfWidth = 12
|
||||
|
||||
// defaultUsageTemplate is a fmt format that defines the usage template with
|
||||
// compactly formatted commands. Should be only used in createUsageTemplate.
|
||||
const defaultUsageTemplate = `{{define "FormatCommand"}}\
|
||||
{{if .FlagSummary}} {{.FlagSummary}}{{end}}\
|
||||
{{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\
|
||||
{{end}}\
|
||||
|
@ -389,7 +448,7 @@ var defaultUsageTemplate = `{{define "FormatCommand"}}\
|
|||
{{define "FormatCommands"}}\
|
||||
{{range .FlattenedCommands}}\
|
||||
{{if not .Hidden}}\
|
||||
{{.FullCommand | printf "%-12s" }}{{if .Default}} (Default){{end}} {{ .Help }}
|
||||
{{.FullCommand | printf "%%-%ds"}}{{if .Default}} (Default){{end}} {{ .Help }}
|
||||
{{end}}\
|
||||
{{end}}\
|
||||
{{end}}\
|
||||
|
|
|
@ -71,6 +71,7 @@ func Run(args []string) error {
|
|||
app := utils.InitCLIParser("tbot", "tbot: Teleport Machine ID").Interspersed(false)
|
||||
app.Flag("debug", "Verbose logging to stdout").Short('d').BoolVar(&cf.Debug)
|
||||
app.Flag("config", "Path to a configuration file. Defaults to `/etc/tbot.yaml` if unspecified.").Short('c').StringVar(&cf.ConfigPath)
|
||||
app.HelpFlag.Short('h')
|
||||
|
||||
versionCmd := app.Command("version", "Print the version")
|
||||
|
||||
|
@ -97,6 +98,7 @@ func Run(args []string) error {
|
|||
|
||||
watchCmd := app.Command("watch", "Watch a destination directory for changes.").Hidden()
|
||||
|
||||
utils.UpdateAppUsageTemplate(app, args)
|
||||
command, err := app.Parse(args)
|
||||
if err != nil {
|
||||
app.Usage(args)
|
||||
|
|
|
@ -137,6 +137,7 @@ func Run(commands []CLICommand) {
|
|||
app.HelpFlag.Short('h')
|
||||
|
||||
// parse CLI commands+flags:
|
||||
utils.UpdateAppUsageTemplate(app, os.Args[1:])
|
||||
selectedCmd, err := app.Parse(os.Args[1:])
|
||||
if err != nil {
|
||||
app.Usage(os.Args[1:])
|
||||
|
|
|
@ -294,6 +294,7 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con
|
|||
dump.Flag("key-file", "Path to a TLS key file for the proxy.").ExistingFileVar(&dumpFlags.KeyFile)
|
||||
|
||||
// parse CLI commands+flags:
|
||||
utils.UpdateAppUsageTemplate(app, options.Args)
|
||||
command, err := app.Parse(options.Args)
|
||||
if err != nil {
|
||||
app.Usage(options.Args)
|
||||
|
|
|
@ -638,6 +638,7 @@ func Run(args []string, opts ...cliOption) error {
|
|||
}
|
||||
|
||||
// parse CLI commands+flags:
|
||||
utils.UpdateAppUsageTemplate(app, args)
|
||||
command, err := app.Parse(args)
|
||||
if err != nil {
|
||||
app.Usage(args)
|
||||
|
|
Loading…
Reference in a new issue