From ca3f3d7d1636fe4eb377be342102148adfb7fd33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Mon, 29 May 2023 14:19:21 +0200 Subject: [PATCH 01/19] Export the `addCommand()` function from `cli`. --- internals/cli/cli.go | 4 ++-- internals/cli/cmd_add.go | 2 +- internals/cli/cmd_autostart.go | 2 +- internals/cli/cmd_changes.go | 4 ++-- internals/cli/cmd_checks.go | 2 +- internals/cli/cmd_enter.go | 2 +- internals/cli/cmd_exec.go | 2 +- internals/cli/cmd_help.go | 2 +- internals/cli/cmd_logs.go | 2 +- internals/cli/cmd_ls.go | 2 +- internals/cli/cmd_mkdir.go | 2 +- internals/cli/cmd_plan.go | 2 +- internals/cli/cmd_replan.go | 2 +- internals/cli/cmd_restart.go | 2 +- internals/cli/cmd_rm.go | 2 +- internals/cli/cmd_run.go | 2 +- internals/cli/cmd_services.go | 2 +- internals/cli/cmd_signal.go | 2 +- internals/cli/cmd_start.go | 2 +- internals/cli/cmd_stop.go | 2 +- internals/cli/cmd_version.go | 2 +- internals/cli/cmd_warnings.go | 4 ++-- 22 files changed, 25 insertions(+), 25 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 18a37851..b3dc040a 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -80,9 +80,9 @@ var commands []*cmdInfo // debugCommands holds information about all debug commands. var debugCommands []*cmdInfo -// addCommand replaces parser.addCommand() in a way that is compatible with +// AddCommand replaces parser.AddCommand() in a way that is compatible with // re-constructing a pristine parser. -func addCommand(name, shortHelp, longHelp string, builder func() flags.Commander, optDescs map[string]string, argDescs []argDesc) *cmdInfo { +func AddCommand(name, shortHelp, longHelp string, builder func() flags.Commander, optDescs map[string]string, argDescs []argDesc) *cmdInfo { info := &cmdInfo{ name: name, shortHelp: shortHelp, diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index 521f1c4c..e477e3b5 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -67,5 +67,5 @@ func (cmd *cmdAdd) Execute(args []string) error { } func init() { - addCommand("add", shortAddHelp, longAddHelp, func() flags.Commander { return &cmdAdd{} }, addDescs, nil) + AddCommand("add", shortAddHelp, longAddHelp, func() flags.Commander { return &cmdAdd{} }, addDescs, nil) } diff --git a/internals/cli/cmd_autostart.go b/internals/cli/cmd_autostart.go index 229691f4..31f38f41 100644 --- a/internals/cli/cmd_autostart.go +++ b/internals/cli/cmd_autostart.go @@ -31,7 +31,7 @@ type cmdAutoStart struct { } func init() { - addCommand("autostart", shortAutoStartHelp, longAutoStartHelp, func() flags.Commander { return &cmdAutoStart{} }, waitDescs, nil) + AddCommand("autostart", shortAutoStartHelp, longAutoStartHelp, func() flags.Commander { return &cmdAutoStart{} }, waitDescs, nil) } func (cmd cmdAutoStart) Execute(args []string) error { diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index b3888548..be238a3a 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -48,9 +48,9 @@ type cmdTasks struct { } func init() { - addCommand("changes", shortChangesHelp, longChangesHelp, + AddCommand("changes", shortChangesHelp, longChangesHelp, func() flags.Commander { return &cmdChanges{} }, timeDescs, nil) - addCommand("tasks", shortTasksHelp, longTasksHelp, + AddCommand("tasks", shortTasksHelp, longTasksHelp, func() flags.Commander { return &cmdTasks{} }, merge(changeIDMixinOptDesc, timeDescs), changeIDMixinArgDesc) diff --git a/internals/cli/cmd_checks.go b/internals/cli/cmd_checks.go index 4ee1af84..6fe93d34 100644 --- a/internals/cli/cmd_checks.go +++ b/internals/cli/cmd_checks.go @@ -79,5 +79,5 @@ func (cmd *cmdChecks) Execute(args []string) error { } func init() { - addCommand("checks", shortChecksHelp, longChecksHelp, func() flags.Commander { return &cmdChecks{} }, checksDescs, nil) + AddCommand("checks", shortChecksHelp, longChecksHelp, func() flags.Commander { return &cmdChecks{} }, checksDescs, nil) } diff --git a/internals/cli/cmd_enter.go b/internals/cli/cmd_enter.go index 981d4034..0d93b3d8 100644 --- a/internals/cli/cmd_enter.go +++ b/internals/cli/cmd_enter.go @@ -58,7 +58,7 @@ func init() { for k, v := range sharedRunEnterOptsHelp { optsHelp[k] = v } - cmdInfo := addCommand("enter", shortEnterHelp, longEnterHelp, func() flags.Commander { return &cmdEnter{} }, optsHelp, nil) + cmdInfo := AddCommand("enter", shortEnterHelp, longEnterHelp, func() flags.Commander { return &cmdEnter{} }, optsHelp, nil) cmdInfo.extra = func(cmd *flags.Command) { cmd.PassAfterNonOption = true } diff --git a/internals/cli/cmd_exec.go b/internals/cli/cmd_exec.go index 0298f2b2..fec1c5e2 100644 --- a/internals/cli/cmd_exec.go +++ b/internals/cli/cmd_exec.go @@ -264,7 +264,7 @@ func execControlHandler(process *client.ExecProcess, terminal bool, stop <-chan } func init() { - info := addCommand("exec", shortExecHelp, longExecHelp, func() flags.Commander { return &cmdExec{} }, execDescs, nil) + info := AddCommand("exec", shortExecHelp, longExecHelp, func() flags.Commander { return &cmdExec{} }, execDescs, nil) info.extra = func(cmd *flags.Command) { cmd.PassAfterNonOption = true } diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index 02b787f3..06907161 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -79,7 +79,7 @@ type cmdHelp struct { } func init() { - addCommand("help", shortHelpHelp, longHelpHelp, func() flags.Commander { return &cmdHelp{} }, + AddCommand("help", shortHelpHelp, longHelpHelp, func() flags.Commander { return &cmdHelp{} }, map[string]string{ "all": "Show a short summary of all commands", "man": "Generate the manpage", diff --git a/internals/cli/cmd_logs.go b/internals/cli/cmd_logs.go index b5896c03..43655f70 100644 --- a/internals/cli/cmd_logs.go +++ b/internals/cli/cmd_logs.go @@ -121,5 +121,5 @@ func notifyContext(parent context.Context, signals ...os.Signal) context.Context } func init() { - addCommand("logs", shortLogsHelp, longLogsHelp, func() flags.Commander { return &cmdLogs{} }, logsDescs, nil) + AddCommand("logs", shortLogsHelp, longLogsHelp, func() flags.Commander { return &cmdLogs{} }, logsDescs, nil) } diff --git a/internals/cli/cmd_ls.go b/internals/cli/cmd_ls.go index 163620c2..39907669 100644 --- a/internals/cli/cmd_ls.go +++ b/internals/cli/cmd_ls.go @@ -103,5 +103,5 @@ func parseGlob(path string) (parsedPath, parsedPattern string, err error) { } func init() { - addCommand("ls", shortLsHelp, longLsHelp, func() flags.Commander { return &cmdLs{} }, merge(lsDescs, timeDescs), nil) + AddCommand("ls", shortLsHelp, longLsHelp, func() flags.Commander { return &cmdLs{} }, merge(lsDescs, timeDescs), nil) } diff --git a/internals/cli/cmd_mkdir.go b/internals/cli/cmd_mkdir.go index 995c71dd..8d7cb068 100644 --- a/internals/cli/cmd_mkdir.go +++ b/internals/cli/cmd_mkdir.go @@ -79,5 +79,5 @@ func (cmd *cmdMkdir) Execute(args []string) error { } func init() { - addCommand("mkdir", shortMkdirHelp, longMkdirHelp, func() flags.Commander { return &cmdMkdir{} }, mkdirDescs, nil) + AddCommand("mkdir", shortMkdirHelp, longMkdirHelp, func() flags.Commander { return &cmdMkdir{} }, mkdirDescs, nil) } diff --git a/internals/cli/cmd_plan.go b/internals/cli/cmd_plan.go index f899339d..0b74051a 100644 --- a/internals/cli/cmd_plan.go +++ b/internals/cli/cmd_plan.go @@ -43,5 +43,5 @@ func (cmd *cmdPlan) Execute(args []string) error { } func init() { - addCommand("plan", shortPlanHelp, longPlanHelp, func() flags.Commander { return &cmdPlan{} }, nil, nil) + AddCommand("plan", shortPlanHelp, longPlanHelp, func() flags.Commander { return &cmdPlan{} }, nil, nil) } diff --git a/internals/cli/cmd_replan.go b/internals/cli/cmd_replan.go index 3bcc7350..3dd57c46 100644 --- a/internals/cli/cmd_replan.go +++ b/internals/cli/cmd_replan.go @@ -32,7 +32,7 @@ type cmdReplan struct { } func init() { - addCommand("replan", shortReplanHelp, longReplanHelp, func() flags.Commander { return &cmdReplan{} }, waitDescs, nil) + AddCommand("replan", shortReplanHelp, longReplanHelp, func() flags.Commander { return &cmdReplan{} }, waitDescs, nil) } func (cmd cmdReplan) Execute(args []string) error { diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index b99cd4ad..5cf009d1 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -33,7 +33,7 @@ type cmdRestart struct { } func init() { - addCommand("restart", shortRestartHelp, longRestartHelp, func() flags.Commander { return &cmdRestart{} }, waitDescs, nil) + AddCommand("restart", shortRestartHelp, longRestartHelp, func() flags.Commander { return &cmdRestart{} }, waitDescs, nil) } func (cmd cmdRestart) Execute(args []string) error { diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index 930e5835..94cd3624 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -51,5 +51,5 @@ func (cmd *cmdRm) Execute(args []string) error { } func init() { - addCommand("rm", shortRmHelp, longRmHelp, func() flags.Commander { return &cmdRm{} }, rmDescs, nil) + AddCommand("rm", shortRmHelp, longRmHelp, func() flags.Commander { return &cmdRm{} }, rmDescs, nil) } diff --git a/internals/cli/cmd_run.go b/internals/cli/cmd_run.go index 2c1f2083..9cc09068 100644 --- a/internals/cli/cmd_run.go +++ b/internals/cli/cmd_run.go @@ -65,7 +65,7 @@ type cmdRun struct { } func init() { - addCommand("run", shortRunHelp, longRunHelp, func() flags.Commander { return &cmdRun{} }, + AddCommand("run", shortRunHelp, longRunHelp, func() flags.Commander { return &cmdRun{} }, sharedRunEnterOptsHelp, nil) } diff --git a/internals/cli/cmd_services.go b/internals/cli/cmd_services.go index 348956b9..d1009704 100644 --- a/internals/cli/cmd_services.go +++ b/internals/cli/cmd_services.go @@ -73,7 +73,7 @@ func (cmd *cmdServices) Execute(args []string) error { } func init() { - addCommand("services", shortServicesHelp, longServicesHelp, + AddCommand("services", shortServicesHelp, longServicesHelp, func() flags.Commander { return &cmdServices{} }, timeDescs, nil) } diff --git a/internals/cli/cmd_signal.go b/internals/cli/cmd_signal.go index 19264728..d92a1acf 100644 --- a/internals/cli/cmd_signal.go +++ b/internals/cli/cmd_signal.go @@ -58,5 +58,5 @@ func (cmd *cmdSignal) Execute(args []string) error { } func init() { - addCommand("signal", shortSignalHelp, longSignalHelp, func() flags.Commander { return &cmdSignal{} }, nil, nil) + AddCommand("signal", shortSignalHelp, longSignalHelp, func() flags.Commander { return &cmdSignal{} }, nil, nil) } diff --git a/internals/cli/cmd_start.go b/internals/cli/cmd_start.go index 9c719f97..d36eba40 100644 --- a/internals/cli/cmd_start.go +++ b/internals/cli/cmd_start.go @@ -34,7 +34,7 @@ type cmdStart struct { } func init() { - addCommand("start", shortStartHelp, longStartHelp, func() flags.Commander { return &cmdStart{} }, waitDescs, nil) + AddCommand("start", shortStartHelp, longStartHelp, func() flags.Commander { return &cmdStart{} }, waitDescs, nil) } func (cmd cmdStart) Execute(args []string) error { diff --git a/internals/cli/cmd_stop.go b/internals/cli/cmd_stop.go index b5d3411d..95473d65 100644 --- a/internals/cli/cmd_stop.go +++ b/internals/cli/cmd_stop.go @@ -34,7 +34,7 @@ type cmdStop struct { } func init() { - addCommand("stop", shortStopHelp, longStopHelp, func() flags.Commander { return &cmdStop{} }, waitDescs, nil) + AddCommand("stop", shortStopHelp, longStopHelp, func() flags.Commander { return &cmdStop{} }, waitDescs, nil) } func (cmd cmdStop) Execute(args []string) error { diff --git a/internals/cli/cmd_version.go b/internals/cli/cmd_version.go index 9e07f0e5..a36bb0c5 100644 --- a/internals/cli/cmd_version.go +++ b/internals/cli/cmd_version.go @@ -38,7 +38,7 @@ var versionDescs = map[string]string{ } func init() { - addCommand("version", shortVersionHelp, longVersionHelp, func() flags.Commander { return &cmdVersion{} }, versionDescs, nil) + AddCommand("version", shortVersionHelp, longVersionHelp, func() flags.Commander { return &cmdVersion{} }, versionDescs, nil) } func (cmd cmdVersion) Execute(args []string) error { diff --git a/internals/cli/cmd_warnings.go b/internals/cli/cmd_warnings.go index 192f97a0..f12c32c1 100644 --- a/internals/cli/cmd_warnings.go +++ b/internals/cli/cmd_warnings.go @@ -61,11 +61,11 @@ sufficient time has passed. ` func init() { - addCommand("warnings", shortWarningsHelp, longWarningsHelp, func() flags.Commander { return &cmdWarnings{} }, merge(timeDescs, unicodeDescs, map[string]string{ + AddCommand("warnings", shortWarningsHelp, longWarningsHelp, func() flags.Commander { return &cmdWarnings{} }, merge(timeDescs, unicodeDescs, map[string]string{ "all": "Show all warnings", "verbose": "Show more information", }), nil) - addCommand("okay", shortOkayHelp, longOkayHelp, func() flags.Commander { return &cmdOkay{} }, nil, nil) + AddCommand("okay", shortOkayHelp, longOkayHelp, func() flags.Commander { return &cmdOkay{} }, nil, nil) } func (cmd *cmdWarnings) Execute(args []string) error { From b65bd903866dfdc7362193d7fd5cd70c27b2d797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Tue, 30 May 2023 10:12:55 +0200 Subject: [PATCH 02/19] Introduce `cli.AddHelpCategory()` --- internals/cli/cmd_help.go | 9 +++++++-- internals/cli/cmd_help_test.go | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index 06907161..267b145f 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -158,14 +158,14 @@ func (cmd cmdHelp) Execute(args []string) error { return &flags.Error{Type: flags.ErrCommandRequired} } -type helpCategory struct { +type HelpCategory struct { Label string Description string Commands []string } // helpCategories helps us by grouping commands -var helpCategories = []helpCategory{{ +var helpCategories = []HelpCategory{{ Label: "Run", Description: "run pebble", Commands: []string{"run", "help", "version"}, @@ -191,6 +191,11 @@ var helpCategories = []helpCategory{{ Commands: []string{"warnings", "okay"}, }} +// AddHelpCategory appends an existing help category to the Pebble help manual. +func AddHelpCategory(categ HelpCategory) { + helpCategories = append(helpCategories, categ) +} + var ( longPebbleDescription = strings.TrimSpace(` Pebble lets you control services and perform management actions on diff --git a/internals/cli/cmd_help_test.go b/internals/cli/cmd_help_test.go index 077ca256..e04769a8 100644 --- a/internals/cli/cmd_help_test.go +++ b/internals/cli/cmd_help_test.go @@ -109,3 +109,20 @@ func (s *PebbleSuite) TestCommandWithHelpOption(c *C) { c.Check(s.Stdout(), Matches, "(?s)Usage.*pebble help.*The help command.*help command options.*") c.Check(s.Stderr(), Equals, "") } + +func (s *PebbleSuite) TestAddHelpCategory(c *C) { + restore := fakeArgs("pebble") + defer restore() + + cli.AddHelpCategory(cli.HelpCategory{ + Label: "Test category", + Description: "Test description", + Commands: []string{"run", "logs"}, + }) + + err := cli.RunMain() + c.Assert(err, Equals, nil) + + c.Check(s.Stdout(), Matches, "(?s).*Test category: run, logs\n.*") + c.Check(s.Stderr(), Equals, "") +} From 8aa94a89950f50b610c735be864269b4e703ff9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Wed, 7 Jun 2023 17:53:22 +0200 Subject: [PATCH 03/19] Minor fixes --- internals/cli/cli.go | 2 +- internals/cli/cmd_help.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index b3dc040a..75dcaacf 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -80,7 +80,7 @@ var commands []*cmdInfo // debugCommands holds information about all debug commands. var debugCommands []*cmdInfo -// AddCommand replaces parser.AddCommand() in a way that is compatible with +// AddCommand replaces parser.addCommand() in a way that is compatible with // re-constructing a pristine parser. func AddCommand(name, shortHelp, longHelp string, builder func() flags.Commander, optDescs map[string]string, argDescs []argDesc) *cmdInfo { info := &cmdInfo{ diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index 267b145f..cd923bf9 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -192,8 +192,8 @@ var helpCategories = []HelpCategory{{ }} // AddHelpCategory appends an existing help category to the Pebble help manual. -func AddHelpCategory(categ HelpCategory) { - helpCategories = append(helpCategories, categ) +func AddHelpCategory(category HelpCategory) { + helpCategories = append(helpCategories, category) } var ( From 7b9c17c127af7c81e19bc38edba4813dd0d5023d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Wed, 7 Jun 2023 17:53:22 +0200 Subject: [PATCH 04/19] cli: remove AddHelpCategory and improve AddCommand * AddHelpCategory() was removed in favor of an exported HelpCategories global. * AddCommand() now accepts a CmdInfo struct as its sole argument. --- internals/cli/cli.go | 116 ++++++++++++++------------------- internals/cli/cmd_add.go | 8 ++- internals/cli/cmd_autostart.go | 8 ++- internals/cli/cmd_changes.go | 21 ++++-- internals/cli/cmd_checks.go | 8 ++- internals/cli/cmd_enter.go | 15 +++-- internals/cli/cmd_exec.go | 14 ++-- internals/cli/cmd_help.go | 28 ++++---- internals/cli/cmd_help_test.go | 2 +- internals/cli/cmd_logs.go | 8 ++- internals/cli/cmd_ls.go | 8 ++- internals/cli/cmd_mkdir.go | 8 ++- internals/cli/cmd_plan.go | 7 +- internals/cli/cmd_replan.go | 8 ++- internals/cli/cmd_restart.go | 8 ++- internals/cli/cmd_rm.go | 8 ++- internals/cli/cmd_run.go | 9 ++- internals/cli/cmd_services.go | 10 ++- internals/cli/cmd_signal.go | 7 +- internals/cli/cmd_start.go | 8 ++- internals/cli/cmd_stop.go | 8 ++- internals/cli/cmd_version.go | 8 ++- internals/cli/cmd_warnings.go | 21 ++++-- 23 files changed, 226 insertions(+), 120 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 75dcaacf..cd901ea7 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -63,52 +63,34 @@ var optionsData options // ErrExtraArgs is returned if extra arguments to a command are found var ErrExtraArgs = fmt.Errorf("too many arguments for command") -// cmdInfo holds information needed to call parser.AddCommand(...). -type cmdInfo struct { - name, shortHelp, longHelp string - builder func() flags.Commander - hidden bool - optDescs map[string]string - argDescs []argDesc - alias string - extra func(*flags.Command) +// CmdInfo holds information needed to call parser.AddCommand(...). +type CmdInfo struct { + Name, ShortHelp, LongHelp string + Builder func() flags.Commander + Hidden bool + OptDescs map[string]string + ArgDescs []argDesc + Alias string + Extra func(*flags.Command) } // commands holds information about all non-debug commands. -var commands []*cmdInfo +var commands []*CmdInfo // debugCommands holds information about all debug commands. -var debugCommands []*cmdInfo +var debugCommands []*CmdInfo // AddCommand replaces parser.addCommand() in a way that is compatible with // re-constructing a pristine parser. -func AddCommand(name, shortHelp, longHelp string, builder func() flags.Commander, optDescs map[string]string, argDescs []argDesc) *cmdInfo { - info := &cmdInfo{ - name: name, - shortHelp: shortHelp, - longHelp: longHelp, - builder: builder, - optDescs: optDescs, - argDescs: argDescs, - } +func AddCommand(info *CmdInfo) { commands = append(commands, info) - return info } // addDebugCommand replaces parser.addCommand() in a way that is // compatible with re-constructing a pristine parser. It is meant for // adding debug commands. -func addDebugCommand(name, shortHelp, longHelp string, builder func() flags.Commander, optDescs map[string]string, argDescs []argDesc) *cmdInfo { - info := &cmdInfo{ - name: name, - shortHelp: shortHelp, - longHelp: longHelp, - builder: builder, - optDescs: optDescs, - argDescs: argDescs, - } +func addDebugCommand(info *CmdInfo) { debugCommands = append(debugCommands, info) - return info } type parserSetter interface { @@ -192,7 +174,7 @@ func Parser(cli *client.Client) *flags.Parser { // Add all regular commands for _, c := range commands { - obj := c.builder() + obj := c.Builder() if x, ok := obj.(clientSetter); ok { x.setClient(cli) } @@ -200,51 +182,51 @@ func Parser(cli *client.Client) *flags.Parser { x.setParser(parser) } - cmd, err := parser.AddCommand(c.name, c.shortHelp, strings.TrimSpace(c.longHelp), obj) + cmd, err := parser.AddCommand(c.Name, c.ShortHelp, strings.TrimSpace(c.LongHelp), obj) if err != nil { - logger.Panicf("cannot add command %q: %v", c.name, err) + logger.Panicf("cannot add command %q: %v", c.Name, err) } - cmd.Hidden = c.hidden - if c.alias != "" { - cmd.Aliases = append(cmd.Aliases, c.alias) + cmd.Hidden = c.Hidden + if c.Alias != "" { + cmd.Aliases = append(cmd.Aliases, c.Alias) } opts := cmd.Options() - if c.optDescs != nil && len(opts) != len(c.optDescs) { - logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.name, len(opts), len(c.optDescs)) + if c.OptDescs != nil && len(opts) != len(c.OptDescs) { + logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(c.OptDescs)) } for _, opt := range opts { name := opt.LongName if name == "" { name = string(opt.ShortName) } - desc, ok := c.optDescs[name] - if !(c.optDescs == nil || ok) { - logger.Panicf("%s missing description for %s", c.name, name) + desc, ok := c.OptDescs[name] + if !(c.OptDescs == nil || ok) { + logger.Panicf("%s missing description for %s", c.Name, name) } - lintDesc(c.name, name, desc, opt.Description) + lintDesc(c.Name, name, desc, opt.Description) if desc != "" { opt.Description = desc } } args := cmd.Args() - if c.argDescs != nil && len(args) != len(c.argDescs) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.name, len(args), len(c.argDescs)) + if c.ArgDescs != nil && len(args) != len(c.ArgDescs) { + logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgDescs)) } for i, arg := range args { name, desc := arg.Name, "" - if c.argDescs != nil { - name = c.argDescs[i].name - desc = c.argDescs[i].desc + if c.ArgDescs != nil { + name = c.ArgDescs[i].name + desc = c.ArgDescs[i].desc } - lintArg(c.name, name, desc, arg.Description) + lintArg(c.Name, name, desc, arg.Description) name = fixupArg(name) arg.Name = name arg.Description = desc } - if c.extra != nil { - c.extra(cmd) + if c.Extra != nil { + c.Extra(cmd) } } // Add the debug command @@ -255,45 +237,45 @@ func Parser(cli *client.Client) *flags.Parser { } // Add all the sub-commands of the debug command for _, c := range debugCommands { - obj := c.builder() + obj := c.Builder() if x, ok := obj.(clientSetter); ok { x.setClient(cli) } - cmd, err := debugCommand.AddCommand(c.name, c.shortHelp, strings.TrimSpace(c.longHelp), obj) + cmd, err := debugCommand.AddCommand(c.Name, c.ShortHelp, strings.TrimSpace(c.LongHelp), obj) if err != nil { - logger.Panicf("cannot add debug command %q: %v", c.name, err) + logger.Panicf("cannot add debug command %q: %v", c.Name, err) } - cmd.Hidden = c.hidden + cmd.Hidden = c.Hidden opts := cmd.Options() - if c.optDescs != nil && len(opts) != len(c.optDescs) { - logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.name, len(opts), len(c.optDescs)) + if c.OptDescs != nil && len(opts) != len(c.OptDescs) { + logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(c.OptDescs)) } for _, opt := range opts { name := opt.LongName if name == "" { name = string(opt.ShortName) } - desc, ok := c.optDescs[name] - if !(c.optDescs == nil || ok) { - logger.Panicf("%s missing description for %s", c.name, name) + desc, ok := c.OptDescs[name] + if !(c.OptDescs == nil || ok) { + logger.Panicf("%s missing description for %s", c.Name, name) } - lintDesc(c.name, name, desc, opt.Description) + lintDesc(c.Name, name, desc, opt.Description) if desc != "" { opt.Description = desc } } args := cmd.Args() - if c.argDescs != nil && len(args) != len(c.argDescs) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.name, len(args), len(c.argDescs)) + if c.ArgDescs != nil && len(args) != len(c.ArgDescs) { + logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgDescs)) } for i, arg := range args { name, desc := arg.Name, "" - if c.argDescs != nil { - name = c.argDescs[i].name - desc = c.argDescs[i].desc + if c.ArgDescs != nil { + name = c.ArgDescs[i].name + desc = c.ArgDescs[i].desc } - lintArg(c.name, name, desc, arg.Description) + lintArg(c.Name, name, desc, arg.Description) name = fixupArg(name) arg.Name = name arg.Description = desc diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index e477e3b5..7734de1f 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -67,5 +67,11 @@ func (cmd *cmdAdd) Execute(args []string) error { } func init() { - AddCommand("add", shortAddHelp, longAddHelp, func() flags.Commander { return &cmdAdd{} }, addDescs, nil) + AddCommand(&CmdInfo{ + Name: "add", + ShortHelp: shortAddHelp, + LongHelp: longAddHelp, + Builder: func() flags.Commander { return &cmdAdd{} }, + OptDescs: addDescs, + }) } diff --git a/internals/cli/cmd_autostart.go b/internals/cli/cmd_autostart.go index 31f38f41..a8601aea 100644 --- a/internals/cli/cmd_autostart.go +++ b/internals/cli/cmd_autostart.go @@ -31,7 +31,13 @@ type cmdAutoStart struct { } func init() { - AddCommand("autostart", shortAutoStartHelp, longAutoStartHelp, func() flags.Commander { return &cmdAutoStart{} }, waitDescs, nil) + AddCommand(&CmdInfo{ + Name: "autostart", + ShortHelp: shortAutoStartHelp, + LongHelp: longAutoStartHelp, + Builder: func() flags.Commander { return &cmdAutoStart{} }, + OptDescs: waitDescs, + }) } func (cmd cmdAutoStart) Execute(args []string) error { diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index be238a3a..19b8bf34 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -48,12 +48,21 @@ type cmdTasks struct { } func init() { - AddCommand("changes", shortChangesHelp, longChangesHelp, - func() flags.Commander { return &cmdChanges{} }, timeDescs, nil) - AddCommand("tasks", shortTasksHelp, longTasksHelp, - func() flags.Commander { return &cmdTasks{} }, - merge(changeIDMixinOptDesc, timeDescs), - changeIDMixinArgDesc) + AddCommand(&CmdInfo{ + Name: "changes", + ShortHelp: shortChangesHelp, + LongHelp: longChangesHelp, + Builder: func() flags.Commander { return &cmdChanges{} }, + OptDescs: timeDescs, + }) + AddCommand(&CmdInfo{ + Name: "tasks", + ShortHelp: shortTasksHelp, + LongHelp: longTasksHelp, + Builder: func() flags.Commander { return &cmdTasks{} }, + OptDescs: merge(changeIDMixinOptDesc, timeDescs), + ArgDescs: changeIDMixinArgDesc, + }) } type changesByTime []*client.Change diff --git a/internals/cli/cmd_checks.go b/internals/cli/cmd_checks.go index 6fe93d34..92e8d5ed 100644 --- a/internals/cli/cmd_checks.go +++ b/internals/cli/cmd_checks.go @@ -79,5 +79,11 @@ func (cmd *cmdChecks) Execute(args []string) error { } func init() { - AddCommand("checks", shortChecksHelp, longChecksHelp, func() flags.Commander { return &cmdChecks{} }, checksDescs, nil) + AddCommand(&CmdInfo{ + Name: "checks", + ShortHelp: shortChecksHelp, + LongHelp: longChecksHelp, + Builder: func() flags.Commander { return &cmdChecks{} }, + OptDescs: checksDescs, + }) } diff --git a/internals/cli/cmd_enter.go b/internals/cli/cmd_enter.go index 0d93b3d8..0343e521 100644 --- a/internals/cli/cmd_enter.go +++ b/internals/cli/cmd_enter.go @@ -58,10 +58,17 @@ func init() { for k, v := range sharedRunEnterOptsHelp { optsHelp[k] = v } - cmdInfo := AddCommand("enter", shortEnterHelp, longEnterHelp, func() flags.Commander { return &cmdEnter{} }, optsHelp, nil) - cmdInfo.extra = func(cmd *flags.Command) { - cmd.PassAfterNonOption = true - } + AddCommand(&CmdInfo{ + Name: "enter", + ShortHelp: shortEnterHelp, + LongHelp: longEnterHelp, + Builder: func() flags.Commander { return &cmdEnter{} }, + OptDescs: optsHelp, + + Extra: func(cmd *flags.Command) { + cmd.PassAfterNonOption = true + }, + }) } func commandEnterFlags(commander flags.Commander) (enterFlags enterFlags, supported bool) { diff --git a/internals/cli/cmd_exec.go b/internals/cli/cmd_exec.go index fec1c5e2..b2f0c3d9 100644 --- a/internals/cli/cmd_exec.go +++ b/internals/cli/cmd_exec.go @@ -264,8 +264,14 @@ func execControlHandler(process *client.ExecProcess, terminal bool, stop <-chan } func init() { - info := AddCommand("exec", shortExecHelp, longExecHelp, func() flags.Commander { return &cmdExec{} }, execDescs, nil) - info.extra = func(cmd *flags.Command) { - cmd.PassAfterNonOption = true - } + AddCommand(&CmdInfo{ + Name: "exec", + ShortHelp: shortExecHelp, + LongHelp: longExecHelp, + Builder: func() flags.Commander { return &cmdExec{} }, + OptDescs: execDescs, + Extra: func(cmd *flags.Command) { + cmd.PassAfterNonOption = true + }, + }) } diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index cd923bf9..4f850ada 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -79,11 +79,16 @@ type cmdHelp struct { } func init() { - AddCommand("help", shortHelpHelp, longHelpHelp, func() flags.Commander { return &cmdHelp{} }, - map[string]string{ + AddCommand(&CmdInfo{ + Name: "help", + ShortHelp: shortHelpHelp, + LongHelp: longHelpHelp, + Builder: func() flags.Commander { return &cmdHelp{} }, + OptDescs: map[string]string{ "all": "Show a short summary of all commands", "man": "Generate the manpage", - }, nil) + }, + }) } func (cmd *cmdHelp) setParser(parser *flags.Parser) { @@ -164,8 +169,8 @@ type HelpCategory struct { Commands []string } -// helpCategories helps us by grouping commands -var helpCategories = []HelpCategory{{ +// HelpCategories helps us by grouping commands +var HelpCategories = []HelpCategory{{ Label: "Run", Description: "run pebble", Commands: []string{"run", "help", "version"}, @@ -191,11 +196,6 @@ var helpCategories = []HelpCategory{{ Commands: []string{"warnings", "okay"}, }} -// AddHelpCategory appends an existing help category to the Pebble help manual. -func AddHelpCategory(category HelpCategory) { - helpCategories = append(helpCategories, category) -} - var ( longPebbleDescription = strings.TrimSpace(` Pebble lets you control services and perform management actions on @@ -234,12 +234,12 @@ func printShortHelp() { printHelpHeader() fmt.Fprintln(Stdout) maxLen := 0 - for _, categ := range helpCategories { + for _, categ := range HelpCategories { if l := utf8.RuneCountInString(categ.Label); l > maxLen { maxLen = l } } - for _, categ := range helpCategories { + for _, categ := range HelpCategories { fmt.Fprintf(Stdout, "%*s: %s\n", maxLen+2, categ.Label, strings.Join(categ.Commands, ", ")) } printHelpFooter() @@ -249,7 +249,7 @@ func printShortHelp() { func printLongHelp(parser *flags.Parser) { printHelpHeader() maxLen := 0 - for _, categ := range helpCategories { + for _, categ := range HelpCategories { for _, command := range categ.Commands { if l := len(command); l > maxLen { maxLen = l @@ -264,7 +264,7 @@ func printLongHelp(parser *flags.Parser) { cmdLookup[cmd.Name] = cmd } - for _, categ := range helpCategories { + for _, categ := range HelpCategories { fmt.Fprintln(Stdout) fmt.Fprintf(Stdout, " %s (%s):\n", categ.Label, categ.Description) for _, name := range categ.Commands { diff --git a/internals/cli/cmd_help_test.go b/internals/cli/cmd_help_test.go index e04769a8..cdab5a2b 100644 --- a/internals/cli/cmd_help_test.go +++ b/internals/cli/cmd_help_test.go @@ -114,7 +114,7 @@ func (s *PebbleSuite) TestAddHelpCategory(c *C) { restore := fakeArgs("pebble") defer restore() - cli.AddHelpCategory(cli.HelpCategory{ + cli.HelpCategories = append(cli.HelpCategories, cli.HelpCategory{ Label: "Test category", Description: "Test description", Commands: []string{"run", "logs"}, diff --git a/internals/cli/cmd_logs.go b/internals/cli/cmd_logs.go index 43655f70..bbb32959 100644 --- a/internals/cli/cmd_logs.go +++ b/internals/cli/cmd_logs.go @@ -121,5 +121,11 @@ func notifyContext(parent context.Context, signals ...os.Signal) context.Context } func init() { - AddCommand("logs", shortLogsHelp, longLogsHelp, func() flags.Commander { return &cmdLogs{} }, logsDescs, nil) + AddCommand(&CmdInfo{ + Name: "logs", + ShortHelp: shortLogsHelp, + LongHelp: longLogsHelp, + Builder: func() flags.Commander { return &cmdLogs{} }, + OptDescs: logsDescs, + }) } diff --git a/internals/cli/cmd_ls.go b/internals/cli/cmd_ls.go index 39907669..1efb66d5 100644 --- a/internals/cli/cmd_ls.go +++ b/internals/cli/cmd_ls.go @@ -103,5 +103,11 @@ func parseGlob(path string) (parsedPath, parsedPattern string, err error) { } func init() { - AddCommand("ls", shortLsHelp, longLsHelp, func() flags.Commander { return &cmdLs{} }, merge(lsDescs, timeDescs), nil) + AddCommand(&CmdInfo{ + Name: "ls", + ShortHelp: shortLsHelp, + LongHelp: longLsHelp, + Builder: func() flags.Commander { return &cmdLs{} }, + OptDescs: merge(lsDescs, timeDescs), + }) } diff --git a/internals/cli/cmd_mkdir.go b/internals/cli/cmd_mkdir.go index 8d7cb068..f8417879 100644 --- a/internals/cli/cmd_mkdir.go +++ b/internals/cli/cmd_mkdir.go @@ -79,5 +79,11 @@ func (cmd *cmdMkdir) Execute(args []string) error { } func init() { - AddCommand("mkdir", shortMkdirHelp, longMkdirHelp, func() flags.Commander { return &cmdMkdir{} }, mkdirDescs, nil) + AddCommand(&CmdInfo{ + Name: "mkdir", + ShortHelp: shortMkdirHelp, + LongHelp: longMkdirHelp, + Builder: func() flags.Commander { return &cmdMkdir{} }, + OptDescs: mkdirDescs, + }) } diff --git a/internals/cli/cmd_plan.go b/internals/cli/cmd_plan.go index 0b74051a..1e1d89d2 100644 --- a/internals/cli/cmd_plan.go +++ b/internals/cli/cmd_plan.go @@ -43,5 +43,10 @@ func (cmd *cmdPlan) Execute(args []string) error { } func init() { - AddCommand("plan", shortPlanHelp, longPlanHelp, func() flags.Commander { return &cmdPlan{} }, nil, nil) + AddCommand(&CmdInfo{ + Name: "plan", + ShortHelp: shortPlanHelp, + LongHelp: longPlanHelp, + Builder: func() flags.Commander { return &cmdPlan{} }, + }) } diff --git a/internals/cli/cmd_replan.go b/internals/cli/cmd_replan.go index 3dd57c46..95606183 100644 --- a/internals/cli/cmd_replan.go +++ b/internals/cli/cmd_replan.go @@ -32,7 +32,13 @@ type cmdReplan struct { } func init() { - AddCommand("replan", shortReplanHelp, longReplanHelp, func() flags.Commander { return &cmdReplan{} }, waitDescs, nil) + AddCommand(&CmdInfo{ + Name: "replan", + ShortHelp: shortReplanHelp, + LongHelp: longReplanHelp, + Builder: func() flags.Commander { return &cmdReplan{} }, + OptDescs: waitDescs, + }) } func (cmd cmdReplan) Execute(args []string) error { diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index 5cf009d1..62329b09 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -33,7 +33,13 @@ type cmdRestart struct { } func init() { - AddCommand("restart", shortRestartHelp, longRestartHelp, func() flags.Commander { return &cmdRestart{} }, waitDescs, nil) + AddCommand(&CmdInfo{ + Name: "restart", + ShortHelp: shortRestartHelp, + LongHelp: longRestartHelp, + Builder: func() flags.Commander { return &cmdRestart{} }, + OptDescs: waitDescs, + }) } func (cmd cmdRestart) Execute(args []string) error { diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index 94cd3624..2f731cda 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -51,5 +51,11 @@ func (cmd *cmdRm) Execute(args []string) error { } func init() { - AddCommand("rm", shortRmHelp, longRmHelp, func() flags.Commander { return &cmdRm{} }, rmDescs, nil) + AddCommand(&CmdInfo{ + Name: "rm", + ShortHelp: shortRmHelp, + LongHelp: longRmHelp, + Builder: func() flags.Commander { return &cmdRm{} }, + OptDescs: rmDescs, + }) } diff --git a/internals/cli/cmd_run.go b/internals/cli/cmd_run.go index 9cc09068..430a0ecd 100644 --- a/internals/cli/cmd_run.go +++ b/internals/cli/cmd_run.go @@ -65,8 +65,13 @@ type cmdRun struct { } func init() { - AddCommand("run", shortRunHelp, longRunHelp, func() flags.Commander { return &cmdRun{} }, - sharedRunEnterOptsHelp, nil) + AddCommand(&CmdInfo{ + Name: "run", + ShortHelp: shortRunHelp, + LongHelp: longRunHelp, + Builder: func() flags.Commander { return &cmdRun{} }, + OptDescs: sharedRunEnterOptsHelp, + }) } func (rcmd *cmdRun) Execute(args []string) error { diff --git a/internals/cli/cmd_services.go b/internals/cli/cmd_services.go index d1009704..0f94cbcf 100644 --- a/internals/cli/cmd_services.go +++ b/internals/cli/cmd_services.go @@ -73,7 +73,11 @@ func (cmd *cmdServices) Execute(args []string) error { } func init() { - AddCommand("services", shortServicesHelp, longServicesHelp, - func() flags.Commander { return &cmdServices{} }, - timeDescs, nil) + AddCommand(&CmdInfo{ + Name: "services", + ShortHelp: shortServicesHelp, + LongHelp: longServicesHelp, + Builder: func() flags.Commander { return &cmdServices{} }, + OptDescs: timeDescs, + }) } diff --git a/internals/cli/cmd_signal.go b/internals/cli/cmd_signal.go index d92a1acf..f5721119 100644 --- a/internals/cli/cmd_signal.go +++ b/internals/cli/cmd_signal.go @@ -58,5 +58,10 @@ func (cmd *cmdSignal) Execute(args []string) error { } func init() { - AddCommand("signal", shortSignalHelp, longSignalHelp, func() flags.Commander { return &cmdSignal{} }, nil, nil) + AddCommand(&CmdInfo{ + Name: "signal", + ShortHelp: shortSignalHelp, + LongHelp: longSignalHelp, + Builder: func() flags.Commander { return &cmdSignal{} }, + }) } diff --git a/internals/cli/cmd_start.go b/internals/cli/cmd_start.go index d36eba40..4f474a57 100644 --- a/internals/cli/cmd_start.go +++ b/internals/cli/cmd_start.go @@ -34,7 +34,13 @@ type cmdStart struct { } func init() { - AddCommand("start", shortStartHelp, longStartHelp, func() flags.Commander { return &cmdStart{} }, waitDescs, nil) + AddCommand(&CmdInfo{ + Name: "start", + ShortHelp: shortStartHelp, + LongHelp: longStartHelp, + Builder: func() flags.Commander { return &cmdStart{} }, + OptDescs: waitDescs, + }) } func (cmd cmdStart) Execute(args []string) error { diff --git a/internals/cli/cmd_stop.go b/internals/cli/cmd_stop.go index 95473d65..db9f5d15 100644 --- a/internals/cli/cmd_stop.go +++ b/internals/cli/cmd_stop.go @@ -34,7 +34,13 @@ type cmdStop struct { } func init() { - AddCommand("stop", shortStopHelp, longStopHelp, func() flags.Commander { return &cmdStop{} }, waitDescs, nil) + AddCommand(&CmdInfo{ + Name: "stop", + ShortHelp: shortStopHelp, + LongHelp: longStopHelp, + Builder: func() flags.Commander { return &cmdStop{} }, + OptDescs: waitDescs, + }) } func (cmd cmdStop) Execute(args []string) error { diff --git a/internals/cli/cmd_version.go b/internals/cli/cmd_version.go index a36bb0c5..ecbe19a0 100644 --- a/internals/cli/cmd_version.go +++ b/internals/cli/cmd_version.go @@ -38,7 +38,13 @@ var versionDescs = map[string]string{ } func init() { - AddCommand("version", shortVersionHelp, longVersionHelp, func() flags.Commander { return &cmdVersion{} }, versionDescs, nil) + AddCommand(&CmdInfo{ + Name: "version", + ShortHelp: shortVersionHelp, + LongHelp: longVersionHelp, + Builder: func() flags.Commander { return &cmdVersion{} }, + OptDescs: versionDescs, + }) } func (cmd cmdVersion) Execute(args []string) error { diff --git a/internals/cli/cmd_warnings.go b/internals/cli/cmd_warnings.go index f12c32c1..2b5642fb 100644 --- a/internals/cli/cmd_warnings.go +++ b/internals/cli/cmd_warnings.go @@ -61,11 +61,22 @@ sufficient time has passed. ` func init() { - AddCommand("warnings", shortWarningsHelp, longWarningsHelp, func() flags.Commander { return &cmdWarnings{} }, merge(timeDescs, unicodeDescs, map[string]string{ - "all": "Show all warnings", - "verbose": "Show more information", - }), nil) - AddCommand("okay", shortOkayHelp, longOkayHelp, func() flags.Commander { return &cmdOkay{} }, nil, nil) + AddCommand(&CmdInfo{ + Name: "warnings", + ShortHelp: shortWarningsHelp, + LongHelp: longWarningsHelp, + Builder: func() flags.Commander { return &cmdWarnings{} }, + OptDescs: merge(timeDescs, unicodeDescs, map[string]string{ + "all": "Show all warnings", + "verbose": "Show more information", + }), + }) + AddCommand(&CmdInfo{ + Name: "okay", + ShortHelp: shortOkayHelp, + LongHelp: longOkayHelp, + Builder: func() flags.Commander { return &cmdOkay{} }, + }) } func (cmd *cmdWarnings) Execute(args []string) error { From 4e3bde99f6471e447596b2b0ab485f7932857e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Wed, 14 Jun 2023 12:22:40 +0200 Subject: [PATCH 05/19] cli: pass CmdInfo by value to AddCommand --- internals/cli/cli.go | 8 ++++---- internals/cli/cmd_add.go | 2 +- internals/cli/cmd_autostart.go | 2 +- internals/cli/cmd_changes.go | 4 ++-- internals/cli/cmd_checks.go | 2 +- internals/cli/cmd_enter.go | 2 +- internals/cli/cmd_exec.go | 2 +- internals/cli/cmd_help.go | 2 +- internals/cli/cmd_logs.go | 2 +- internals/cli/cmd_ls.go | 2 +- internals/cli/cmd_mkdir.go | 2 +- internals/cli/cmd_plan.go | 2 +- internals/cli/cmd_replan.go | 2 +- internals/cli/cmd_restart.go | 2 +- internals/cli/cmd_rm.go | 2 +- internals/cli/cmd_run.go | 2 +- internals/cli/cmd_services.go | 2 +- internals/cli/cmd_signal.go | 2 +- internals/cli/cmd_start.go | 2 +- internals/cli/cmd_stop.go | 2 +- internals/cli/cmd_version.go | 2 +- internals/cli/cmd_warnings.go | 4 ++-- 22 files changed, 27 insertions(+), 27 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index cd901ea7..2cf3bde0 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -82,15 +82,15 @@ var debugCommands []*CmdInfo // AddCommand replaces parser.addCommand() in a way that is compatible with // re-constructing a pristine parser. -func AddCommand(info *CmdInfo) { - commands = append(commands, info) +func AddCommand(info CmdInfo) { + commands = append(commands, &info) } // addDebugCommand replaces parser.addCommand() in a way that is // compatible with re-constructing a pristine parser. It is meant for // adding debug commands. -func addDebugCommand(info *CmdInfo) { - debugCommands = append(debugCommands, info) +func addDebugCommand(info CmdInfo) { + debugCommands = append(debugCommands, &info) } type parserSetter interface { diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index 7734de1f..0e12b7c0 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -67,7 +67,7 @@ func (cmd *cmdAdd) Execute(args []string) error { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "add", ShortHelp: shortAddHelp, LongHelp: longAddHelp, diff --git a/internals/cli/cmd_autostart.go b/internals/cli/cmd_autostart.go index a8601aea..95fb8990 100644 --- a/internals/cli/cmd_autostart.go +++ b/internals/cli/cmd_autostart.go @@ -31,7 +31,7 @@ type cmdAutoStart struct { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "autostart", ShortHelp: shortAutoStartHelp, LongHelp: longAutoStartHelp, diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index 19b8bf34..85d644c5 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -48,14 +48,14 @@ type cmdTasks struct { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "changes", ShortHelp: shortChangesHelp, LongHelp: longChangesHelp, Builder: func() flags.Commander { return &cmdChanges{} }, OptDescs: timeDescs, }) - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "tasks", ShortHelp: shortTasksHelp, LongHelp: longTasksHelp, diff --git a/internals/cli/cmd_checks.go b/internals/cli/cmd_checks.go index 92e8d5ed..9021dfd6 100644 --- a/internals/cli/cmd_checks.go +++ b/internals/cli/cmd_checks.go @@ -79,7 +79,7 @@ func (cmd *cmdChecks) Execute(args []string) error { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "checks", ShortHelp: shortChecksHelp, LongHelp: longChecksHelp, diff --git a/internals/cli/cmd_enter.go b/internals/cli/cmd_enter.go index 0343e521..c25dd56a 100644 --- a/internals/cli/cmd_enter.go +++ b/internals/cli/cmd_enter.go @@ -58,7 +58,7 @@ func init() { for k, v := range sharedRunEnterOptsHelp { optsHelp[k] = v } - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "enter", ShortHelp: shortEnterHelp, LongHelp: longEnterHelp, diff --git a/internals/cli/cmd_exec.go b/internals/cli/cmd_exec.go index b2f0c3d9..170041ad 100644 --- a/internals/cli/cmd_exec.go +++ b/internals/cli/cmd_exec.go @@ -264,7 +264,7 @@ func execControlHandler(process *client.ExecProcess, terminal bool, stop <-chan } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "exec", ShortHelp: shortExecHelp, LongHelp: longExecHelp, diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index 4f850ada..401584fd 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -79,7 +79,7 @@ type cmdHelp struct { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "help", ShortHelp: shortHelpHelp, LongHelp: longHelpHelp, diff --git a/internals/cli/cmd_logs.go b/internals/cli/cmd_logs.go index bbb32959..b07e3a8d 100644 --- a/internals/cli/cmd_logs.go +++ b/internals/cli/cmd_logs.go @@ -121,7 +121,7 @@ func notifyContext(parent context.Context, signals ...os.Signal) context.Context } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "logs", ShortHelp: shortLogsHelp, LongHelp: longLogsHelp, diff --git a/internals/cli/cmd_ls.go b/internals/cli/cmd_ls.go index 1efb66d5..b3ea190e 100644 --- a/internals/cli/cmd_ls.go +++ b/internals/cli/cmd_ls.go @@ -103,7 +103,7 @@ func parseGlob(path string) (parsedPath, parsedPattern string, err error) { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "ls", ShortHelp: shortLsHelp, LongHelp: longLsHelp, diff --git a/internals/cli/cmd_mkdir.go b/internals/cli/cmd_mkdir.go index f8417879..1cdf4331 100644 --- a/internals/cli/cmd_mkdir.go +++ b/internals/cli/cmd_mkdir.go @@ -79,7 +79,7 @@ func (cmd *cmdMkdir) Execute(args []string) error { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "mkdir", ShortHelp: shortMkdirHelp, LongHelp: longMkdirHelp, diff --git a/internals/cli/cmd_plan.go b/internals/cli/cmd_plan.go index 1e1d89d2..352b68ef 100644 --- a/internals/cli/cmd_plan.go +++ b/internals/cli/cmd_plan.go @@ -43,7 +43,7 @@ func (cmd *cmdPlan) Execute(args []string) error { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "plan", ShortHelp: shortPlanHelp, LongHelp: longPlanHelp, diff --git a/internals/cli/cmd_replan.go b/internals/cli/cmd_replan.go index 95606183..3b5a1482 100644 --- a/internals/cli/cmd_replan.go +++ b/internals/cli/cmd_replan.go @@ -32,7 +32,7 @@ type cmdReplan struct { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "replan", ShortHelp: shortReplanHelp, LongHelp: longReplanHelp, diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index 62329b09..20f283b8 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -33,7 +33,7 @@ type cmdRestart struct { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "restart", ShortHelp: shortRestartHelp, LongHelp: longRestartHelp, diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index 2f731cda..9585c77a 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -51,7 +51,7 @@ func (cmd *cmdRm) Execute(args []string) error { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "rm", ShortHelp: shortRmHelp, LongHelp: longRmHelp, diff --git a/internals/cli/cmd_run.go b/internals/cli/cmd_run.go index 430a0ecd..bee145ea 100644 --- a/internals/cli/cmd_run.go +++ b/internals/cli/cmd_run.go @@ -65,7 +65,7 @@ type cmdRun struct { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "run", ShortHelp: shortRunHelp, LongHelp: longRunHelp, diff --git a/internals/cli/cmd_services.go b/internals/cli/cmd_services.go index 0f94cbcf..5d3a49bc 100644 --- a/internals/cli/cmd_services.go +++ b/internals/cli/cmd_services.go @@ -73,7 +73,7 @@ func (cmd *cmdServices) Execute(args []string) error { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "services", ShortHelp: shortServicesHelp, LongHelp: longServicesHelp, diff --git a/internals/cli/cmd_signal.go b/internals/cli/cmd_signal.go index f5721119..59421104 100644 --- a/internals/cli/cmd_signal.go +++ b/internals/cli/cmd_signal.go @@ -58,7 +58,7 @@ func (cmd *cmdSignal) Execute(args []string) error { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "signal", ShortHelp: shortSignalHelp, LongHelp: longSignalHelp, diff --git a/internals/cli/cmd_start.go b/internals/cli/cmd_start.go index 4f474a57..3ff6b9ca 100644 --- a/internals/cli/cmd_start.go +++ b/internals/cli/cmd_start.go @@ -34,7 +34,7 @@ type cmdStart struct { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "start", ShortHelp: shortStartHelp, LongHelp: longStartHelp, diff --git a/internals/cli/cmd_stop.go b/internals/cli/cmd_stop.go index db9f5d15..97d8f520 100644 --- a/internals/cli/cmd_stop.go +++ b/internals/cli/cmd_stop.go @@ -34,7 +34,7 @@ type cmdStop struct { } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "stop", ShortHelp: shortStopHelp, LongHelp: longStopHelp, diff --git a/internals/cli/cmd_version.go b/internals/cli/cmd_version.go index ecbe19a0..3d580ac8 100644 --- a/internals/cli/cmd_version.go +++ b/internals/cli/cmd_version.go @@ -38,7 +38,7 @@ var versionDescs = map[string]string{ } func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "version", ShortHelp: shortVersionHelp, LongHelp: longVersionHelp, diff --git a/internals/cli/cmd_warnings.go b/internals/cli/cmd_warnings.go index 2b5642fb..c1541e76 100644 --- a/internals/cli/cmd_warnings.go +++ b/internals/cli/cmd_warnings.go @@ -61,7 +61,7 @@ sufficient time has passed. ` func init() { - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "warnings", ShortHelp: shortWarningsHelp, LongHelp: longWarningsHelp, @@ -71,7 +71,7 @@ func init() { "verbose": "Show more information", }), }) - AddCommand(&CmdInfo{ + AddCommand(CmdInfo{ Name: "okay", ShortHelp: shortOkayHelp, LongHelp: longOkayHelp, From f8b585e28eff6e67eb7fbdc1cce0445a6f790e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Thu, 15 Jun 2023 13:52:40 +0200 Subject: [PATCH 06/19] cli: improve CmdInfo * Removed unused struct members such as Aliases and Hidden. * Replace the Extra function with PassAfterNonOption, as this is the only internal flags.Command option that justified its need. * Rename OptDesc/ArgDesc for clarity. * Document the public API. --- internals/cli/cli.go | 102 ++++++++++++++++++++------------- internals/cli/cmd_add.go | 14 ++--- internals/cli/cmd_autostart.go | 12 ++-- internals/cli/cmd_changes.go | 26 ++++----- internals/cli/cmd_checks.go | 14 ++--- internals/cli/cmd_enter.go | 17 +++--- internals/cli/cmd_exec.go | 18 +++--- internals/cli/cmd_help.go | 4 +- internals/cli/cmd_logs.go | 14 ++--- internals/cli/cmd_ls.go | 14 ++--- internals/cli/cmd_mkdir.go | 14 ++--- internals/cli/cmd_plan.go | 2 +- internals/cli/cmd_replan.go | 12 ++-- internals/cli/cmd_restart.go | 12 ++-- internals/cli/cmd_rm.go | 14 ++--- internals/cli/cmd_run.go | 12 ++-- internals/cli/cmd_services.go | 12 ++-- internals/cli/cmd_signal.go | 2 +- internals/cli/cmd_start.go | 12 ++-- internals/cli/cmd_stop.go | 12 ++-- internals/cli/cmd_version.go | 14 ++--- internals/cli/cmd_warnings.go | 6 +- internals/cli/format.go | 6 +- internals/cli/last.go | 6 +- internals/cli/times.go | 4 +- internals/cli/wait.go | 2 +- 26 files changed, 196 insertions(+), 181 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 2cf3bde0..9e34c427 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -53,9 +53,14 @@ type options struct { Version func() `long:"version"` } -type argDesc struct { - name string - desc string +// PositionalArg contains information about the positional arguments accepted +// by a command. +type PositionalArg struct { + // Name of the positional argument as displayed in the command usage string. + Name string + // ShortHelp is a single-line help string that will be displayed in the + // command's manual alongside the argument name. + ShortHelp string } var optionsData options @@ -63,15 +68,37 @@ var optionsData options // ErrExtraArgs is returned if extra arguments to a command are found var ErrExtraArgs = fmt.Errorf("too many arguments for command") -// CmdInfo holds information needed to call parser.AddCommand(...). +// CmdInfo holds information needed by the CLI to execute commands and +// populate entries in the help manual. type CmdInfo struct { - Name, ShortHelp, LongHelp string - Builder func() flags.Commander - Hidden bool - OptDescs map[string]string - ArgDescs []argDesc - Alias string - Extra func(*flags.Command) + // Name of the command + Name string + + // ShortHelp is a single-line help string that will be displayed + // in the full Pebble help manual (i.e. help --all) + ShortHelp string + + // LongHelp contains exhaustive documentation about the command, + // that will be reflected in the specific help manual for the + // command, and in the Pebble man page. + LongHelp string + + // Builder is a function that creates a new instance of the command + // struct containing an Execute(args []string) implementation. + Builder func() flags.Commander + + // OptionsHelp (optional) maps long option names (e.g. "foo" for --foo), + // to the help strings that will be shown in the command's manual + // besides every option. + OptionsHelp map[string]string + + // PositionalArgs (optional) contains help information about the + // positional arguments accepted by the command. + PositionalArgs []PositionalArg + + // Whether to pass all arguments after the first non-option as remaining + // command line arguments. This is equivalent to strict POSIX processing. + PassAfterNonOption bool } // commands holds information about all non-debug commands. @@ -82,15 +109,15 @@ var debugCommands []*CmdInfo // AddCommand replaces parser.addCommand() in a way that is compatible with // re-constructing a pristine parser. -func AddCommand(info CmdInfo) { - commands = append(commands, &info) +func AddCommand(info *CmdInfo) { + commands = append(commands, info) } // addDebugCommand replaces parser.addCommand() in a way that is // compatible with re-constructing a pristine parser. It is meant for // adding debug commands. -func addDebugCommand(info CmdInfo) { - debugCommands = append(debugCommands, &info) +func addDebugCommand(info *CmdInfo) { + debugCommands = append(debugCommands, info) } type parserSetter interface { @@ -186,22 +213,19 @@ func Parser(cli *client.Client) *flags.Parser { if err != nil { logger.Panicf("cannot add command %q: %v", c.Name, err) } - cmd.Hidden = c.Hidden - if c.Alias != "" { - cmd.Aliases = append(cmd.Aliases, c.Alias) - } + cmd.PassAfterNonOption = c.PassAfterNonOption opts := cmd.Options() - if c.OptDescs != nil && len(opts) != len(c.OptDescs) { - logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(c.OptDescs)) + if c.OptionsHelp != nil && len(opts) != len(c.OptionsHelp) { + logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(c.OptionsHelp)) } for _, opt := range opts { name := opt.LongName if name == "" { name = string(opt.ShortName) } - desc, ok := c.OptDescs[name] - if !(c.OptDescs == nil || ok) { + desc, ok := c.OptionsHelp[name] + if !(c.OptionsHelp == nil || ok) { logger.Panicf("%s missing description for %s", c.Name, name) } lintDesc(c.Name, name, desc, opt.Description) @@ -211,23 +235,20 @@ func Parser(cli *client.Client) *flags.Parser { } args := cmd.Args() - if c.ArgDescs != nil && len(args) != len(c.ArgDescs) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgDescs)) + if c.PositionalArgs != nil && len(args) != len(c.PositionalArgs) { + logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.PositionalArgs)) } for i, arg := range args { name, desc := arg.Name, "" - if c.ArgDescs != nil { - name = c.ArgDescs[i].name - desc = c.ArgDescs[i].desc + if c.PositionalArgs != nil { + name = c.PositionalArgs[i].Name + desc = c.PositionalArgs[i].ShortHelp } lintArg(c.Name, name, desc, arg.Description) name = fixupArg(name) arg.Name = name arg.Description = desc } - if c.Extra != nil { - c.Extra(cmd) - } } // Add the debug command debugCommand, err := parser.AddCommand("debug", shortDebugHelp, longDebugHelp, &cmdDebug{}) @@ -245,18 +266,17 @@ func Parser(cli *client.Client) *flags.Parser { if err != nil { logger.Panicf("cannot add debug command %q: %v", c.Name, err) } - cmd.Hidden = c.Hidden opts := cmd.Options() - if c.OptDescs != nil && len(opts) != len(c.OptDescs) { - logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(c.OptDescs)) + if c.OptionsHelp != nil && len(opts) != len(c.OptionsHelp) { + logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(c.OptionsHelp)) } for _, opt := range opts { name := opt.LongName if name == "" { name = string(opt.ShortName) } - desc, ok := c.OptDescs[name] - if !(c.OptDescs == nil || ok) { + desc, ok := c.OptionsHelp[name] + if !(c.OptionsHelp == nil || ok) { logger.Panicf("%s missing description for %s", c.Name, name) } lintDesc(c.Name, name, desc, opt.Description) @@ -266,14 +286,14 @@ func Parser(cli *client.Client) *flags.Parser { } args := cmd.Args() - if c.ArgDescs != nil && len(args) != len(c.ArgDescs) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgDescs)) + if c.PositionalArgs != nil && len(args) != len(c.PositionalArgs) { + logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.PositionalArgs)) } for i, arg := range args { name, desc := arg.Name, "" - if c.ArgDescs != nil { - name = c.ArgDescs[i].name - desc = c.ArgDescs[i].desc + if c.PositionalArgs != nil { + name = c.PositionalArgs[i].Name + desc = c.PositionalArgs[i].ShortHelp } lintArg(c.Name, name, desc, arg.Description) name = fixupArg(name) diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index 0e12b7c0..53d153cf 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -32,7 +32,7 @@ type cmdAdd struct { } `positional-args:"yes"` } -var addDescs = map[string]string{ +var addOptionsHelp = map[string]string{ "combine": `Combine the new layer with an existing layer that has the given label (default is to append)`, } @@ -67,11 +67,11 @@ func (cmd *cmdAdd) Execute(args []string) error { } func init() { - AddCommand(CmdInfo{ - Name: "add", - ShortHelp: shortAddHelp, - LongHelp: longAddHelp, - Builder: func() flags.Commander { return &cmdAdd{} }, - OptDescs: addDescs, + AddCommand(&CmdInfo{ + Name: "add", + ShortHelp: shortAddHelp, + LongHelp: longAddHelp, + Builder: func() flags.Commander { return &cmdAdd{} }, + OptionsHelp: addOptionsHelp, }) } diff --git a/internals/cli/cmd_autostart.go b/internals/cli/cmd_autostart.go index 95fb8990..d79505a6 100644 --- a/internals/cli/cmd_autostart.go +++ b/internals/cli/cmd_autostart.go @@ -31,12 +31,12 @@ type cmdAutoStart struct { } func init() { - AddCommand(CmdInfo{ - Name: "autostart", - ShortHelp: shortAutoStartHelp, - LongHelp: longAutoStartHelp, - Builder: func() flags.Commander { return &cmdAutoStart{} }, - OptDescs: waitDescs, + AddCommand(&CmdInfo{ + Name: "autostart", + ShortHelp: shortAutoStartHelp, + LongHelp: longAutoStartHelp, + Builder: func() flags.Commander { return &cmdAutoStart{} }, + OptionsHelp: waitOptionsHelp, }) } diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index 85d644c5..39d7075a 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -48,20 +48,20 @@ type cmdTasks struct { } func init() { - AddCommand(CmdInfo{ - Name: "changes", - ShortHelp: shortChangesHelp, - LongHelp: longChangesHelp, - Builder: func() flags.Commander { return &cmdChanges{} }, - OptDescs: timeDescs, + AddCommand(&CmdInfo{ + Name: "changes", + ShortHelp: shortChangesHelp, + LongHelp: longChangesHelp, + Builder: func() flags.Commander { return &cmdChanges{} }, + OptionsHelp: timeOptionsHelp, }) - AddCommand(CmdInfo{ - Name: "tasks", - ShortHelp: shortTasksHelp, - LongHelp: longTasksHelp, - Builder: func() flags.Commander { return &cmdTasks{} }, - OptDescs: merge(changeIDMixinOptDesc, timeDescs), - ArgDescs: changeIDMixinArgDesc, + AddCommand(&CmdInfo{ + Name: "tasks", + ShortHelp: shortTasksHelp, + LongHelp: longTasksHelp, + Builder: func() flags.Commander { return &cmdTasks{} }, + OptionsHelp: merge(changeIDMixinOptDesc, timeOptionsHelp), + PositionalArgs: changeIDMixinArgDesc, }) } diff --git a/internals/cli/cmd_checks.go b/internals/cli/cmd_checks.go index 9021dfd6..adfaf55b 100644 --- a/internals/cli/cmd_checks.go +++ b/internals/cli/cmd_checks.go @@ -30,7 +30,7 @@ type cmdChecks struct { } `positional-args:"yes"` } -var checksDescs = map[string]string{ +var checksOptionsHelp = map[string]string{ "level": `Check level to filter for ("alive" or "ready")`, } @@ -79,11 +79,11 @@ func (cmd *cmdChecks) Execute(args []string) error { } func init() { - AddCommand(CmdInfo{ - Name: "checks", - ShortHelp: shortChecksHelp, - LongHelp: longChecksHelp, - Builder: func() flags.Commander { return &cmdChecks{} }, - OptDescs: checksDescs, + AddCommand(&CmdInfo{ + Name: "checks", + ShortHelp: shortChecksHelp, + LongHelp: longChecksHelp, + Builder: func() flags.Commander { return &cmdChecks{} }, + OptionsHelp: checksOptionsHelp, }) } diff --git a/internals/cli/cmd_enter.go b/internals/cli/cmd_enter.go index c25dd56a..da2dd668 100644 --- a/internals/cli/cmd_enter.go +++ b/internals/cli/cmd_enter.go @@ -58,16 +58,13 @@ func init() { for k, v := range sharedRunEnterOptsHelp { optsHelp[k] = v } - AddCommand(CmdInfo{ - Name: "enter", - ShortHelp: shortEnterHelp, - LongHelp: longEnterHelp, - Builder: func() flags.Commander { return &cmdEnter{} }, - OptDescs: optsHelp, - - Extra: func(cmd *flags.Command) { - cmd.PassAfterNonOption = true - }, + AddCommand(&CmdInfo{ + Name: "enter", + ShortHelp: shortEnterHelp, + LongHelp: longEnterHelp, + Builder: func() flags.Commander { return &cmdEnter{} }, + OptionsHelp: optsHelp, + PassAfterNonOption: true, }) } diff --git a/internals/cli/cmd_exec.go b/internals/cli/cmd_exec.go index 170041ad..374249ea 100644 --- a/internals/cli/cmd_exec.go +++ b/internals/cli/cmd_exec.go @@ -48,7 +48,7 @@ type cmdExec struct { } `positional-args:"yes"` } -var execDescs = map[string]string{ +var execOptionsHelp = map[string]string{ "w": "Working directory to run command in", "env": "Environment variable to set (in 'FOO=bar' format)", "uid": "User ID to run command as", @@ -264,14 +264,12 @@ func execControlHandler(process *client.ExecProcess, terminal bool, stop <-chan } func init() { - AddCommand(CmdInfo{ - Name: "exec", - ShortHelp: shortExecHelp, - LongHelp: longExecHelp, - Builder: func() flags.Commander { return &cmdExec{} }, - OptDescs: execDescs, - Extra: func(cmd *flags.Command) { - cmd.PassAfterNonOption = true - }, + AddCommand(&CmdInfo{ + Name: "exec", + ShortHelp: shortExecHelp, + LongHelp: longExecHelp, + Builder: func() flags.Commander { return &cmdExec{} }, + OptionsHelp: execOptionsHelp, + PassAfterNonOption: true, }) } diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index 401584fd..19af03c2 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -79,12 +79,12 @@ type cmdHelp struct { } func init() { - AddCommand(CmdInfo{ + AddCommand(&CmdInfo{ Name: "help", ShortHelp: shortHelpHelp, LongHelp: longHelpHelp, Builder: func() flags.Commander { return &cmdHelp{} }, - OptDescs: map[string]string{ + OptionsHelp: map[string]string{ "all": "Show a short summary of all commands", "man": "Generate the manpage", }, diff --git a/internals/cli/cmd_logs.go b/internals/cli/cmd_logs.go index b07e3a8d..a9aec7f1 100644 --- a/internals/cli/cmd_logs.go +++ b/internals/cli/cmd_logs.go @@ -41,7 +41,7 @@ type cmdLogs struct { } `positional-args:"yes"` } -var logsDescs = map[string]string{ +var logsOptionsHelp = map[string]string{ "follow": "Follow (tail) logs for given services until Ctrl-C is\npressed. If no services are specified, show logs from\nall services running when the command starts.", "format": "Output format: \"text\" (default) or \"json\" (JSON lines).", "n": "Number of logs to show (before following); defaults to 30.\nIf 'all', show all buffered logs.", @@ -121,11 +121,11 @@ func notifyContext(parent context.Context, signals ...os.Signal) context.Context } func init() { - AddCommand(CmdInfo{ - Name: "logs", - ShortHelp: shortLogsHelp, - LongHelp: longLogsHelp, - Builder: func() flags.Commander { return &cmdLogs{} }, - OptDescs: logsDescs, + AddCommand(&CmdInfo{ + Name: "logs", + ShortHelp: shortLogsHelp, + LongHelp: longLogsHelp, + Builder: func() flags.Commander { return &cmdLogs{} }, + OptionsHelp: logsOptionsHelp, }) } diff --git a/internals/cli/cmd_ls.go b/internals/cli/cmd_ls.go index b3ea190e..01173570 100644 --- a/internals/cli/cmd_ls.go +++ b/internals/cli/cmd_ls.go @@ -38,7 +38,7 @@ type cmdLs struct { } `positional-args:"yes" required:"yes"` } -var lsDescs = map[string]string{ +var lsOptionsHelp = map[string]string{ "d": `List matching entries themselves, not directory contents`, "l": `Use a long listing format`, } @@ -103,11 +103,11 @@ func parseGlob(path string) (parsedPath, parsedPattern string, err error) { } func init() { - AddCommand(CmdInfo{ - Name: "ls", - ShortHelp: shortLsHelp, - LongHelp: longLsHelp, - Builder: func() flags.Commander { return &cmdLs{} }, - OptDescs: merge(lsDescs, timeDescs), + AddCommand(&CmdInfo{ + Name: "ls", + ShortHelp: shortLsHelp, + LongHelp: longLsHelp, + Builder: func() flags.Commander { return &cmdLs{} }, + OptionsHelp: merge(lsOptionsHelp, timeOptionsHelp), }) } diff --git a/internals/cli/cmd_mkdir.go b/internals/cli/cmd_mkdir.go index 1cdf4331..3cb1cc33 100644 --- a/internals/cli/cmd_mkdir.go +++ b/internals/cli/cmd_mkdir.go @@ -39,7 +39,7 @@ type cmdMkdir struct { } `positional-args:"yes" required:"yes"` } -var mkdirDescs = map[string]string{ +var mkdirOptionsHelp = map[string]string{ "p": "Create parent directories as needed", "m": "Set permissions (e.g. 0644)", "uid": "Use specified user ID", @@ -79,11 +79,11 @@ func (cmd *cmdMkdir) Execute(args []string) error { } func init() { - AddCommand(CmdInfo{ - Name: "mkdir", - ShortHelp: shortMkdirHelp, - LongHelp: longMkdirHelp, - Builder: func() flags.Commander { return &cmdMkdir{} }, - OptDescs: mkdirDescs, + AddCommand(&CmdInfo{ + Name: "mkdir", + ShortHelp: shortMkdirHelp, + LongHelp: longMkdirHelp, + Builder: func() flags.Commander { return &cmdMkdir{} }, + OptionsHelp: mkdirOptionsHelp, }) } diff --git a/internals/cli/cmd_plan.go b/internals/cli/cmd_plan.go index 352b68ef..1e1d89d2 100644 --- a/internals/cli/cmd_plan.go +++ b/internals/cli/cmd_plan.go @@ -43,7 +43,7 @@ func (cmd *cmdPlan) Execute(args []string) error { } func init() { - AddCommand(CmdInfo{ + AddCommand(&CmdInfo{ Name: "plan", ShortHelp: shortPlanHelp, LongHelp: longPlanHelp, diff --git a/internals/cli/cmd_replan.go b/internals/cli/cmd_replan.go index 3b5a1482..17bbe131 100644 --- a/internals/cli/cmd_replan.go +++ b/internals/cli/cmd_replan.go @@ -32,12 +32,12 @@ type cmdReplan struct { } func init() { - AddCommand(CmdInfo{ - Name: "replan", - ShortHelp: shortReplanHelp, - LongHelp: longReplanHelp, - Builder: func() flags.Commander { return &cmdReplan{} }, - OptDescs: waitDescs, + AddCommand(&CmdInfo{ + Name: "replan", + ShortHelp: shortReplanHelp, + LongHelp: longReplanHelp, + Builder: func() flags.Commander { return &cmdReplan{} }, + OptionsHelp: waitOptionsHelp, }) } diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index 20f283b8..761f4fe9 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -33,12 +33,12 @@ type cmdRestart struct { } func init() { - AddCommand(CmdInfo{ - Name: "restart", - ShortHelp: shortRestartHelp, - LongHelp: longRestartHelp, - Builder: func() flags.Commander { return &cmdRestart{} }, - OptDescs: waitDescs, + AddCommand(&CmdInfo{ + Name: "restart", + ShortHelp: shortRestartHelp, + LongHelp: longRestartHelp, + Builder: func() flags.Commander { return &cmdRestart{} }, + OptionsHelp: waitOptionsHelp, }) } diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index 9585c77a..43606fcd 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -30,7 +30,7 @@ type cmdRm struct { } `positional-args:"yes" required:"yes"` } -var rmDescs = map[string]string{ +var rmOptionsHelp = map[string]string{ "r": "Remove all files and directories recursively in the specified path", } @@ -51,11 +51,11 @@ func (cmd *cmdRm) Execute(args []string) error { } func init() { - AddCommand(CmdInfo{ - Name: "rm", - ShortHelp: shortRmHelp, - LongHelp: longRmHelp, - Builder: func() flags.Commander { return &cmdRm{} }, - OptDescs: rmDescs, + AddCommand(&CmdInfo{ + Name: "rm", + ShortHelp: shortRmHelp, + LongHelp: longRmHelp, + Builder: func() flags.Commander { return &cmdRm{} }, + OptionsHelp: rmOptionsHelp, }) } diff --git a/internals/cli/cmd_run.go b/internals/cli/cmd_run.go index bee145ea..c8cb5ca3 100644 --- a/internals/cli/cmd_run.go +++ b/internals/cli/cmd_run.go @@ -65,12 +65,12 @@ type cmdRun struct { } func init() { - AddCommand(CmdInfo{ - Name: "run", - ShortHelp: shortRunHelp, - LongHelp: longRunHelp, - Builder: func() flags.Commander { return &cmdRun{} }, - OptDescs: sharedRunEnterOptsHelp, + AddCommand(&CmdInfo{ + Name: "run", + ShortHelp: shortRunHelp, + LongHelp: longRunHelp, + Builder: func() flags.Commander { return &cmdRun{} }, + OptionsHelp: sharedRunEnterOptsHelp, }) } diff --git a/internals/cli/cmd_services.go b/internals/cli/cmd_services.go index 5d3a49bc..08756824 100644 --- a/internals/cli/cmd_services.go +++ b/internals/cli/cmd_services.go @@ -73,11 +73,11 @@ func (cmd *cmdServices) Execute(args []string) error { } func init() { - AddCommand(CmdInfo{ - Name: "services", - ShortHelp: shortServicesHelp, - LongHelp: longServicesHelp, - Builder: func() flags.Commander { return &cmdServices{} }, - OptDescs: timeDescs, + AddCommand(&CmdInfo{ + Name: "services", + ShortHelp: shortServicesHelp, + LongHelp: longServicesHelp, + Builder: func() flags.Commander { return &cmdServices{} }, + OptionsHelp: timeOptionsHelp, }) } diff --git a/internals/cli/cmd_signal.go b/internals/cli/cmd_signal.go index 59421104..f5721119 100644 --- a/internals/cli/cmd_signal.go +++ b/internals/cli/cmd_signal.go @@ -58,7 +58,7 @@ func (cmd *cmdSignal) Execute(args []string) error { } func init() { - AddCommand(CmdInfo{ + AddCommand(&CmdInfo{ Name: "signal", ShortHelp: shortSignalHelp, LongHelp: longSignalHelp, diff --git a/internals/cli/cmd_start.go b/internals/cli/cmd_start.go index 3ff6b9ca..0c6247ba 100644 --- a/internals/cli/cmd_start.go +++ b/internals/cli/cmd_start.go @@ -34,12 +34,12 @@ type cmdStart struct { } func init() { - AddCommand(CmdInfo{ - Name: "start", - ShortHelp: shortStartHelp, - LongHelp: longStartHelp, - Builder: func() flags.Commander { return &cmdStart{} }, - OptDescs: waitDescs, + AddCommand(&CmdInfo{ + Name: "start", + ShortHelp: shortStartHelp, + LongHelp: longStartHelp, + Builder: func() flags.Commander { return &cmdStart{} }, + OptionsHelp: waitOptionsHelp, }) } diff --git a/internals/cli/cmd_stop.go b/internals/cli/cmd_stop.go index 97d8f520..da4a2f7c 100644 --- a/internals/cli/cmd_stop.go +++ b/internals/cli/cmd_stop.go @@ -34,12 +34,12 @@ type cmdStop struct { } func init() { - AddCommand(CmdInfo{ - Name: "stop", - ShortHelp: shortStopHelp, - LongHelp: longStopHelp, - Builder: func() flags.Commander { return &cmdStop{} }, - OptDescs: waitDescs, + AddCommand(&CmdInfo{ + Name: "stop", + ShortHelp: shortStopHelp, + LongHelp: longStopHelp, + Builder: func() flags.Commander { return &cmdStop{} }, + OptionsHelp: waitOptionsHelp, }) } diff --git a/internals/cli/cmd_version.go b/internals/cli/cmd_version.go index 3d580ac8..fd2f397d 100644 --- a/internals/cli/cmd_version.go +++ b/internals/cli/cmd_version.go @@ -33,17 +33,17 @@ type cmdVersion struct { ClientOnly bool `long:"client"` } -var versionDescs = map[string]string{ +var versionOptionsHelp = map[string]string{ "client": `Only display the client version`, } func init() { - AddCommand(CmdInfo{ - Name: "version", - ShortHelp: shortVersionHelp, - LongHelp: longVersionHelp, - Builder: func() flags.Commander { return &cmdVersion{} }, - OptDescs: versionDescs, + AddCommand(&CmdInfo{ + Name: "version", + ShortHelp: shortVersionHelp, + LongHelp: longVersionHelp, + Builder: func() flags.Commander { return &cmdVersion{} }, + OptionsHelp: versionOptionsHelp, }) } diff --git a/internals/cli/cmd_warnings.go b/internals/cli/cmd_warnings.go index c1541e76..17c0a0a8 100644 --- a/internals/cli/cmd_warnings.go +++ b/internals/cli/cmd_warnings.go @@ -61,17 +61,17 @@ sufficient time has passed. ` func init() { - AddCommand(CmdInfo{ + AddCommand(&CmdInfo{ Name: "warnings", ShortHelp: shortWarningsHelp, LongHelp: longWarningsHelp, Builder: func() flags.Commander { return &cmdWarnings{} }, - OptDescs: merge(timeDescs, unicodeDescs, map[string]string{ + OptionsHelp: merge(timeOptionsHelp, unicodeOptionsHelp, map[string]string{ "all": "Show all warnings", "verbose": "Show more information", }), }) - AddCommand(CmdInfo{ + AddCommand(&CmdInfo{ Name: "okay", ShortHelp: shortOkayHelp, LongHelp: longOkayHelp, diff --git a/internals/cli/format.go b/internals/cli/format.go index e0c2050d..4dc55436 100644 --- a/internals/cli/format.go +++ b/internals/cli/format.go @@ -111,12 +111,12 @@ func colorTable(mode string) escapes { return color } -var colorDescs = map[string]string{ +var colorOptionsHelp = map[string]string{ "color": "Use a little bit of color to highlight some things.", - "unicode": unicodeDescs["unicode"], + "unicode": unicodeOptionsHelp["unicode"], } -var unicodeDescs = map[string]string{ +var unicodeOptionsHelp = map[string]string{ "unicode": "Use a little bit of Unicode to improve legibility.", } diff --git a/internals/cli/last.go b/internals/cli/last.go index 0114edb9..9b4276a6 100644 --- a/internals/cli/last.go +++ b/internals/cli/last.go @@ -33,9 +33,9 @@ var changeIDMixinOptDesc = map[string]string{ "last": "Select last change of given type (install, refresh, remove, try, auto-refresh, etc.). A question mark at the end of the type means to do nothing (instead of returning an error) if no change of the given type is found. Note the question mark could need protecting from the shell.", } -var changeIDMixinArgDesc = []argDesc{{ - name: "", - desc: "Change ID", +var changeIDMixinArgDesc = []PositionalArg{{ + Name: "", + ShortHelp: "Change ID", }} // should not be user-visible, but keep it clear and polite because mistakes happen diff --git a/internals/cli/times.go b/internals/cli/times.go index 612b7bbe..9f81ec32 100644 --- a/internals/cli/times.go +++ b/internals/cli/times.go @@ -29,7 +29,7 @@ type timeMixin struct { AbsTime bool `long:"abs-time"` } -var timeDescs = map[string]string{ +var timeOptionsHelp = map[string]string{ "abs-time": "Display absolute times (in RFC 3339 format). Otherwise, display relative times up to 60 days, then YYYY-MM-DD.", } @@ -44,7 +44,7 @@ type durationMixin struct { AbsTime bool `long:"abs-time"` } -var durationDescs = map[string]string{ +var durationOptionsHelp = map[string]string{ "abs-time": "Display absolute times (in RFC 3339 format). Otherwise, display short relative times.", } diff --git a/internals/cli/wait.go b/internals/cli/wait.go index ef2ba0d4..05cea01c 100644 --- a/internals/cli/wait.go +++ b/internals/cli/wait.go @@ -36,7 +36,7 @@ type waitMixin struct { skipAbort bool } -var waitDescs = map[string]string{ +var waitOptionsHelp = map[string]string{ "no-wait": "Do not wait for the operation to finish but just print the change id.", } From 4267955a5e7daf13cd114b0111de4e0e6af490cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Mon, 19 Jun 2023 09:41:15 +0200 Subject: [PATCH 07/19] cli: minor changes to CmdInfo * CmdInfo.{ShortHelp,LongHelp} -> CmdInfo.{Summary,Description} * CmdInfo.PositionalArgs -> CmdInfo.ArgumentsHelp * PositionalArg.{Name,ShortHelp} -> ArgumentHelp.{Placeholder,Help} --- internals/cli/cli.go | 49 +++++++++++++++++----------------- internals/cli/cmd_add.go | 4 +-- internals/cli/cmd_autostart.go | 4 +-- internals/cli/cmd_changes.go | 16 +++++------ internals/cli/cmd_checks.go | 4 +-- internals/cli/cmd_enter.go | 4 +-- internals/cli/cmd_exec.go | 4 +-- internals/cli/cmd_help.go | 8 +++--- internals/cli/cmd_logs.go | 4 +-- internals/cli/cmd_ls.go | 4 +-- internals/cli/cmd_mkdir.go | 4 +-- internals/cli/cmd_plan.go | 8 +++--- internals/cli/cmd_replan.go | 4 +-- internals/cli/cmd_restart.go | 4 +-- internals/cli/cmd_rm.go | 4 +-- internals/cli/cmd_run.go | 4 +-- internals/cli/cmd_services.go | 4 +-- internals/cli/cmd_signal.go | 8 +++--- internals/cli/cmd_start.go | 4 +-- internals/cli/cmd_stop.go | 4 +-- internals/cli/cmd_version.go | 4 +-- internals/cli/cmd_warnings.go | 16 +++++------ internals/cli/last.go | 6 ++--- 23 files changed, 87 insertions(+), 88 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 9e34c427..606e56b1 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -53,14 +53,13 @@ type options struct { Version func() `long:"version"` } -// PositionalArg contains information about the positional arguments accepted +// ArgumentHelp contains help information about the positional arguments accepted // by a command. -type PositionalArg struct { - // Name of the positional argument as displayed in the command usage string. - Name string - // ShortHelp is a single-line help string that will be displayed in the - // command's manual alongside the argument name. - ShortHelp string +type ArgumentHelp struct { + // Placeholer supplies a string representation of the argument. + Placeholder string + // Help provides information on how to use the argument. + Help string } var optionsData options @@ -74,14 +73,14 @@ type CmdInfo struct { // Name of the command Name string - // ShortHelp is a single-line help string that will be displayed + // Summary is a single-line help string that will be displayed // in the full Pebble help manual (i.e. help --all) - ShortHelp string + Summary string - // LongHelp contains exhaustive documentation about the command, + // Description contains exhaustive documentation about the command, // that will be reflected in the specific help manual for the // command, and in the Pebble man page. - LongHelp string + Description string // Builder is a function that creates a new instance of the command // struct containing an Execute(args []string) implementation. @@ -92,9 +91,9 @@ type CmdInfo struct { // besides every option. OptionsHelp map[string]string - // PositionalArgs (optional) contains help information about the + // ArgumentsHelp (optional) contains help information about the // positional arguments accepted by the command. - PositionalArgs []PositionalArg + ArgumentsHelp []ArgumentHelp // Whether to pass all arguments after the first non-option as remaining // command line arguments. This is equivalent to strict POSIX processing. @@ -209,7 +208,7 @@ func Parser(cli *client.Client) *flags.Parser { x.setParser(parser) } - cmd, err := parser.AddCommand(c.Name, c.ShortHelp, strings.TrimSpace(c.LongHelp), obj) + cmd, err := parser.AddCommand(c.Name, c.Summary, strings.TrimSpace(c.Description), obj) if err != nil { logger.Panicf("cannot add command %q: %v", c.Name, err) } @@ -235,14 +234,14 @@ func Parser(cli *client.Client) *flags.Parser { } args := cmd.Args() - if c.PositionalArgs != nil && len(args) != len(c.PositionalArgs) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.PositionalArgs)) + if c.ArgumentsHelp != nil && len(args) != len(c.ArgumentsHelp) { + logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgumentsHelp)) } for i, arg := range args { name, desc := arg.Name, "" - if c.PositionalArgs != nil { - name = c.PositionalArgs[i].Name - desc = c.PositionalArgs[i].ShortHelp + if c.ArgumentsHelp != nil { + name = c.ArgumentsHelp[i].Placeholder + desc = c.ArgumentsHelp[i].Help } lintArg(c.Name, name, desc, arg.Description) name = fixupArg(name) @@ -262,7 +261,7 @@ func Parser(cli *client.Client) *flags.Parser { if x, ok := obj.(clientSetter); ok { x.setClient(cli) } - cmd, err := debugCommand.AddCommand(c.Name, c.ShortHelp, strings.TrimSpace(c.LongHelp), obj) + cmd, err := debugCommand.AddCommand(c.Name, c.Summary, strings.TrimSpace(c.Description), obj) if err != nil { logger.Panicf("cannot add debug command %q: %v", c.Name, err) } @@ -286,14 +285,14 @@ func Parser(cli *client.Client) *flags.Parser { } args := cmd.Args() - if c.PositionalArgs != nil && len(args) != len(c.PositionalArgs) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.PositionalArgs)) + if c.ArgumentsHelp != nil && len(args) != len(c.ArgumentsHelp) { + logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgumentsHelp)) } for i, arg := range args { name, desc := arg.Name, "" - if c.PositionalArgs != nil { - name = c.PositionalArgs[i].Name - desc = c.PositionalArgs[i].ShortHelp + if c.ArgumentsHelp != nil { + name = c.ArgumentsHelp[i].Placeholder + desc = c.ArgumentsHelp[i].Help } lintArg(c.Name, name, desc, arg.Description) name = fixupArg(name) diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index 53d153cf..ab7d57a1 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -69,8 +69,8 @@ func (cmd *cmdAdd) Execute(args []string) error { func init() { AddCommand(&CmdInfo{ Name: "add", - ShortHelp: shortAddHelp, - LongHelp: longAddHelp, + Summary: shortAddHelp, + Description: longAddHelp, Builder: func() flags.Commander { return &cmdAdd{} }, OptionsHelp: addOptionsHelp, }) diff --git a/internals/cli/cmd_autostart.go b/internals/cli/cmd_autostart.go index d79505a6..00ccade2 100644 --- a/internals/cli/cmd_autostart.go +++ b/internals/cli/cmd_autostart.go @@ -33,8 +33,8 @@ type cmdAutoStart struct { func init() { AddCommand(&CmdInfo{ Name: "autostart", - ShortHelp: shortAutoStartHelp, - LongHelp: longAutoStartHelp, + Summary: shortAutoStartHelp, + Description: longAutoStartHelp, Builder: func() flags.Commander { return &cmdAutoStart{} }, OptionsHelp: waitOptionsHelp, }) diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index 39d7075a..6f42c899 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -50,18 +50,18 @@ type cmdTasks struct { func init() { AddCommand(&CmdInfo{ Name: "changes", - ShortHelp: shortChangesHelp, - LongHelp: longChangesHelp, + Summary: shortChangesHelp, + Description: longChangesHelp, Builder: func() flags.Commander { return &cmdChanges{} }, OptionsHelp: timeOptionsHelp, }) AddCommand(&CmdInfo{ - Name: "tasks", - ShortHelp: shortTasksHelp, - LongHelp: longTasksHelp, - Builder: func() flags.Commander { return &cmdTasks{} }, - OptionsHelp: merge(changeIDMixinOptDesc, timeOptionsHelp), - PositionalArgs: changeIDMixinArgDesc, + Name: "tasks", + Summary: shortTasksHelp, + Description: longTasksHelp, + Builder: func() flags.Commander { return &cmdTasks{} }, + OptionsHelp: merge(changeIDMixinOptDesc, timeOptionsHelp), + ArgumentsHelp: changeIDMixinArgDesc, }) } diff --git a/internals/cli/cmd_checks.go b/internals/cli/cmd_checks.go index adfaf55b..c23fcd96 100644 --- a/internals/cli/cmd_checks.go +++ b/internals/cli/cmd_checks.go @@ -81,8 +81,8 @@ func (cmd *cmdChecks) Execute(args []string) error { func init() { AddCommand(&CmdInfo{ Name: "checks", - ShortHelp: shortChecksHelp, - LongHelp: longChecksHelp, + Summary: shortChecksHelp, + Description: longChecksHelp, Builder: func() flags.Commander { return &cmdChecks{} }, OptionsHelp: checksOptionsHelp, }) diff --git a/internals/cli/cmd_enter.go b/internals/cli/cmd_enter.go index da2dd668..7eae08c6 100644 --- a/internals/cli/cmd_enter.go +++ b/internals/cli/cmd_enter.go @@ -60,8 +60,8 @@ func init() { } AddCommand(&CmdInfo{ Name: "enter", - ShortHelp: shortEnterHelp, - LongHelp: longEnterHelp, + Summary: shortEnterHelp, + Description: longEnterHelp, Builder: func() flags.Commander { return &cmdEnter{} }, OptionsHelp: optsHelp, PassAfterNonOption: true, diff --git a/internals/cli/cmd_exec.go b/internals/cli/cmd_exec.go index 374249ea..494293c3 100644 --- a/internals/cli/cmd_exec.go +++ b/internals/cli/cmd_exec.go @@ -266,8 +266,8 @@ func execControlHandler(process *client.ExecProcess, terminal bool, stop <-chan func init() { AddCommand(&CmdInfo{ Name: "exec", - ShortHelp: shortExecHelp, - LongHelp: longExecHelp, + Summary: shortExecHelp, + Description: longExecHelp, Builder: func() flags.Commander { return &cmdExec{} }, OptionsHelp: execOptionsHelp, PassAfterNonOption: true, diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index 19af03c2..80d8b41e 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -80,10 +80,10 @@ type cmdHelp struct { func init() { AddCommand(&CmdInfo{ - Name: "help", - ShortHelp: shortHelpHelp, - LongHelp: longHelpHelp, - Builder: func() flags.Commander { return &cmdHelp{} }, + Name: "help", + Summary: shortHelpHelp, + Description: longHelpHelp, + Builder: func() flags.Commander { return &cmdHelp{} }, OptionsHelp: map[string]string{ "all": "Show a short summary of all commands", "man": "Generate the manpage", diff --git a/internals/cli/cmd_logs.go b/internals/cli/cmd_logs.go index a9aec7f1..80ebf2ed 100644 --- a/internals/cli/cmd_logs.go +++ b/internals/cli/cmd_logs.go @@ -123,8 +123,8 @@ func notifyContext(parent context.Context, signals ...os.Signal) context.Context func init() { AddCommand(&CmdInfo{ Name: "logs", - ShortHelp: shortLogsHelp, - LongHelp: longLogsHelp, + Summary: shortLogsHelp, + Description: longLogsHelp, Builder: func() flags.Commander { return &cmdLogs{} }, OptionsHelp: logsOptionsHelp, }) diff --git a/internals/cli/cmd_ls.go b/internals/cli/cmd_ls.go index 01173570..6b21c322 100644 --- a/internals/cli/cmd_ls.go +++ b/internals/cli/cmd_ls.go @@ -105,8 +105,8 @@ func parseGlob(path string) (parsedPath, parsedPattern string, err error) { func init() { AddCommand(&CmdInfo{ Name: "ls", - ShortHelp: shortLsHelp, - LongHelp: longLsHelp, + Summary: shortLsHelp, + Description: longLsHelp, Builder: func() flags.Commander { return &cmdLs{} }, OptionsHelp: merge(lsOptionsHelp, timeOptionsHelp), }) diff --git a/internals/cli/cmd_mkdir.go b/internals/cli/cmd_mkdir.go index 3cb1cc33..c5b233aa 100644 --- a/internals/cli/cmd_mkdir.go +++ b/internals/cli/cmd_mkdir.go @@ -81,8 +81,8 @@ func (cmd *cmdMkdir) Execute(args []string) error { func init() { AddCommand(&CmdInfo{ Name: "mkdir", - ShortHelp: shortMkdirHelp, - LongHelp: longMkdirHelp, + Summary: shortMkdirHelp, + Description: longMkdirHelp, Builder: func() flags.Commander { return &cmdMkdir{} }, OptionsHelp: mkdirOptionsHelp, }) diff --git a/internals/cli/cmd_plan.go b/internals/cli/cmd_plan.go index 1e1d89d2..b57fcc4e 100644 --- a/internals/cli/cmd_plan.go +++ b/internals/cli/cmd_plan.go @@ -44,9 +44,9 @@ func (cmd *cmdPlan) Execute(args []string) error { func init() { AddCommand(&CmdInfo{ - Name: "plan", - ShortHelp: shortPlanHelp, - LongHelp: longPlanHelp, - Builder: func() flags.Commander { return &cmdPlan{} }, + Name: "plan", + Summary: shortPlanHelp, + Description: longPlanHelp, + Builder: func() flags.Commander { return &cmdPlan{} }, }) } diff --git a/internals/cli/cmd_replan.go b/internals/cli/cmd_replan.go index 17bbe131..f4837048 100644 --- a/internals/cli/cmd_replan.go +++ b/internals/cli/cmd_replan.go @@ -34,8 +34,8 @@ type cmdReplan struct { func init() { AddCommand(&CmdInfo{ Name: "replan", - ShortHelp: shortReplanHelp, - LongHelp: longReplanHelp, + Summary: shortReplanHelp, + Description: longReplanHelp, Builder: func() flags.Commander { return &cmdReplan{} }, OptionsHelp: waitOptionsHelp, }) diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index 761f4fe9..b65e61a8 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -35,8 +35,8 @@ type cmdRestart struct { func init() { AddCommand(&CmdInfo{ Name: "restart", - ShortHelp: shortRestartHelp, - LongHelp: longRestartHelp, + Summary: shortRestartHelp, + Description: longRestartHelp, Builder: func() flags.Commander { return &cmdRestart{} }, OptionsHelp: waitOptionsHelp, }) diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index 43606fcd..3d90d388 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -53,8 +53,8 @@ func (cmd *cmdRm) Execute(args []string) error { func init() { AddCommand(&CmdInfo{ Name: "rm", - ShortHelp: shortRmHelp, - LongHelp: longRmHelp, + Summary: shortRmHelp, + Description: longRmHelp, Builder: func() flags.Commander { return &cmdRm{} }, OptionsHelp: rmOptionsHelp, }) diff --git a/internals/cli/cmd_run.go b/internals/cli/cmd_run.go index c8cb5ca3..78381099 100644 --- a/internals/cli/cmd_run.go +++ b/internals/cli/cmd_run.go @@ -67,8 +67,8 @@ type cmdRun struct { func init() { AddCommand(&CmdInfo{ Name: "run", - ShortHelp: shortRunHelp, - LongHelp: longRunHelp, + Summary: shortRunHelp, + Description: longRunHelp, Builder: func() flags.Commander { return &cmdRun{} }, OptionsHelp: sharedRunEnterOptsHelp, }) diff --git a/internals/cli/cmd_services.go b/internals/cli/cmd_services.go index 08756824..37e597d2 100644 --- a/internals/cli/cmd_services.go +++ b/internals/cli/cmd_services.go @@ -75,8 +75,8 @@ func (cmd *cmdServices) Execute(args []string) error { func init() { AddCommand(&CmdInfo{ Name: "services", - ShortHelp: shortServicesHelp, - LongHelp: longServicesHelp, + Summary: shortServicesHelp, + Description: longServicesHelp, Builder: func() flags.Commander { return &cmdServices{} }, OptionsHelp: timeOptionsHelp, }) diff --git a/internals/cli/cmd_signal.go b/internals/cli/cmd_signal.go index f5721119..76b8a7ea 100644 --- a/internals/cli/cmd_signal.go +++ b/internals/cli/cmd_signal.go @@ -59,9 +59,9 @@ func (cmd *cmdSignal) Execute(args []string) error { func init() { AddCommand(&CmdInfo{ - Name: "signal", - ShortHelp: shortSignalHelp, - LongHelp: longSignalHelp, - Builder: func() flags.Commander { return &cmdSignal{} }, + Name: "signal", + Summary: shortSignalHelp, + Description: longSignalHelp, + Builder: func() flags.Commander { return &cmdSignal{} }, }) } diff --git a/internals/cli/cmd_start.go b/internals/cli/cmd_start.go index 0c6247ba..143da204 100644 --- a/internals/cli/cmd_start.go +++ b/internals/cli/cmd_start.go @@ -36,8 +36,8 @@ type cmdStart struct { func init() { AddCommand(&CmdInfo{ Name: "start", - ShortHelp: shortStartHelp, - LongHelp: longStartHelp, + Summary: shortStartHelp, + Description: longStartHelp, Builder: func() flags.Commander { return &cmdStart{} }, OptionsHelp: waitOptionsHelp, }) diff --git a/internals/cli/cmd_stop.go b/internals/cli/cmd_stop.go index da4a2f7c..1c378fe3 100644 --- a/internals/cli/cmd_stop.go +++ b/internals/cli/cmd_stop.go @@ -36,8 +36,8 @@ type cmdStop struct { func init() { AddCommand(&CmdInfo{ Name: "stop", - ShortHelp: shortStopHelp, - LongHelp: longStopHelp, + Summary: shortStopHelp, + Description: longStopHelp, Builder: func() flags.Commander { return &cmdStop{} }, OptionsHelp: waitOptionsHelp, }) diff --git a/internals/cli/cmd_version.go b/internals/cli/cmd_version.go index fd2f397d..c49c100d 100644 --- a/internals/cli/cmd_version.go +++ b/internals/cli/cmd_version.go @@ -40,8 +40,8 @@ var versionOptionsHelp = map[string]string{ func init() { AddCommand(&CmdInfo{ Name: "version", - ShortHelp: shortVersionHelp, - LongHelp: longVersionHelp, + Summary: shortVersionHelp, + Description: longVersionHelp, Builder: func() flags.Commander { return &cmdVersion{} }, OptionsHelp: versionOptionsHelp, }) diff --git a/internals/cli/cmd_warnings.go b/internals/cli/cmd_warnings.go index 17c0a0a8..d871f5f9 100644 --- a/internals/cli/cmd_warnings.go +++ b/internals/cli/cmd_warnings.go @@ -62,20 +62,20 @@ sufficient time has passed. func init() { AddCommand(&CmdInfo{ - Name: "warnings", - ShortHelp: shortWarningsHelp, - LongHelp: longWarningsHelp, - Builder: func() flags.Commander { return &cmdWarnings{} }, + Name: "warnings", + Summary: shortWarningsHelp, + Description: longWarningsHelp, + Builder: func() flags.Commander { return &cmdWarnings{} }, OptionsHelp: merge(timeOptionsHelp, unicodeOptionsHelp, map[string]string{ "all": "Show all warnings", "verbose": "Show more information", }), }) AddCommand(&CmdInfo{ - Name: "okay", - ShortHelp: shortOkayHelp, - LongHelp: longOkayHelp, - Builder: func() flags.Commander { return &cmdOkay{} }, + Name: "okay", + Summary: shortOkayHelp, + Description: longOkayHelp, + Builder: func() flags.Commander { return &cmdOkay{} }, }) } diff --git a/internals/cli/last.go b/internals/cli/last.go index 9b4276a6..6d3207a9 100644 --- a/internals/cli/last.go +++ b/internals/cli/last.go @@ -33,9 +33,9 @@ var changeIDMixinOptDesc = map[string]string{ "last": "Select last change of given type (install, refresh, remove, try, auto-refresh, etc.). A question mark at the end of the type means to do nothing (instead of returning an error) if no change of the given type is found. Note the question mark could need protecting from the shell.", } -var changeIDMixinArgDesc = []PositionalArg{{ - Name: "", - ShortHelp: "Change ID", +var changeIDMixinArgDesc = []ArgumentHelp{{ + Placeholder: "", + Help: "Change ID", }} // should not be user-visible, but keep it clear and polite because mistakes happen From c1669b04d136c89efb330ffd7956d456d99f2c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Thu, 22 Jun 2023 10:40:51 +0200 Subject: [PATCH 08/19] cli: use a map for both args and options --- internals/cli/cli.go | 14 +++++++------- internals/cli/cmd_changes.go | 4 ++-- internals/cli/last.go | 12 +++++++----- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 606e56b1..150dc42e 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -93,7 +93,7 @@ type CmdInfo struct { // ArgumentsHelp (optional) contains help information about the // positional arguments accepted by the command. - ArgumentsHelp []ArgumentHelp + ArgumentsHelp map[string]ArgumentHelp // Whether to pass all arguments after the first non-option as remaining // command line arguments. This is equivalent to strict POSIX processing. @@ -237,11 +237,11 @@ func Parser(cli *client.Client) *flags.Parser { if c.ArgumentsHelp != nil && len(args) != len(c.ArgumentsHelp) { logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgumentsHelp)) } - for i, arg := range args { + for _, arg := range args { name, desc := arg.Name, "" if c.ArgumentsHelp != nil { - name = c.ArgumentsHelp[i].Placeholder - desc = c.ArgumentsHelp[i].Help + name = c.ArgumentsHelp[name].Placeholder + desc = c.ArgumentsHelp[name].Help } lintArg(c.Name, name, desc, arg.Description) name = fixupArg(name) @@ -288,11 +288,11 @@ func Parser(cli *client.Client) *flags.Parser { if c.ArgumentsHelp != nil && len(args) != len(c.ArgumentsHelp) { logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgumentsHelp)) } - for i, arg := range args { + for _, arg := range args { name, desc := arg.Name, "" if c.ArgumentsHelp != nil { - name = c.ArgumentsHelp[i].Placeholder - desc = c.ArgumentsHelp[i].Help + name = c.ArgumentsHelp[name].Placeholder + desc = c.ArgumentsHelp[name].Help } lintArg(c.Name, name, desc, arg.Description) name = fixupArg(name) diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index 6f42c899..2f673f5e 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -60,8 +60,8 @@ func init() { Summary: shortTasksHelp, Description: longTasksHelp, Builder: func() flags.Commander { return &cmdTasks{} }, - OptionsHelp: merge(changeIDMixinOptDesc, timeOptionsHelp), - ArgumentsHelp: changeIDMixinArgDesc, + OptionsHelp: merge(changeIDMixinOptionsHelp, timeOptionsHelp), + ArgumentsHelp: changeIDMixinArgumentsHelp, }) } diff --git a/internals/cli/last.go b/internals/cli/last.go index 6d3207a9..36d7cc0a 100644 --- a/internals/cli/last.go +++ b/internals/cli/last.go @@ -29,14 +29,16 @@ type changeIDMixin struct { } `positional-args:"yes"` } -var changeIDMixinOptDesc = map[string]string{ +var changeIDMixinOptionsHelp = map[string]string{ "last": "Select last change of given type (install, refresh, remove, try, auto-refresh, etc.). A question mark at the end of the type means to do nothing (instead of returning an error) if no change of the given type is found. Note the question mark could need protecting from the shell.", } -var changeIDMixinArgDesc = []ArgumentHelp{{ - Placeholder: "", - Help: "Change ID", -}} +var changeIDMixinArgumentsHelp = map[string]ArgumentHelp{ + "": ArgumentHelp{ + Placeholder: "", + Help: "Change ID", + }, +} // should not be user-visible, but keep it clear and polite because mistakes happen var noChangeFoundOK = errors.New("no change found but that's ok") From 8ac498e921adb201a4f3db90984ffaa8fb49433c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Fri, 23 Jun 2023 13:23:23 +0200 Subject: [PATCH 09/19] cli: merge args/opts help * CmdInfo.ArgsHelp now contains the help text for short, long options and positional arguments, using a new convention. * func init() on all commands is now moved to the top of the source file, and help strings no longer are globals, for better readability and for immediate information about the command when reading from the top. * Remove debug command (which duplicated Parser() functionality) * Refactor Parser() * Still needs fix: broken workaround that has been removed, which previously overrode the usage string from the parser so that help manuals don't introduce the [-OPTIONS] string on the usage line. This is a bug in both the CLI help and manpage generation code in go-flags, and will be tackled in a future PR in canonical/go-flags. See canonical/go-flags#4 --- internals/cli/cli.go | 185 +++++++++++++-------------------- internals/cli/cmd_add.go | 30 +++--- internals/cli/cmd_autostart.go | 19 ++-- internals/cli/cmd_changes.go | 36 +++---- internals/cli/cmd_checks.go | 30 +++--- internals/cli/cmd_debug.go | 25 ----- internals/cli/cmd_enter.go | 53 ++++------ internals/cli/cmd_exec.go | 53 +++++----- internals/cli/cmd_help.go | 47 ++++----- internals/cli/cmd_logs.go | 42 ++++---- internals/cli/cmd_ls.go | 31 +++--- internals/cli/cmd_mkdir.go | 39 +++---- internals/cli/cmd_replan.go | 21 ++-- internals/cli/cmd_restart.go | 18 ++-- internals/cli/cmd_rm.go | 34 +++--- internals/cli/cmd_run.go | 43 ++++---- internals/cli/cmd_services.go | 24 ++--- internals/cli/cmd_signal.go | 22 ++-- internals/cli/cmd_start.go | 19 ++-- internals/cli/cmd_stop.go | 19 ++-- internals/cli/cmd_version.go | 29 +++--- internals/cli/cmd_warnings.go | 42 ++++---- internals/cli/format.go | 9 +- internals/cli/last.go | 20 ++-- internals/cli/times.go | 4 +- internals/cli/wait.go | 4 +- 26 files changed, 363 insertions(+), 535 deletions(-) delete mode 100644 internals/cli/cmd_debug.go diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 150dc42e..6925ab1f 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -49,10 +49,6 @@ var ( // the pebble client. const defaultPebbleDir = "/var/lib/pebble/default" -type options struct { - Version func() `long:"version"` -} - // ArgumentHelp contains help information about the positional arguments accepted // by a command. type ArgumentHelp struct { @@ -62,8 +58,6 @@ type ArgumentHelp struct { Help string } -var optionsData options - // ErrExtraArgs is returned if extra arguments to a command are found var ErrExtraArgs = fmt.Errorf("too many arguments for command") @@ -86,14 +80,15 @@ type CmdInfo struct { // struct containing an Execute(args []string) implementation. Builder func() flags.Commander - // OptionsHelp (optional) maps long option names (e.g. "foo" for --foo), - // to the help strings that will be shown in the command's manual - // besides every option. - OptionsHelp map[string]string - - // ArgumentsHelp (optional) contains help information about the - // positional arguments accepted by the command. - ArgumentsHelp map[string]ArgumentHelp + // ArgsHelp (optional) contains help about the command-line arguments + // (including options) supported by the command. + // + // map[string]string{ + // "--long-option": "my very long option", + // "-v": "verbose output", + // "": "named positional argument" + // } + ArgsHelp map[string]string // Whether to pass all arguments after the first non-option as remaining // command line arguments. This is equivalent to strict POSIX processing. @@ -103,26 +98,12 @@ type CmdInfo struct { // commands holds information about all non-debug commands. var commands []*CmdInfo -// debugCommands holds information about all debug commands. -var debugCommands []*CmdInfo - // AddCommand replaces parser.addCommand() in a way that is compatible with // re-constructing a pristine parser. func AddCommand(info *CmdInfo) { commands = append(commands, info) } -// addDebugCommand replaces parser.addCommand() in a way that is -// compatible with re-constructing a pristine parser. It is meant for -// adding debug commands. -func addDebugCommand(info *CmdInfo) { - debugCommands = append(debugCommands, info) -} - -type parserSetter interface { - setParser(*flags.Parser) -} - func lintDesc(cmdName, optName, desc, origDesc string) { if len(optName) == 0 { logger.Panicf("option on %q has no name", cmdName) @@ -165,37 +146,50 @@ func fixupArg(optName string) string { return optName } -type clientSetter interface { - setClient(*client.Client) -} - type clientMixin struct { client *client.Client } +type clientSetter interface { + setClient(*client.Client) +} + func (ch *clientMixin) setClient(cli *client.Client) { ch.client = cli } +type parserSetter interface { + setParser(*flags.Parser) +} + +type options struct { + Version func() `long:"version"` +} + // Parser creates and populates a fresh parser. // Since commands have local state a fresh parser is required to isolate tests // from each other. func Parser(cli *client.Client) *flags.Parser { - optionsData.Version = func() { - printVersions(cli) - panic(&exitStatus{0}) + // Implement --version by default on every command + defaultOptions := options{ + Version: func() { + printVersions(cli) + panic(&exitStatus{0}) + }, } - flagopts := flags.Options(flags.PassDoubleDash) - parser := flags.NewParser(&optionsData, flagopts) + + flagOpts := flags.Options(flags.PassDoubleDash) + parser := flags.NewParser(&defaultOptions, flagOpts) parser.ShortDescription = "Tool to interact with pebble" parser.LongDescription = longPebbleDescription - // hide the unhelpful "[OPTIONS]" from help output - parser.Usage = "" + + // Hide the global --version option on every command if version := parser.FindOptionByLongName("version"); version != nil { version.Description = "Print the version and exit" version.Hidden = true } - // add --help like what go-flags would do for us, but hidden + + // Add --help like what go-flags would do for us, but hidden addHelp(parser) // Add all regular commands @@ -214,92 +208,57 @@ func Parser(cli *client.Client) *flags.Parser { } cmd.PassAfterNonOption = c.PassAfterNonOption - opts := cmd.Options() - if c.OptionsHelp != nil && len(opts) != len(c.OptionsHelp) { - logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(c.OptionsHelp)) - } - for _, opt := range opts { - name := opt.LongName - if name == "" { - name = string(opt.ShortName) - } - desc, ok := c.OptionsHelp[name] - if !(c.OptionsHelp == nil || ok) { - logger.Panicf("%s missing description for %s", c.Name, name) - } - lintDesc(c.Name, name, desc, opt.Description) - if desc != "" { - opt.Description = desc + optionsHelp := map[string]string{} + positionalArgsHelp := map[string]string{} + + for specifier, help := range c.ArgsHelp { + if strings.HasPrefix(specifier, "--") { + optionsHelp[specifier] = help + } else if utf8.RuneCountInString(specifier) == 2 && strings.HasPrefix(specifier, "-") { + optionsHelp[specifier] = help + } else if strings.HasPrefix(specifier, "<") && strings.HasSuffix(specifier, ">") { + positionalArgsHelp[specifier] = help + } else { + logger.Panicf("invalid help specifier: %#v %#v", c.Name, strings.HasPrefix(specifier, "-")) } } - args := cmd.Args() - if c.ArgumentsHelp != nil && len(args) != len(c.ArgumentsHelp) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgumentsHelp)) - } - for _, arg := range args { - name, desc := arg.Name, "" - if c.ArgumentsHelp != nil { - name = c.ArgumentsHelp[name].Placeholder - desc = c.ArgumentsHelp[name].Help - } - lintArg(c.Name, name, desc, arg.Description) - name = fixupArg(name) - arg.Name = name - arg.Description = desc - } - } - // Add the debug command - debugCommand, err := parser.AddCommand("debug", shortDebugHelp, longDebugHelp, &cmdDebug{}) - debugCommand.Hidden = true - if err != nil { - logger.Panicf("cannot add command %q: %v", "debug", err) - } - // Add all the sub-commands of the debug command - for _, c := range debugCommands { - obj := c.Builder() - if x, ok := obj.(clientSetter); ok { - x.setClient(cli) - } - cmd, err := debugCommand.AddCommand(c.Name, c.Summary, strings.TrimSpace(c.Description), obj) - if err != nil { - logger.Panicf("cannot add debug command %q: %v", c.Name, err) - } + hasAnyOptionHelp := len(optionsHelp) > 0 + hasAnyPositionalHelp := len(positionalArgsHelp) > 0 + + // Check either all or none opts/positional argument descriptions are set opts := cmd.Options() - if c.OptionsHelp != nil && len(opts) != len(c.OptionsHelp) { - logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(c.OptionsHelp)) + if hasAnyOptionHelp && len(opts) != len(optionsHelp) { + logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(optionsHelp)) } + args := cmd.Args() + if hasAnyPositionalHelp && len(args) != len(positionalArgsHelp) { + logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(positionalArgsHelp)) + } + for _, opt := range opts { - name := opt.LongName - if name == "" { - name = string(opt.ShortName) - } - desc, ok := c.OptionsHelp[name] - if !(c.OptionsHelp == nil || ok) { - logger.Panicf("%s missing description for %s", c.Name, name) - } - lintDesc(c.Name, name, desc, opt.Description) - if desc != "" { - opt.Description = desc + if description, ok := optionsHelp["--"+opt.LongName]; ok { + lintDesc(c.Name, opt.LongName, description, opt.Description) + opt.Description = description + } else if description, ok := optionsHelp["-"+string(opt.ShortName)]; ok { + lintDesc(c.Name, string(opt.ShortName), description, opt.Description) + opt.Description = description + } else if hasAnyOptionHelp { + logger.Panicf("%s missing description for %s", c.Name, opt) } } - args := cmd.Args() - if c.ArgumentsHelp != nil && len(args) != len(c.ArgumentsHelp) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(c.ArgumentsHelp)) - } for _, arg := range args { - name, desc := arg.Name, "" - if c.ArgumentsHelp != nil { - name = c.ArgumentsHelp[name].Placeholder - desc = c.ArgumentsHelp[name].Help + if description, ok := positionalArgsHelp[arg.Name]; ok { + lintArg(c.Name, arg.Name, description, arg.Description) + arg.Name = fixupArg(arg.Name) + arg.Description = description + } else if hasAnyPositionalHelp { + logger.Panicf("%s missing description for %s", c.Name, arg.Name) } - lintArg(c.Name, name, desc, arg.Description) - name = fixupArg(name) - arg.Name = name - arg.Description = desc } } + return parser } diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index ab7d57a1..dcdb44d0 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -19,7 +19,6 @@ import ( "io/ioutil" "github.com/canonical/go-flags" - "github.com/canonical/pebble/client" ) @@ -32,17 +31,22 @@ type cmdAdd struct { } `positional-args:"yes"` } -var addOptionsHelp = map[string]string{ - "combine": `Combine the new layer with an existing layer that has the given label (default is to append)`, -} - -var shortAddHelp = "Dynamically add a layer to the plan's layers" -var longAddHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "add", + Summary: "Dynamically add a layer to the plan's layers", + Description: ` The add command reads the plan's layer YAML from the path specified and appends a layer with the given label to the plan's layers. If --combine is specified, combine the layer with an existing layer that has the given label (or append if the label is not found). -` +`, + ArgsHelp: map[string]string{ + "--combine": "Combine the new layer with an existing layer that has the given label (default is to append)", + }, + Builder: func() flags.Commander { return &cmdAdd{} }, + }) +} func (cmd *cmdAdd) Execute(args []string) error { if len(args) > 0 { @@ -65,13 +69,3 @@ func (cmd *cmdAdd) Execute(args []string) error { cmd.Positional.Label, cmd.Positional.LayerPath) return nil } - -func init() { - AddCommand(&CmdInfo{ - Name: "add", - Summary: shortAddHelp, - Description: longAddHelp, - Builder: func() flags.Commander { return &cmdAdd{} }, - OptionsHelp: addOptionsHelp, - }) -} diff --git a/internals/cli/cmd_autostart.go b/internals/cli/cmd_autostart.go index 00ccade2..a59b6680 100644 --- a/internals/cli/cmd_autostart.go +++ b/internals/cli/cmd_autostart.go @@ -20,23 +20,20 @@ import ( "github.com/canonical/pebble/client" ) -var shortAutoStartHelp = "Start services set to start by default" -var longAutoStartHelp = ` -The autostart command starts the services that were configured -to start by default. -` - type cmdAutoStart struct { waitMixin } func init() { AddCommand(&CmdInfo{ - Name: "autostart", - Summary: shortAutoStartHelp, - Description: longAutoStartHelp, - Builder: func() flags.Commander { return &cmdAutoStart{} }, - OptionsHelp: waitOptionsHelp, + Name: "autostart", + Summary: "Start services set to start by default", + Description: ` +The autostart command starts the services that were configured +to start by default. +`, + ArgsHelp: waitArgsHelp, + Builder: func() flags.Commander { return &cmdAutoStart{} }, }) } diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index 2f673f5e..0750d54f 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -24,16 +24,6 @@ import ( "github.com/canonical/pebble/client" ) -var shortChangesHelp = "List system changes" -var shortTasksHelp = "List a change's tasks" -var longChangesHelp = ` -The changes command displays a summary of system changes performed recently. -` -var longTasksHelp = ` -The tasks command displays a summary of tasks associated with an individual -change that happened recently. -` - type cmdChanges struct { clientMixin timeMixin @@ -49,19 +39,23 @@ type cmdTasks struct { func init() { AddCommand(&CmdInfo{ - Name: "changes", - Summary: shortChangesHelp, - Description: longChangesHelp, - Builder: func() flags.Commander { return &cmdChanges{} }, - OptionsHelp: timeOptionsHelp, + Name: "changes", + Summary: "List system changes", + Description: ` +The changes command displays a summary of system changes performed recently. +`, + ArgsHelp: timeArgsHelp, + Builder: func() flags.Commander { return &cmdChanges{} }, }) AddCommand(&CmdInfo{ - Name: "tasks", - Summary: shortTasksHelp, - Description: longTasksHelp, - Builder: func() flags.Commander { return &cmdTasks{} }, - OptionsHelp: merge(changeIDMixinOptionsHelp, timeOptionsHelp), - ArgumentsHelp: changeIDMixinArgumentsHelp, + Name: "tasks", + Summary: "List a change's tasks", + Description: ` +The tasks command displays a summary of tasks associated with an individual +change that happened recently. +`, + ArgsHelp: merge(changeIDMixinArgsHelp, timeArgsHelp), + Builder: func() flags.Commander { return &cmdTasks{} }, }) } diff --git a/internals/cli/cmd_checks.go b/internals/cli/cmd_checks.go index c23fcd96..7fe041b9 100644 --- a/internals/cli/cmd_checks.go +++ b/internals/cli/cmd_checks.go @@ -18,7 +18,6 @@ import ( "fmt" "github.com/canonical/go-flags" - "github.com/canonical/pebble/client" ) @@ -30,16 +29,21 @@ type cmdChecks struct { } `positional-args:"yes"` } -var checksOptionsHelp = map[string]string{ - "level": `Check level to filter for ("alive" or "ready")`, -} - -var shortChecksHelp = "Query the status of configured health checks" -var longChecksHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "checks", + Summary: "Query the status of configured health checks", + Description: ` The checks command lists status information about the configured health checks, optionally filtered by level and check names provided as positional arguments. -` +`, + ArgsHelp: map[string]string{ + "--level": `Check level to filter for ("alive" or "ready")`, + }, + Builder: func() flags.Commander { return &cmdChecks{} }, + }) +} func (cmd *cmdChecks) Execute(args []string) error { if len(args) > 0 { @@ -77,13 +81,3 @@ func (cmd *cmdChecks) Execute(args []string) error { } return nil } - -func init() { - AddCommand(&CmdInfo{ - Name: "checks", - Summary: shortChecksHelp, - Description: longChecksHelp, - Builder: func() flags.Commander { return &cmdChecks{} }, - OptionsHelp: checksOptionsHelp, - }) -} diff --git a/internals/cli/cmd_debug.go b/internals/cli/cmd_debug.go deleted file mode 100644 index 201a0a1e..00000000 --- a/internals/cli/cmd_debug.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2014-2020 Canonical Ltd -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 3 as -// published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -package cli - -type cmdDebug struct{} - -var shortDebugHelp = "Run debug commands" -var longDebugHelp = ` -The debug command contains a selection of additional sub-commands. - -Debug commands can be removed without notice and may not work on -non-development systems. -` diff --git a/internals/cli/cmd_enter.go b/internals/cli/cmd_enter.go index 7eae08c6..7280a4a8 100644 --- a/internals/cli/cmd_enter.go +++ b/internals/cli/cmd_enter.go @@ -8,8 +8,21 @@ import ( "github.com/canonical/pebble/internals/logger" ) -const shortEnterHelp = "Run subcommand under a container environment" -const longEnterHelp = ` +type cmdEnter struct { + clientMixin + sharedRunEnterOpts + Run bool `long:"run"` + Positional struct { + Cmd []string `positional-arg-name:""` + } `positional-args:"yes"` + parser *flags.Parser +} + +func init() { + AddCommand(&CmdInfo{ + Name: "enter", + Summary: "Run subcommand under a container environment", + Description: ` The enter command facilitates the use of Pebble as an entrypoint for containers. When used without a subcommand it mimics the behavior of the run command alone, while if used with a subcommand it runs that subcommand in the most @@ -29,7 +42,14 @@ These subcommands are currently supported: (1) Services are not started. (2) No logs on stdout unless -v is used. (3) Services continue running after the subcommand succeeds. -` +`, + Builder: func() flags.Commander { return &cmdEnter{} }, + ArgsHelp: merge(sharedRunEnterArgsHelp, map[string]string{ + "--run": "Start default services before executing subcommand", + }), + PassAfterNonOption: true, + }) +} type enterFlags int @@ -41,33 +61,6 @@ const ( enterProhibitServiceAutostart ) -type cmdEnter struct { - clientMixin - sharedRunEnterOpts - Run bool `long:"run"` - Positional struct { - Cmd []string `positional-arg-name:""` - } `positional-args:"yes"` - parser *flags.Parser -} - -func init() { - optsHelp := map[string]string{ - "run": "Start default services before executing subcommand", - } - for k, v := range sharedRunEnterOptsHelp { - optsHelp[k] = v - } - AddCommand(&CmdInfo{ - Name: "enter", - Summary: shortEnterHelp, - Description: longEnterHelp, - Builder: func() flags.Commander { return &cmdEnter{} }, - OptionsHelp: optsHelp, - PassAfterNonOption: true, - }) -} - func commandEnterFlags(commander flags.Commander) (enterFlags enterFlags, supported bool) { supported = true switch commander.(type) { diff --git a/internals/cli/cmd_exec.go b/internals/cli/cmd_exec.go index 494293c3..3a3821a2 100644 --- a/internals/cli/cmd_exec.go +++ b/internals/cli/cmd_exec.go @@ -22,9 +22,9 @@ import ( "strings" "time" - "github.com/canonical/go-flags" "golang.org/x/sys/unix" + "github.com/canonical/go-flags" "github.com/canonical/pebble/client" "github.com/canonical/pebble/internals/logger" "github.com/canonical/pebble/internals/ptyutil" @@ -48,22 +48,11 @@ type cmdExec struct { } `positional-args:"yes"` } -var execOptionsHelp = map[string]string{ - "w": "Working directory to run command in", - "env": "Environment variable to set (in 'FOO=bar' format)", - "uid": "User ID to run command as", - "user": "Username to run command as (user's UID must match uid if both present)", - "gid": "Group ID to run command as", - "group": "Group name to run command as (group's GID must match gid if both present)", - "timeout": "Timeout after which to terminate command", - "t": "Allocate remote pseudo-terminal and connect stdout to it (default if stdout is a TTY)", - "T": "Disable remote pseudo-terminal allocation", - "i": "Interactive mode: connect stdin to the pseudo-terminal (default if stdin and stdout are TTYs)", - "I": "Disable interactive mode and use a pipe for stdin", -} - -var shortExecHelp = "Execute a remote command and wait for it to finish" -var longExecHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "exec", + Summary: "Execute a remote command and wait for it to finish", + Description: ` The exec command runs a remote command and waits for it to finish. The local stdin is sent as the input to the remote process, while the remote stdout and stderr are output locally. @@ -72,7 +61,24 @@ To avoid confusion, exec options may be separated from the command and its arguments using "--", for example: pebble exec --timeout 10s -- echo -n foo bar -` +`, + ArgsHelp: map[string]string{ + "-w": "Working directory to run command in", + "--env": "Environment variable to set (in 'FOO=bar' format)", + "--uid": "User ID to run command as", + "--user": "Username to run command as (user's UID must match uid if both present)", + "--gid": "Group ID to run command as", + "--group": "Group name to run command as (group's GID must match gid if both present)", + "--timeout": "Timeout after which to terminate command", + "-t": "Allocate remote pseudo-terminal and connect stdout to it (default if stdout is a TTY)", + "-T": "Disable remote pseudo-terminal allocation", + "-i": "Interactive mode: connect stdin to the pseudo-terminal (default if stdin and stdout are TTYs)", + "-I": "Disable interactive mode and use a pipe for stdin", + }, + PassAfterNonOption: true, + Builder: func() flags.Commander { return &cmdExec{} }, + }) +} func (cmd *cmdExec) Execute(args []string) error { if cmd.Terminal && cmd.NoTerminal { @@ -262,14 +268,3 @@ func execControlHandler(process *client.ExecProcess, terminal bool, stop <-chan } } } - -func init() { - AddCommand(&CmdInfo{ - Name: "exec", - Summary: shortExecHelp, - Description: longExecHelp, - Builder: func() flags.Commander { return &cmdExec{} }, - OptionsHelp: execOptionsHelp, - PassAfterNonOption: true, - }) -} diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index 80d8b41e..c35fa0f0 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -25,10 +25,29 @@ import ( "github.com/canonical/go-flags" ) -var shortHelpHelp = "Show help about a command" -var longHelpHelp = ` +type cmdHelp struct { + All bool `long:"all"` + Manpage bool `long:"man" hidden:"true"` + Positional struct { + Subs []string `positional-arg-name:""` + } `positional-args:"yes"` + parser *flags.Parser +} + +func init() { + AddCommand(&CmdInfo{ + Name: "help", + Summary: "Show help about a command", + Description: ` The help command displays information about commands. -` +`, + ArgsHelp: map[string]string{ + "--all": "Show a short summary of all commands", + "--man": "Generate the manpage", + }, + Builder: func() flags.Commander { return &cmdHelp{} }, + }) +} // addHelp adds --help like what go-flags would do for us, but hidden func addHelp(parser *flags.Parser) error { @@ -69,28 +88,6 @@ func addHelp(parser *flags.Parser) error { return nil } -type cmdHelp struct { - All bool `long:"all"` - Manpage bool `long:"man" hidden:"true"` - Positional struct { - Subs []string `positional-arg-name:""` - } `positional-args:"yes"` - parser *flags.Parser -} - -func init() { - AddCommand(&CmdInfo{ - Name: "help", - Summary: shortHelpHelp, - Description: longHelpHelp, - Builder: func() flags.Commander { return &cmdHelp{} }, - OptionsHelp: map[string]string{ - "all": "Show a short summary of all commands", - "man": "Generate the manpage", - }, - }) -} - func (cmd *cmdHelp) setParser(parser *flags.Parser) { cmd.parser = parser } diff --git a/internals/cli/cmd_logs.go b/internals/cli/cmd_logs.go index 80ebf2ed..ca914eb0 100644 --- a/internals/cli/cmd_logs.go +++ b/internals/cli/cmd_logs.go @@ -23,14 +23,9 @@ import ( "strconv" "github.com/canonical/go-flags" - "github.com/canonical/pebble/client" ) -const ( - logTimeFormat = "2006-01-02T15:04:05.000Z07:00" -) - type cmdLogs struct { clientMixin Follow bool `short:"f" long:"follow"` @@ -41,17 +36,26 @@ type cmdLogs struct { } `positional-args:"yes"` } -var logsOptionsHelp = map[string]string{ - "follow": "Follow (tail) logs for given services until Ctrl-C is\npressed. If no services are specified, show logs from\nall services running when the command starts.", - "format": "Output format: \"text\" (default) or \"json\" (JSON lines).", - "n": "Number of logs to show (before following); defaults to 30.\nIf 'all', show all buffered logs.", -} - -var shortLogsHelp = "Fetch service logs" -var longLogsHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "logs", + Summary: "Fetch service logs", + Description: ` The logs command fetches buffered logs from the given services (or all services if none are specified) and displays them in chronological order. -` +`, + ArgsHelp: map[string]string{ + "--follow": "Follow (tail) logs for given services until Ctrl-C is\npressed. If no services are specified, show logs from\nall services running when the command starts.", + "--format": "Output format: \"text\" (default) or \"json\" (JSON lines).", + "-n": "Number of logs to show (before following); defaults to 30.\nIf 'all', show all buffered logs.", + }, + Builder: func() flags.Commander { return &cmdLogs{} }, + }) +} + +const ( + logTimeFormat = "2006-01-02T15:04:05.000Z07:00" +) func (cmd *cmdLogs) Execute(args []string) error { var n int @@ -119,13 +123,3 @@ func notifyContext(parent context.Context, signals ...os.Signal) context.Context }() return ctx } - -func init() { - AddCommand(&CmdInfo{ - Name: "logs", - Summary: shortLogsHelp, - Description: longLogsHelp, - Builder: func() flags.Commander { return &cmdLogs{} }, - OptionsHelp: logsOptionsHelp, - }) -} diff --git a/internals/cli/cmd_ls.go b/internals/cli/cmd_ls.go index 6b21c322..99acc3a2 100644 --- a/internals/cli/cmd_ls.go +++ b/internals/cli/cmd_ls.go @@ -38,16 +38,21 @@ type cmdLs struct { } `positional-args:"yes" required:"yes"` } -var lsOptionsHelp = map[string]string{ - "d": `List matching entries themselves, not directory contents`, - "l": `Use a long listing format`, -} - -var shortLsHelp = "List path contents" -var longLsHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "ls", + Summary: "List path contents", + Description: ` The ls command lists entries in the filesystem at the specified path. A glob pattern may be specified for the last path element. -` +`, + ArgsHelp: merge(timeArgsHelp, map[string]string{ + "-d": "List matching entries themselves, not directory contents", + "-l": "Use a long listing format", + }), + Builder: func() flags.Commander { return &cmdLs{} }, + }) +} func (cmd *cmdLs) Execute(args []string) error { if len(args) > 0 { @@ -101,13 +106,3 @@ func parseGlob(path string) (parsedPath, parsedPattern string, err error) { return path, "", nil } - -func init() { - AddCommand(&CmdInfo{ - Name: "ls", - Summary: shortLsHelp, - Description: longLsHelp, - Builder: func() flags.Commander { return &cmdLs{} }, - OptionsHelp: merge(lsOptionsHelp, timeOptionsHelp), - }) -} diff --git a/internals/cli/cmd_mkdir.go b/internals/cli/cmd_mkdir.go index c5b233aa..232dd65c 100644 --- a/internals/cli/cmd_mkdir.go +++ b/internals/cli/cmd_mkdir.go @@ -39,19 +39,24 @@ type cmdMkdir struct { } `positional-args:"yes" required:"yes"` } -var mkdirOptionsHelp = map[string]string{ - "p": "Create parent directories as needed", - "m": "Set permissions (e.g. 0644)", - "uid": "Use specified user ID", - "user": "Use specified username", - "gid": "Use specified group ID", - "group": "Use specified group name", -} - -var shortMkdirHelp = "Create a directory" -var longMkdirHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "mkdir", + Summary: "Create a directory", + Description: ` The mkdir command creates the specified directory. -` +`, + Builder: func() flags.Commander { return &cmdMkdir{} }, + ArgsHelp: map[string]string{ + "-p": "Create parent directories as needed", + "-m": "Set permissions (e.g. 0644)", + "--uid": "Use specified user ID", + "--user": "Use specified username", + "--gid": "Use specified group ID", + "--group": "Use specified group name", + }, + }) +} func (cmd *cmdMkdir) Execute(args []string) error { if len(args) > 0 { @@ -77,13 +82,3 @@ func (cmd *cmdMkdir) Execute(args []string) error { return cmd.client.MakeDir(&opts) } - -func init() { - AddCommand(&CmdInfo{ - Name: "mkdir", - Summary: shortMkdirHelp, - Description: longMkdirHelp, - Builder: func() flags.Commander { return &cmdMkdir{} }, - OptionsHelp: mkdirOptionsHelp, - }) -} diff --git a/internals/cli/cmd_replan.go b/internals/cli/cmd_replan.go index f4837048..c16e6bec 100644 --- a/internals/cli/cmd_replan.go +++ b/internals/cli/cmd_replan.go @@ -20,24 +20,21 @@ import ( "github.com/canonical/pebble/client" ) -var shortReplanHelp = "Ensure running services match the current plan" -var longReplanHelp = ` -The replan command starts, stops, or restarts services that have changed, -so that running services exactly match the desired configuration in the -current plan. -` - type cmdReplan struct { waitMixin } func init() { AddCommand(&CmdInfo{ - Name: "replan", - Summary: shortReplanHelp, - Description: longReplanHelp, - Builder: func() flags.Commander { return &cmdReplan{} }, - OptionsHelp: waitOptionsHelp, + Name: "replan", + Summary: "Ensure running services match the current plan", + Description: ` +The replan command starts, stops, or restarts services that have changed, +so that running services exactly match the desired configuration in the +current plan. +`, + ArgsHelp: waitArgsHelp, + Builder: func() flags.Commander { return &cmdReplan{} }, }) } diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index b65e61a8..62f4a09f 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -16,15 +16,9 @@ package cli import ( "github.com/canonical/go-flags" - "github.com/canonical/pebble/client" ) -var shortRestartHelp = "Restart a service" -var longRestartHelp = ` -The restart command restarts the named service(s) in the correct order. -` - type cmdRestart struct { waitMixin Positional struct { @@ -34,11 +28,13 @@ type cmdRestart struct { func init() { AddCommand(&CmdInfo{ - Name: "restart", - Summary: shortRestartHelp, - Description: longRestartHelp, - Builder: func() flags.Commander { return &cmdRestart{} }, - OptionsHelp: waitOptionsHelp, + Name: "restart", + Summary: "Restart a service", + Description: ` +The restart command restarts the named service(s) in the correct order. +`, + ArgsHelp: waitArgsHelp, + Builder: func() flags.Commander { return &cmdRestart{} }, }) } diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index 3d90d388..d5d10202 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -16,28 +16,30 @@ package cli import ( "github.com/canonical/go-flags" - "github.com/canonical/pebble/client" ) type cmdRm struct { clientMixin - - Recursive bool `short:"r"` - + Recursive bool `short:"r"` Positional struct { Path string `positional-arg-name:""` } `positional-args:"yes" required:"yes"` } -var rmOptionsHelp = map[string]string{ - "r": "Remove all files and directories recursively in the specified path", -} - -var shortRmHelp = "Remove a file or directory." -var longRmHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "rm", + Summary: "Remove a file or directory", + Description: ` The rm command removes a file or directory. -` +`, + ArgsHelp: map[string]string{ + "-r": "Remove all files and directories recursively in the specified path", + }, + Builder: func() flags.Commander { return &cmdRm{} }, + }) +} func (cmd *cmdRm) Execute(args []string) error { if len(args) > 0 { @@ -49,13 +51,3 @@ func (cmd *cmdRm) Execute(args []string) error { Recursive: cmd.Recursive, }) } - -func init() { - AddCommand(&CmdInfo{ - Name: "rm", - Summary: shortRmHelp, - Description: longRmHelp, - Builder: func() flags.Commander { return &cmdRm{} }, - OptionsHelp: rmOptionsHelp, - }) -} diff --git a/internals/cli/cmd_run.go b/internals/cli/cmd_run.go index 78381099..6ad46899 100644 --- a/internals/cli/cmd_run.go +++ b/internals/cli/cmd_run.go @@ -31,18 +31,6 @@ import ( "github.com/canonical/pebble/internals/systemd" ) -var shortRunHelp = "Run the pebble environment" -var longRunHelp = ` -The run command starts pebble and runs the configured environment. - -Additional arguments may be provided to the service command with the --args option, which -must be terminated with ";" unless there are no further Pebble options. These arguments -are appended to the end of the service command, and replace any default arguments defined -in the service plan. For example: - - $ pebble run --args myservice --port 8080 \; --hold -` - type sharedRunEnterOpts struct { CreateDirs bool `long:"create-dirs"` Hold bool `long:"hold"` @@ -51,12 +39,12 @@ type sharedRunEnterOpts struct { Args [][]string `long:"args" terminator:";"` } -var sharedRunEnterOptsHelp = map[string]string{ - "create-dirs": "Create pebble directory on startup if it doesn't exist", - "hold": "Do not start default services automatically", - "http": `Start HTTP API listening on this address (e.g., ":4000")`, - "verbose": "Log all output from services to stdout", - "args": `Provide additional arguments to a service`, +var sharedRunEnterArgsHelp = map[string]string{ + "--create-dirs": "Create pebble directory on startup if it doesn't exist", + "--hold": "Do not start default services automatically", + "--http": `Start HTTP API listening on this address (e.g., ":4000")`, + "--verbose": "Log all output from services to stdout", + "--args": `Provide additional arguments to a service`, } type cmdRun struct { @@ -66,11 +54,20 @@ type cmdRun struct { func init() { AddCommand(&CmdInfo{ - Name: "run", - Summary: shortRunHelp, - Description: longRunHelp, - Builder: func() flags.Commander { return &cmdRun{} }, - OptionsHelp: sharedRunEnterOptsHelp, + Name: "run", + Summary: "Run the pebble environment", + Description: ` +The run command starts pebble and runs the configured environment. + +Additional arguments may be provided to the service command with the --args option, which +must be terminated with ";" unless there are no further Pebble options. These arguments +are appended to the end of the service command, and replace any default arguments defined +in the service plan. For example: + + $ pebble run --args myservice --port 8080 \; --hold +`, + ArgsHelp: sharedRunEnterArgsHelp, + Builder: func() flags.Commander { return &cmdRun{} }, }) } diff --git a/internals/cli/cmd_services.go b/internals/cli/cmd_services.go index 37e597d2..57c23234 100644 --- a/internals/cli/cmd_services.go +++ b/internals/cli/cmd_services.go @@ -18,7 +18,6 @@ import ( "fmt" "github.com/canonical/go-flags" - "github.com/canonical/pebble/client" ) @@ -30,11 +29,18 @@ type cmdServices struct { } `positional-args:"yes"` } -var shortServicesHelp = "Query the status of configured services" -var longServicesHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "services", + Summary: "Query the status of configured services", + Description: ` The services command lists status information about the services specified, or about all services if none are specified. -` +`, + ArgsHelp: timeArgsHelp, + Builder: func() flags.Commander { return &cmdServices{} }, + }) +} func (cmd *cmdServices) Execute(args []string) error { if len(args) > 0 { @@ -71,13 +77,3 @@ func (cmd *cmdServices) Execute(args []string) error { } return nil } - -func init() { - AddCommand(&CmdInfo{ - Name: "services", - Summary: shortServicesHelp, - Description: longServicesHelp, - Builder: func() flags.Commander { return &cmdServices{} }, - OptionsHelp: timeOptionsHelp, - }) -} diff --git a/internals/cli/cmd_signal.go b/internals/cli/cmd_signal.go index 76b8a7ea..558d496d 100644 --- a/internals/cli/cmd_signal.go +++ b/internals/cli/cmd_signal.go @@ -19,7 +19,6 @@ import ( "strings" "github.com/canonical/go-flags" - "github.com/canonical/pebble/client" ) @@ -31,13 +30,19 @@ type cmdSignal struct { } `positional-args:"yes" required:"yes"` } -var shortSignalHelp = "Send a signal to one or more running services" -var longSignalHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "signal", + Summary: "Send a signal to one or more running services", + Description: ` The signal command sends a signal to one or more running services. The signal name must be uppercase, for example: pebble signal HUP mysql nginx -` +`, + Builder: func() flags.Commander { return &cmdSignal{} }, + }) +} func (cmd *cmdSignal) Execute(args []string) error { if strings.ToUpper(cmd.Positional.Signal) != cmd.Positional.Signal { @@ -56,12 +61,3 @@ func (cmd *cmdSignal) Execute(args []string) error { } return nil } - -func init() { - AddCommand(&CmdInfo{ - Name: "signal", - Summary: shortSignalHelp, - Description: longSignalHelp, - Builder: func() flags.Commander { return &cmdSignal{} }, - }) -} diff --git a/internals/cli/cmd_start.go b/internals/cli/cmd_start.go index 143da204..82fc0f75 100644 --- a/internals/cli/cmd_start.go +++ b/internals/cli/cmd_start.go @@ -20,12 +20,6 @@ import ( "github.com/canonical/pebble/client" ) -var shortStartHelp = "Start a service and its dependencies" -var longStartHelp = ` -The start command starts the service with the provided name and -any other services it depends on, in the correct order. -` - type cmdStart struct { waitMixin Positional struct { @@ -35,11 +29,14 @@ type cmdStart struct { func init() { AddCommand(&CmdInfo{ - Name: "start", - Summary: shortStartHelp, - Description: longStartHelp, - Builder: func() flags.Commander { return &cmdStart{} }, - OptionsHelp: waitOptionsHelp, + Name: "start", + Summary: "Start a service and its dependencies", + Description: ` +The start command starts the service with the provided name and +any other services it depends on, in the correct order. +`, + ArgsHelp: waitArgsHelp, + Builder: func() flags.Commander { return &cmdStart{} }, }) } diff --git a/internals/cli/cmd_stop.go b/internals/cli/cmd_stop.go index 1c378fe3..60626984 100644 --- a/internals/cli/cmd_stop.go +++ b/internals/cli/cmd_stop.go @@ -20,12 +20,6 @@ import ( "github.com/canonical/pebble/client" ) -var shortStopHelp = "Stop a service and its dependents" -var longStopHelp = ` -The stop command stops the service with the provided name and -any other service that depends on it, in the correct order. -` - type cmdStop struct { waitMixin Positional struct { @@ -35,11 +29,14 @@ type cmdStop struct { func init() { AddCommand(&CmdInfo{ - Name: "stop", - Summary: shortStopHelp, - Description: longStopHelp, - Builder: func() flags.Commander { return &cmdStop{} }, - OptionsHelp: waitOptionsHelp, + Name: "stop", + Summary: "Stop a service and its dependents", + Description: ` +The stop command stops the service with the provided name and +any other service that depends on it, in the correct order. +`, + Builder: func() flags.Commander { return &cmdStop{} }, + ArgsHelp: waitArgsHelp, }) } diff --git a/internals/cli/cmd_version.go b/internals/cli/cmd_version.go index c49c100d..f69fa654 100644 --- a/internals/cli/cmd_version.go +++ b/internals/cli/cmd_version.go @@ -20,30 +20,25 @@ import ( "github.com/canonical/go-flags" "github.com/canonical/pebble/client" - cmdpkg "github.com/canonical/pebble/cmd" + version "github.com/canonical/pebble/cmd" ) -var shortVersionHelp = "Show version details" -var longVersionHelp = ` -The version command displays the versions of the running client and server. -` - type cmdVersion struct { clientMixin ClientOnly bool `long:"client"` } -var versionOptionsHelp = map[string]string{ - "client": `Only display the client version`, -} - func init() { AddCommand(&CmdInfo{ - Name: "version", - Summary: shortVersionHelp, - Description: longVersionHelp, - Builder: func() flags.Commander { return &cmdVersion{} }, - OptionsHelp: versionOptionsHelp, + Name: "version", + Summary: "Show version details", + Description: ` +The version command displays the versions of the running client and server. +`, + ArgsHelp: map[string]string{ + "--client": "Only display the client version", + }, + Builder: func() flags.Commander { return &cmdVersion{} }, }) } @@ -53,7 +48,7 @@ func (cmd cmdVersion) Execute(args []string) error { } if cmd.ClientOnly { - fmt.Fprintln(Stdout, cmdpkg.Version) + fmt.Fprintln(Stdout, version.Version) return nil } @@ -67,7 +62,7 @@ func printVersions(cli *client.Client) error { serverVersion = sysInfo.Version } w := tabWriter() - fmt.Fprintf(w, "client\t%s\n", cmdpkg.Version) + fmt.Fprintf(w, "client\t%s\n", version.Version) fmt.Fprintf(w, "server\t%s\n", serverVersion) w.Flush() return nil diff --git a/internals/cli/cmd_warnings.go b/internals/cli/cmd_warnings.go index d871f5f9..a327526a 100644 --- a/internals/cli/cmd_warnings.go +++ b/internals/cli/cmd_warnings.go @@ -41,8 +41,11 @@ type cmdWarnings struct { type cmdOkay struct{ clientMixin } -var shortWarningsHelp = "List warnings" -var longWarningsHelp = ` +func init() { + AddCommand(&CmdInfo{ + Name: "warnings", + Summary: "List warnings", + Description: ` The warnings command lists the warnings that have been reported to the system. Once warnings have been listed with 'pebble warnings', 'pebble okay' may be used to @@ -50,32 +53,23 @@ silence them. A warning that's been silenced in this way will not be listed again unless it happens again, _and_ a cooldown time has passed. Warnings expire automatically, and once expired they are forgotten. -` - -var shortOkayHelp = "Acknowledge warnings" -var longOkayHelp = ` +`, + ArgsHelp: merge(timeArgsHelp, unicodeArgsHelp, map[string]string{ + "--all": "Show all warnings", + "--verbose": "Show more information", + }), + Builder: func() flags.Commander { return &cmdWarnings{} }, + }) + AddCommand(&CmdInfo{ + Name: "okay", + Summary: "Acknowledge warnings", + Description: ` The okay command acknowledges the warnings listed with 'pebble warnings'. Once acknowledged, a warning won't appear again unless it reoccurs and sufficient time has passed. -` - -func init() { - AddCommand(&CmdInfo{ - Name: "warnings", - Summary: shortWarningsHelp, - Description: longWarningsHelp, - Builder: func() flags.Commander { return &cmdWarnings{} }, - OptionsHelp: merge(timeOptionsHelp, unicodeOptionsHelp, map[string]string{ - "all": "Show all warnings", - "verbose": "Show more information", - }), - }) - AddCommand(&CmdInfo{ - Name: "okay", - Summary: shortOkayHelp, - Description: longOkayHelp, - Builder: func() flags.Commander { return &cmdOkay{} }, +`, + Builder: func() flags.Commander { return &cmdOkay{} }, }) } diff --git a/internals/cli/format.go b/internals/cli/format.go index 4dc55436..fa8de12f 100644 --- a/internals/cli/format.go +++ b/internals/cli/format.go @@ -111,13 +111,8 @@ func colorTable(mode string) escapes { return color } -var colorOptionsHelp = map[string]string{ - "color": "Use a little bit of color to highlight some things.", - "unicode": unicodeOptionsHelp["unicode"], -} - -var unicodeOptionsHelp = map[string]string{ - "unicode": "Use a little bit of Unicode to improve legibility.", +var unicodeArgsHelp = map[string]string{ + "--unicode": "Use a little bit of Unicode to improve legibility.", } func merge(maps ...map[string]string) map[string]string { diff --git a/internals/cli/last.go b/internals/cli/last.go index 36d7cc0a..deafc9a3 100644 --- a/internals/cli/last.go +++ b/internals/cli/last.go @@ -25,35 +25,29 @@ type changeIDMixin struct { clientMixin LastChangeType string `long:"last"` Positional struct { - ID string `positional-arg-name:""` + ChangeID string `positional-arg-name:""` } `positional-args:"yes"` } -var changeIDMixinOptionsHelp = map[string]string{ - "last": "Select last change of given type (install, refresh, remove, try, auto-refresh, etc.). A question mark at the end of the type means to do nothing (instead of returning an error) if no change of the given type is found. Note the question mark could need protecting from the shell.", -} - -var changeIDMixinArgumentsHelp = map[string]ArgumentHelp{ - "": ArgumentHelp{ - Placeholder: "", - Help: "Change ID", - }, +var changeIDMixinArgsHelp = map[string]string{ + "": "Change ID", + "--last": "Select last change of given type (install, refresh, remove, try, auto-refresh, etc.). A question mark at the end of the type means to do nothing (instead of returning an error) if no change of the given type is found. Note the question mark could need protecting from the shell.", } // should not be user-visible, but keep it clear and polite because mistakes happen var noChangeFoundOK = errors.New("no change found but that's ok") func (l *changeIDMixin) GetChangeID() (string, error) { - if l.Positional.ID == "" && l.LastChangeType == "" { + if l.Positional.ChangeID == "" && l.LastChangeType == "" { return "", fmt.Errorf("please provide change ID or type with --last=") } - if l.Positional.ID != "" { + if l.Positional.ChangeID != "" { if l.LastChangeType != "" { return "", fmt.Errorf("cannot use change ID and type together") } - return string(l.Positional.ID), nil + return string(l.Positional.ChangeID), nil } cli := l.client diff --git a/internals/cli/times.go b/internals/cli/times.go index 9f81ec32..a96a193d 100644 --- a/internals/cli/times.go +++ b/internals/cli/times.go @@ -29,8 +29,8 @@ type timeMixin struct { AbsTime bool `long:"abs-time"` } -var timeOptionsHelp = map[string]string{ - "abs-time": "Display absolute times (in RFC 3339 format). Otherwise, display relative times up to 60 days, then YYYY-MM-DD.", +var timeArgsHelp = map[string]string{ + "--abs-time": "Display absolute times (in RFC 3339 format). Otherwise, display relative times up to 60 days, then YYYY-MM-DD.", } func (mx timeMixin) fmtTime(t time.Time) string { diff --git a/internals/cli/wait.go b/internals/cli/wait.go index 05cea01c..750bfce3 100644 --- a/internals/cli/wait.go +++ b/internals/cli/wait.go @@ -36,8 +36,8 @@ type waitMixin struct { skipAbort bool } -var waitOptionsHelp = map[string]string{ - "no-wait": "Do not wait for the operation to finish but just print the change id.", +var waitArgsHelp = map[string]string{ + "--no-wait": "Do not wait for the operation to finish but just print the change id.", } var noWait = errors.New("no wait for op") From d9d63d1f69cb1122c8611853ee6ff76dc3aede70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Mon, 26 Jun 2023 02:17:57 +0200 Subject: [PATCH 10/19] cli: minor changes --- internals/cli/cli.go | 11 ++++++----- internals/cli/times.go | 18 ------------------ 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 6925ab1f..4ddbbca0 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -52,7 +52,7 @@ const defaultPebbleDir = "/var/lib/pebble/default" // ArgumentHelp contains help information about the positional arguments accepted // by a command. type ArgumentHelp struct { - // Placeholer supplies a string representation of the argument. + // Placeholder supplies a string representation of the argument. Placeholder string // Help provides information on how to use the argument. Help string @@ -84,7 +84,7 @@ type CmdInfo struct { // (including options) supported by the command. // // map[string]string{ - // "--long-option": "my very long option", + // "--long-option": "my very long option", // "-v": "verbose output", // "": "named positional argument" // } @@ -212,11 +212,12 @@ func Parser(cli *client.Client) *flags.Parser { positionalArgsHelp := map[string]string{} for specifier, help := range c.ArgsHelp { - if strings.HasPrefix(specifier, "--") { - optionsHelp[specifier] = help - } else if utf8.RuneCountInString(specifier) == 2 && strings.HasPrefix(specifier, "-") { + isLongOption := strings.HasPrefix(specifier, "--") + isShortOption := utf8.RuneCountInString(specifier) == 2 && strings.HasPrefix(specifier, "-") + if isShortOption || isLongOption { optionsHelp[specifier] = help } else if strings.HasPrefix(specifier, "<") && strings.HasSuffix(specifier, ">") { + // This is a positional argument positionalArgsHelp[specifier] = help } else { logger.Panicf("invalid help specifier: %#v %#v", c.Name, strings.HasPrefix(specifier, "-")) diff --git a/internals/cli/times.go b/internals/cli/times.go index a96a193d..ddade772 100644 --- a/internals/cli/times.go +++ b/internals/cli/times.go @@ -15,11 +15,8 @@ package cli import ( - "strings" "time" - "github.com/canonical/x-go/strutil/quantity" - "github.com/canonical/pebble/internals/timeutil" ) @@ -39,18 +36,3 @@ func (mx timeMixin) fmtTime(t time.Time) string { } return timeutilHuman(t) } - -type durationMixin struct { - AbsTime bool `long:"abs-time"` -} - -var durationOptionsHelp = map[string]string{ - "abs-time": "Display absolute times (in RFC 3339 format). Otherwise, display short relative times.", -} - -func (mx durationMixin) fmtDuration(t time.Time) string { - if mx.AbsTime { - return t.Format(time.RFC3339) - } - return strings.TrimSpace(quantity.FormatDuration(time.Since(t).Seconds())) -} From bc316ad42671cb85285707989fddb666c828fda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Wed, 28 Jun 2023 09:58:34 +0200 Subject: [PATCH 11/19] cli: minor fixes * Strip some dead code * Minor corrections to keep staticcheck happy. --- internals/cli/cli.go | 19 +++++-------------- internals/cli/cmd_enter_test.go | 2 +- internals/cli/format.go | 21 ++------------------- 3 files changed, 8 insertions(+), 34 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 4ddbbca0..db3a4c30 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -27,7 +27,7 @@ import ( "github.com/canonical/go-flags" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" "github.com/canonical/pebble/client" "github.com/canonical/pebble/internals/logger" @@ -39,7 +39,7 @@ var ( Stdout io.Writer = os.Stdout Stderr io.Writer = os.Stderr // overridden for testing - ReadPassword = terminal.ReadPassword + ReadPassword = term.ReadPassword // set to logger.Panicf in testing noticef = logger.Noticef ) @@ -49,15 +49,6 @@ var ( // the pebble client. const defaultPebbleDir = "/var/lib/pebble/default" -// ArgumentHelp contains help information about the positional arguments accepted -// by a command. -type ArgumentHelp struct { - // Placeholder supplies a string representation of the argument. - Placeholder string - // Help provides information on how to use the argument. - Help string -} - // ErrExtraArgs is returned if extra arguments to a command are found var ErrExtraArgs = fmt.Errorf("too many arguments for command") @@ -264,8 +255,8 @@ func Parser(cli *client.Client) *flags.Parser { } var ( - isStdinTTY = terminal.IsTerminal(0) - isStdoutTTY = terminal.IsTerminal(1) + isStdinTTY = term.IsTerminal(0) + isStdoutTTY = term.IsTerminal(1) osExit = os.Exit ) @@ -323,7 +314,7 @@ func Run() error { sug = "pebble help " + x.Name } } - return fmt.Errorf("unknown command %q, see '%s'.", sub, sug) + return fmt.Errorf("unknown command %q, see '%s'", sub, sug) } } diff --git a/internals/cli/cmd_enter_test.go b/internals/cli/cmd_enter_test.go index efcb76c5..c4161d01 100644 --- a/internals/cli/cmd_enter_test.go +++ b/internals/cli/cmd_enter_test.go @@ -99,7 +99,7 @@ func (s *PebbleSuite) TestEnterUnknownCommand(c *C) { defer restore() exitCode := cli.PebbleMain() - c.Check(s.Stderr(), Equals, "error: unknown command \"foo\", see 'pebble help'.\n") + c.Check(s.Stderr(), Equals, "error: unknown command \"foo\", see 'pebble help'\n") c.Check(s.Stdout(), Equals, "") c.Check(exitCode, Equals, 1) } diff --git a/internals/cli/format.go b/internals/cli/format.go index fa8de12f..7be5349b 100644 --- a/internals/cli/format.go +++ b/internals/cli/format.go @@ -26,7 +26,7 @@ import ( "unicode" "unicode/utf8" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) type unicodeMixin struct { @@ -51,17 +51,6 @@ func (ux unicodeMixin) getEscapes() *escapes { return esc } -type colorMixin struct { - Color string `long:"color" default:"auto" choice:"auto" choice:"never" choice:"always"` - unicodeMixin -} - -func (mx colorMixin) getEscapes() *escapes { - esc := colorTable(mx.Color) - mx.addUnicodeChars(&esc) - return &esc -} - func canUnicode(mode string) bool { switch mode { case "always": @@ -161,7 +150,7 @@ var termSize = termSizeImpl func termSizeImpl() (width, height int) { if f, ok := Stdout.(*os.File); ok { - width, height, _ = terminal.GetSize(int(f.Fd())) + width, height, _ = term.GetSize(int(f.Fd())) } if width <= 0 { @@ -247,12 +236,6 @@ func wrapLine(out io.Writer, text []rune, pad string, termWidth int) error { return wrapGeneric(out, text, indent, indent, termWidth) } -// wrapFlow wraps the text using yaml's flow style, allowing indent -// characters for the first line. -func wrapFlow(out io.Writer, text []rune, indent string, termWidth int) error { - return wrapGeneric(out, text, indent, " ", termWidth) -} - // wrapGeneric wraps the given text to the given width, prefixing the // first line with indent and the remaining lines with indent2 func wrapGeneric(out io.Writer, text []rune, indent, indent2 string, termWidth int) error { From 6a34f535e5cd74377354a3b634e38c89db2fe2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Thu, 29 Jun 2023 10:03:56 +0200 Subject: [PATCH 12/19] cli: rollback x/crypto/ssh/terminal->x/term --- internals/cli/cli.go | 8 ++++---- internals/cli/format.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index db3a4c30..d38bba77 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -27,7 +27,7 @@ import ( "github.com/canonical/go-flags" - "golang.org/x/term" + "golang.org/x/crypto/ssh/terminal" "github.com/canonical/pebble/client" "github.com/canonical/pebble/internals/logger" @@ -39,7 +39,7 @@ var ( Stdout io.Writer = os.Stdout Stderr io.Writer = os.Stderr // overridden for testing - ReadPassword = term.ReadPassword + ReadPassword = terminal.ReadPassword // set to logger.Panicf in testing noticef = logger.Noticef ) @@ -255,8 +255,8 @@ func Parser(cli *client.Client) *flags.Parser { } var ( - isStdinTTY = term.IsTerminal(0) - isStdoutTTY = term.IsTerminal(1) + isStdinTTY = terminal.IsTerminal(0) + isStdoutTTY = terminal.IsTerminal(1) osExit = os.Exit ) diff --git a/internals/cli/format.go b/internals/cli/format.go index 7be5349b..ba1146fa 100644 --- a/internals/cli/format.go +++ b/internals/cli/format.go @@ -26,7 +26,7 @@ import ( "unicode" "unicode/utf8" - "golang.org/x/term" + "golang.org/x/crypto/ssh/terminal" ) type unicodeMixin struct { @@ -150,7 +150,7 @@ var termSize = termSizeImpl func termSizeImpl() (width, height int) { if f, ok := Stdout.(*os.File); ok { - width, height, _ = term.GetSize(int(f.Fd())) + width, height, _ = terminal.GetSize(int(f.Fd())) } if width <= 0 { From fbb805c8b351184b712dd056071451196840ee4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Mon, 3 Jul 2023 10:17:41 +0200 Subject: [PATCH 13/19] cli: minor changes --- internals/cli/cli.go | 55 +++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index d38bba77..660c7a95 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -21,6 +21,7 @@ import ( "os" "os/user" "path/filepath" + "regexp" "strings" "unicode" "unicode/utf8" @@ -154,7 +155,7 @@ type parserSetter interface { } type options struct { - Version func() `long:"version"` + Version func() `long:"version" hidden:"yes" description:"Print the version and exit"` } // Parser creates and populates a fresh parser. @@ -174,15 +175,13 @@ func Parser(cli *client.Client) *flags.Parser { parser.ShortDescription = "Tool to interact with pebble" parser.LongDescription = longPebbleDescription - // Hide the global --version option on every command - if version := parser.FindOptionByLongName("version"); version != nil { - version.Description = "Print the version and exit" - version.Hidden = true - } - // Add --help like what go-flags would do for us, but hidden addHelp(parser) + // Regular expressions for positional and flag arguments + positionalRegexp := regexp.MustCompile(`^<[\w-]+>$`) + flagRegexp := regexp.MustCompile(`^-(\w|-[\w-]+)$`) + // Add all regular commands for _, c := range commands { obj := c.Builder() @@ -199,54 +198,42 @@ func Parser(cli *client.Client) *flags.Parser { } cmd.PassAfterNonOption = c.PassAfterNonOption - optionsHelp := map[string]string{} - positionalArgsHelp := map[string]string{} + flagHelp := map[string]string{} + positionalHelp := map[string]string{} for specifier, help := range c.ArgsHelp { - isLongOption := strings.HasPrefix(specifier, "--") - isShortOption := utf8.RuneCountInString(specifier) == 2 && strings.HasPrefix(specifier, "-") - if isShortOption || isLongOption { - optionsHelp[specifier] = help - } else if strings.HasPrefix(specifier, "<") && strings.HasSuffix(specifier, ">") { - // This is a positional argument - positionalArgsHelp[specifier] = help + if flagRegexp.MatchString(specifier) { + flagHelp[specifier] = help + } else if positionalRegexp.MatchString(specifier) { + positionalHelp[specifier] = help } else { - logger.Panicf("invalid help specifier: %#v %#v", c.Name, strings.HasPrefix(specifier, "-")) + logger.Panicf("invalid help specifier from %s: %s", c.Name, specifier) } } - hasAnyOptionHelp := len(optionsHelp) > 0 - hasAnyPositionalHelp := len(positionalArgsHelp) > 0 - - // Check either all or none opts/positional argument descriptions are set + // Make sure all argument descriptions are set opts := cmd.Options() - if hasAnyOptionHelp && len(opts) != len(optionsHelp) { - logger.Panicf("wrong number of option descriptions for %s: expected %d, got %d", c.Name, len(opts), len(optionsHelp)) + if len(opts) != len(flagHelp) { + logger.Panicf("wrong number of flag descriptions for %s: expected %d, got %d", c.Name, len(opts), len(flagHelp)) } - args := cmd.Args() - if hasAnyPositionalHelp && len(args) != len(positionalArgsHelp) { - logger.Panicf("wrong number of argument descriptions for %s: expected %d, got %d", c.Name, len(args), len(positionalArgsHelp)) - } - for _, opt := range opts { - if description, ok := optionsHelp["--"+opt.LongName]; ok { + if description, ok := flagHelp["--"+opt.LongName]; ok { lintDesc(c.Name, opt.LongName, description, opt.Description) opt.Description = description - } else if description, ok := optionsHelp["-"+string(opt.ShortName)]; ok { + } else if description, ok := flagHelp["-"+string(opt.ShortName)]; ok { lintDesc(c.Name, string(opt.ShortName), description, opt.Description) opt.Description = description - } else if hasAnyOptionHelp { + } else if !opt.Hidden { logger.Panicf("%s missing description for %s", c.Name, opt) } } + args := cmd.Args() for _, arg := range args { - if description, ok := positionalArgsHelp[arg.Name]; ok { + if description, ok := positionalHelp[arg.Name]; ok { lintArg(c.Name, arg.Name, description, arg.Description) arg.Name = fixupArg(arg.Name) arg.Description = description - } else if hasAnyPositionalHelp { - logger.Panicf("%s missing description for %s", c.Name, arg.Name) } } } From 908a4dff176187c72bd16b9d9b17ab418611444c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Mon, 3 Jul 2023 15:21:07 +0200 Subject: [PATCH 14/19] cli: restore debug command functionality --- internals/cli/cli.go | 62 +++++++++++++++++++++++++++----------- internals/cli/cmd_debug.go | 25 +++++++++++++++ 2 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 internals/cli/cmd_debug.go diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 660c7a95..c2a67435 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -85,17 +85,29 @@ type CmdInfo struct { // Whether to pass all arguments after the first non-option as remaining // command line arguments. This is equivalent to strict POSIX processing. PassAfterNonOption bool + + // When set, the command will be a subcommand of the `debug` command. + // Do not set this flag manually, use AddDebugCommand instead. + debug bool } -// commands holds information about all non-debug commands. +// commands holds information about all the regular Pebble commands. var commands []*CmdInfo -// AddCommand replaces parser.addCommand() in a way that is compatible with -// re-constructing a pristine parser. +// debugCommands holds information about all the subcommands of the `pebble debug` command. +var debugCommands []*CmdInfo + +// AddCommand adds a command to the top-level parser. func AddCommand(info *CmdInfo) { commands = append(commands, info) } +// AddDebugCommand adds a subcommand to the `debug` command. +func AddDebugCommand(info *CmdInfo) { + info.debug = true + debugCommands = append(debugCommands, info) +} + func lintDesc(cmdName, optName, desc, origDesc string) { if len(optName) == 0 { logger.Panicf("option on %q has no name", cmdName) @@ -138,14 +150,14 @@ func fixupArg(optName string) string { return optName } -type clientMixin struct { - client *client.Client -} - type clientSetter interface { setClient(*client.Client) } +type clientMixin struct { + client *client.Client +} + func (ch *clientMixin) setClient(cli *client.Client) { ch.client = cli } @@ -154,7 +166,7 @@ type parserSetter interface { setParser(*flags.Parser) } -type options struct { +type defaultOptions struct { Version func() `long:"version" hidden:"yes" description:"Print the version and exit"` } @@ -163,7 +175,7 @@ type options struct { // from each other. func Parser(cli *client.Client) *flags.Parser { // Implement --version by default on every command - defaultOptions := options{ + defaultOpts := defaultOptions{ Version: func() { printVersions(cli) panic(&exitStatus{0}) @@ -171,7 +183,7 @@ func Parser(cli *client.Client) *flags.Parser { } flagOpts := flags.Options(flags.PassDoubleDash) - parser := flags.NewParser(&defaultOptions, flagOpts) + parser := flags.NewParser(&defaultOpts, flagOpts) parser.ShortDescription = "Tool to interact with pebble" parser.LongDescription = longPebbleDescription @@ -182,8 +194,15 @@ func Parser(cli *client.Client) *flags.Parser { positionalRegexp := regexp.MustCompile(`^<[\w-]+>$`) flagRegexp := regexp.MustCompile(`^-(\w|-[\w-]+)$`) - // Add all regular commands - for _, c := range commands { + // Create debug command + debugCmd, err := parser.AddCommand("debug", shortDebugHelp, longDebugHelp, &cmdDebug{}) + debugCmd.Hidden = true + if err != nil { + logger.Panicf("cannot add command %q: %v", "debug", err) + } + + // Add all commands + for _, c := range append(commands, debugCommands...) { obj := c.Builder() if x, ok := obj.(clientSetter); ok { x.setClient(cli) @@ -192,12 +211,22 @@ func Parser(cli *client.Client) *flags.Parser { x.setParser(parser) } - cmd, err := parser.AddCommand(c.Name, c.Summary, strings.TrimSpace(c.Description), obj) + // Target either the `debug` command or the top-level parser depending on this command + // being or not marked as debug. + var target *flags.Command + if c.debug { + target = debugCmd + } else { + target = parser.Command + } + + cmd, err := target.AddCommand(c.Name, c.Summary, strings.TrimSpace(c.Description), obj) if err != nil { logger.Panicf("cannot add command %q: %v", c.Name, err) } cmd.PassAfterNonOption = c.PassAfterNonOption + // Extract help for flags and positional arguments from ArgsHelp flagHelp := map[string]string{} positionalHelp := map[string]string{} @@ -207,14 +236,14 @@ func Parser(cli *client.Client) *flags.Parser { } else if positionalRegexp.MatchString(specifier) { positionalHelp[specifier] = help } else { - logger.Panicf("invalid help specifier from %s: %s", c.Name, specifier) + logger.Panicf("invalid help specifier from %q: %q", c.Name, specifier) } } // Make sure all argument descriptions are set opts := cmd.Options() if len(opts) != len(flagHelp) { - logger.Panicf("wrong number of flag descriptions for %s: expected %d, got %d", c.Name, len(opts), len(flagHelp)) + logger.Panicf("wrong number of flag descriptions for %q: expected %d, got %d", c.Name, len(opts), len(flagHelp)) } for _, opt := range opts { if description, ok := flagHelp["--"+opt.LongName]; ok { @@ -224,7 +253,7 @@ func Parser(cli *client.Client) *flags.Parser { lintDesc(c.Name, string(opt.ShortName), description, opt.Description) opt.Description = description } else if !opt.Hidden { - logger.Panicf("%s missing description for %s", c.Name, opt) + logger.Panicf("%q missing description for %q", c.Name, opt) } } @@ -237,7 +266,6 @@ func Parser(cli *client.Client) *flags.Parser { } } } - return parser } diff --git a/internals/cli/cmd_debug.go b/internals/cli/cmd_debug.go new file mode 100644 index 00000000..201a0a1e --- /dev/null +++ b/internals/cli/cmd_debug.go @@ -0,0 +1,25 @@ +// Copyright (c) 2014-2020 Canonical Ltd +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 3 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package cli + +type cmdDebug struct{} + +var shortDebugHelp = "Run debug commands" +var longDebugHelp = ` +The debug command contains a selection of additional sub-commands. + +Debug commands can be removed without notice and may not work on +non-development systems. +` From 50fd3dd2d51a76bdf73bbfb9529997aaded69ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Mon, 3 Jul 2023 16:06:08 +0200 Subject: [PATCH 15/19] cli: restore command summary/description consts --- internals/cli/cli.go | 2 +- internals/cli/cmd_add.go | 19 ++++++------ internals/cli/cmd_autostart.go | 19 ++++++------ internals/cli/cmd_changes.go | 34 ++++++++++++---------- internals/cli/cmd_checks.go | 17 ++++++----- internals/cli/cmd_debug.go | 8 +++--- internals/cli/cmd_enter.go | 51 ++++++++++++++++++++++----------- internals/cli/cmd_enter_test.go | 15 ++++++++-- internals/cli/cmd_help.go | 11 +++---- internals/cli/cmd_logs.go | 15 ++++++---- internals/cli/cmd_ls.go | 15 ++++++---- internals/cli/cmd_mkdir.go | 13 +++++---- internals/cli/cmd_plan.go | 28 +++++++++--------- internals/cli/cmd_replan.go | 21 ++++++++------ internals/cli/cmd_restart.go | 15 +++++----- internals/cli/cmd_rm.go | 11 +++---- internals/cli/cmd_run.go | 29 ++++++++++--------- internals/cli/cmd_services.go | 19 ++++++------ internals/cli/cmd_signal.go | 21 ++++++++------ internals/cli/cmd_start.go | 19 ++++++------ internals/cli/cmd_stop.go | 19 ++++++------ internals/cli/cmd_version.go | 11 +++---- internals/cli/cmd_warnings.go | 46 ++++++++++++++++------------- 23 files changed, 267 insertions(+), 191 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index c2a67435..a5945f5e 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -195,7 +195,7 @@ func Parser(cli *client.Client) *flags.Parser { flagRegexp := regexp.MustCompile(`^-(\w|-[\w-]+)$`) // Create debug command - debugCmd, err := parser.AddCommand("debug", shortDebugHelp, longDebugHelp, &cmdDebug{}) + debugCmd, err := parser.AddCommand("debug", cmdDebugSummary, cmdDebugDescription, &cmdDebug{}) debugCmd.Hidden = true if err != nil { logger.Panicf("cannot add command %q: %v", "debug", err) diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index dcdb44d0..88c01c12 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -22,6 +22,14 @@ import ( "github.com/canonical/pebble/client" ) +const cmdAddSummary = "Dynamically add a layer to the plan's layers" +const cmdAddDescription = ` +The add command reads the plan's layer YAML from the path specified and +appends a layer with the given label to the plan's layers. If --combine +is specified, combine the layer with an existing layer that has the given +label (or append if the label is not found). +` + type cmdAdd struct { clientMixin Combine bool `long:"combine"` @@ -33,14 +41,9 @@ type cmdAdd struct { func init() { AddCommand(&CmdInfo{ - Name: "add", - Summary: "Dynamically add a layer to the plan's layers", - Description: ` -The add command reads the plan's layer YAML from the path specified and -appends a layer with the given label to the plan's layers. If --combine -is specified, combine the layer with an existing layer that has the given -label (or append if the label is not found). -`, + Name: "add", + Summary: cmdAddSummary, + Description: cmdAddDescription, ArgsHelp: map[string]string{ "--combine": "Combine the new layer with an existing layer that has the given label (default is to append)", }, diff --git a/internals/cli/cmd_autostart.go b/internals/cli/cmd_autostart.go index a59b6680..251c64fc 100644 --- a/internals/cli/cmd_autostart.go +++ b/internals/cli/cmd_autostart.go @@ -20,20 +20,23 @@ import ( "github.com/canonical/pebble/client" ) +const cmdAutoStartSummary = "Start services set to start by default" +const cmdAutoStartDescription = ` +The autostart command starts the services that were configured +to start by default. +` + type cmdAutoStart struct { waitMixin } func init() { AddCommand(&CmdInfo{ - Name: "autostart", - Summary: "Start services set to start by default", - Description: ` -The autostart command starts the services that were configured -to start by default. -`, - ArgsHelp: waitArgsHelp, - Builder: func() flags.Commander { return &cmdAutoStart{} }, + Name: "autostart", + Summary: cmdAutoStartSummary, + Description: cmdAutoStartDescription, + ArgsHelp: waitArgsHelp, + Builder: func() flags.Commander { return &cmdAutoStart{} }, }) } diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index 0750d54f..e5836d25 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -24,6 +24,9 @@ import ( "github.com/canonical/pebble/client" ) +const cmdChangesSummary = "List system changes" +const cmdChangesDescription = "The changes command displays a summary of system changes performed recently." + type cmdChanges struct { clientMixin timeMixin @@ -32,6 +35,12 @@ type cmdChanges struct { } `positional-args:"yes"` } +const cmdTasksSummary = "List a change's tasks" +const cmdTasksDescription = ` +The tasks command displays a summary of tasks associated with an individual +change that happened recently. +` + type cmdTasks struct { timeMixin changeIDMixin @@ -39,23 +48,18 @@ type cmdTasks struct { func init() { AddCommand(&CmdInfo{ - Name: "changes", - Summary: "List system changes", - Description: ` -The changes command displays a summary of system changes performed recently. -`, - ArgsHelp: timeArgsHelp, - Builder: func() flags.Commander { return &cmdChanges{} }, + Name: "changes", + Summary: cmdChangesSummary, + Description: cmdChangesDescription, + ArgsHelp: timeArgsHelp, + Builder: func() flags.Commander { return &cmdChanges{} }, }) AddCommand(&CmdInfo{ - Name: "tasks", - Summary: "List a change's tasks", - Description: ` -The tasks command displays a summary of tasks associated with an individual -change that happened recently. -`, - ArgsHelp: merge(changeIDMixinArgsHelp, timeArgsHelp), - Builder: func() flags.Commander { return &cmdTasks{} }, + Name: "tasks", + Summary: cmdTasksSummary, + Description: cmdTasksDescription, + ArgsHelp: merge(changeIDMixinArgsHelp, timeArgsHelp), + Builder: func() flags.Commander { return &cmdTasks{} }, }) } diff --git a/internals/cli/cmd_checks.go b/internals/cli/cmd_checks.go index 7fe041b9..9d95c15a 100644 --- a/internals/cli/cmd_checks.go +++ b/internals/cli/cmd_checks.go @@ -21,6 +21,13 @@ import ( "github.com/canonical/pebble/client" ) +const cmdChecksSummary = "Query the status of configured health checks" +const cmdChecksDescription = ` +The checks command lists status information about the configured health +checks, optionally filtered by level and check names provided as positional +arguments. +` + type cmdChecks struct { clientMixin Level string `long:"level"` @@ -31,13 +38,9 @@ type cmdChecks struct { func init() { AddCommand(&CmdInfo{ - Name: "checks", - Summary: "Query the status of configured health checks", - Description: ` -The checks command lists status information about the configured health -checks, optionally filtered by level and check names provided as positional -arguments. -`, + Name: "checks", + Summary: cmdChecksSummary, + Description: cmdChecksDescription, ArgsHelp: map[string]string{ "--level": `Check level to filter for ("alive" or "ready")`, }, diff --git a/internals/cli/cmd_debug.go b/internals/cli/cmd_debug.go index 201a0a1e..ea999393 100644 --- a/internals/cli/cmd_debug.go +++ b/internals/cli/cmd_debug.go @@ -14,12 +14,12 @@ package cli -type cmdDebug struct{} - -var shortDebugHelp = "Run debug commands" -var longDebugHelp = ` +var cmdDebugSummary = "Run debug commands" +var cmdDebugDescription = ` The debug command contains a selection of additional sub-commands. Debug commands can be removed without notice and may not work on non-development systems. ` + +type cmdDebug struct{} diff --git a/internals/cli/cmd_enter.go b/internals/cli/cmd_enter.go index 7280a4a8..6e4e6ccb 100644 --- a/internals/cli/cmd_enter.go +++ b/internals/cli/cmd_enter.go @@ -1,3 +1,17 @@ +// Copyright (c) 2023 Canonical Ltd +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 3 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + package cli import ( @@ -8,21 +22,8 @@ import ( "github.com/canonical/pebble/internals/logger" ) -type cmdEnter struct { - clientMixin - sharedRunEnterOpts - Run bool `long:"run"` - Positional struct { - Cmd []string `positional-arg-name:""` - } `positional-args:"yes"` - parser *flags.Parser -} - -func init() { - AddCommand(&CmdInfo{ - Name: "enter", - Summary: "Run subcommand under a container environment", - Description: ` +const cmdEnterSummary = "Run subcommand under a container environment" +const cmdEnterDescription = ` The enter command facilitates the use of Pebble as an entrypoint for containers. When used without a subcommand it mimics the behavior of the run command alone, while if used with a subcommand it runs that subcommand in the most @@ -42,8 +43,24 @@ These subcommands are currently supported: (1) Services are not started. (2) No logs on stdout unless -v is used. (3) Services continue running after the subcommand succeeds. -`, - Builder: func() flags.Commander { return &cmdEnter{} }, +` + +type cmdEnter struct { + clientMixin + sharedRunEnterOpts + Run bool `long:"run"` + Positional struct { + Cmd []string `positional-arg-name:""` + } `positional-args:"yes"` + parser *flags.Parser +} + +func init() { + AddCommand(&CmdInfo{ + Name: "enter", + Summary: cmdEnterSummary, + Description: cmdEnterDescription, + Builder: func() flags.Commander { return &cmdEnter{} }, ArgsHelp: merge(sharedRunEnterArgsHelp, map[string]string{ "--run": "Start default services before executing subcommand", }), diff --git a/internals/cli/cmd_enter_test.go b/internals/cli/cmd_enter_test.go index c4161d01..80e43690 100644 --- a/internals/cli/cmd_enter_test.go +++ b/internals/cli/cmd_enter_test.go @@ -1,5 +1,16 @@ -// SPDX-FileCopyrightText: 2023 Canonical Ltd -// SPDX-License-Identifier: GPL-3.0-only +// Copyright (c) 2023 Canonical Ltd +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 3 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . package cli_test diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index c35fa0f0..93b436f0 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -25,6 +25,9 @@ import ( "github.com/canonical/go-flags" ) +const cmdHelpSummary = "Show help about a command" +const cmdHelpDescription = "The help command displays information about commands." + type cmdHelp struct { All bool `long:"all"` Manpage bool `long:"man" hidden:"true"` @@ -36,11 +39,9 @@ type cmdHelp struct { func init() { AddCommand(&CmdInfo{ - Name: "help", - Summary: "Show help about a command", - Description: ` -The help command displays information about commands. -`, + Name: "help", + Summary: cmdHelpSummary, + Description: cmdHelpDescription, ArgsHelp: map[string]string{ "--all": "Show a short summary of all commands", "--man": "Generate the manpage", diff --git a/internals/cli/cmd_logs.go b/internals/cli/cmd_logs.go index ca914eb0..4faf1bb5 100644 --- a/internals/cli/cmd_logs.go +++ b/internals/cli/cmd_logs.go @@ -26,6 +26,12 @@ import ( "github.com/canonical/pebble/client" ) +const cmdLogsSummary = "Fetch service logs" +const cmdLogsDescription = ` +The logs command fetches buffered logs from the given services (or all services +if none are specified) and displays them in chronological order. +` + type cmdLogs struct { clientMixin Follow bool `short:"f" long:"follow"` @@ -38,12 +44,9 @@ type cmdLogs struct { func init() { AddCommand(&CmdInfo{ - Name: "logs", - Summary: "Fetch service logs", - Description: ` -The logs command fetches buffered logs from the given services (or all services -if none are specified) and displays them in chronological order. -`, + Name: "logs", + Summary: cmdLogsSummary, + Description: cmdLogsDescription, ArgsHelp: map[string]string{ "--follow": "Follow (tail) logs for given services until Ctrl-C is\npressed. If no services are specified, show logs from\nall services running when the command starts.", "--format": "Output format: \"text\" (default) or \"json\" (JSON lines).", diff --git a/internals/cli/cmd_ls.go b/internals/cli/cmd_ls.go index 99acc3a2..8cd31f9e 100644 --- a/internals/cli/cmd_ls.go +++ b/internals/cli/cmd_ls.go @@ -26,6 +26,12 @@ import ( "github.com/canonical/pebble/client" ) +const cmdLsSummary = "List path contents" +const cmdLsDescription = ` +The ls command lists entries in the filesystem at the specified path. A glob pattern +may be specified for the last path element. +` + type cmdLs struct { clientMixin timeMixin @@ -40,12 +46,9 @@ type cmdLs struct { func init() { AddCommand(&CmdInfo{ - Name: "ls", - Summary: "List path contents", - Description: ` -The ls command lists entries in the filesystem at the specified path. A glob pattern -may be specified for the last path element. -`, + Name: "ls", + Summary: cmdLsSummary, + Description: cmdLsDescription, ArgsHelp: merge(timeArgsHelp, map[string]string{ "-d": "List matching entries themselves, not directory contents", "-l": "Use a long listing format", diff --git a/internals/cli/cmd_mkdir.go b/internals/cli/cmd_mkdir.go index 232dd65c..80dd3496 100644 --- a/internals/cli/cmd_mkdir.go +++ b/internals/cli/cmd_mkdir.go @@ -24,6 +24,9 @@ import ( "github.com/canonical/pebble/client" ) +const cmdMkdirSummary = "Create a directory" +const cmdMkdirDescription = "The mkdir command creates the specified directory." + type cmdMkdir struct { clientMixin @@ -41,12 +44,10 @@ type cmdMkdir struct { func init() { AddCommand(&CmdInfo{ - Name: "mkdir", - Summary: "Create a directory", - Description: ` -The mkdir command creates the specified directory. -`, - Builder: func() flags.Commander { return &cmdMkdir{} }, + Name: "mkdir", + Summary: cmdMkdirSummary, + Description: cmdMkdirDescription, + Builder: func() flags.Commander { return &cmdMkdir{} }, ArgsHelp: map[string]string{ "-p": "Create parent directories as needed", "-m": "Set permissions (e.g. 0644)", diff --git a/internals/cli/cmd_plan.go b/internals/cli/cmd_plan.go index b57fcc4e..0e82796c 100644 --- a/internals/cli/cmd_plan.go +++ b/internals/cli/cmd_plan.go @@ -20,15 +20,24 @@ import ( "github.com/canonical/pebble/client" ) +var cmdPlanSummary = "Show the plan with layers combined" +var cmdPlanDescription = ` +The plan command prints out the effective configuration of pebble in YAML +format. Layers are combined according to the override rules defined in them. +` + type cmdPlan struct { clientMixin } -var shortPlanHelp = "Show the plan with layers combined" -var longPlanHelp = ` -The plan command prints out the effective configuration of pebble in YAML -format. Layers are combined according to the override rules defined in them. -` +func init() { + AddCommand(&CmdInfo{ + Name: "plan", + Summary: cmdPlanSummary, + Description: cmdPlanDescription, + Builder: func() flags.Commander { return &cmdPlan{} }, + }) +} func (cmd *cmdPlan) Execute(args []string) error { if len(args) > 0 { @@ -41,12 +50,3 @@ func (cmd *cmdPlan) Execute(args []string) error { Stdout.Write(planYAML) return nil } - -func init() { - AddCommand(&CmdInfo{ - Name: "plan", - Summary: shortPlanHelp, - Description: longPlanHelp, - Builder: func() flags.Commander { return &cmdPlan{} }, - }) -} diff --git a/internals/cli/cmd_replan.go b/internals/cli/cmd_replan.go index c16e6bec..b4b92ad9 100644 --- a/internals/cli/cmd_replan.go +++ b/internals/cli/cmd_replan.go @@ -20,21 +20,24 @@ import ( "github.com/canonical/pebble/client" ) +const cmdReplanSummary = "Ensure running services match the current plan" +const cmdReplanDescription = ` +The replan command starts, stops, or restarts services that have changed, +so that running services exactly match the desired configuration in the +current plan. +` + type cmdReplan struct { waitMixin } func init() { AddCommand(&CmdInfo{ - Name: "replan", - Summary: "Ensure running services match the current plan", - Description: ` -The replan command starts, stops, or restarts services that have changed, -so that running services exactly match the desired configuration in the -current plan. -`, - ArgsHelp: waitArgsHelp, - Builder: func() flags.Commander { return &cmdReplan{} }, + Name: "replan", + Summary: cmdReplanSummary, + Description: cmdReplanDescription, + ArgsHelp: waitArgsHelp, + Builder: func() flags.Commander { return &cmdReplan{} }, }) } diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index 62f4a09f..e629d061 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -19,6 +19,9 @@ import ( "github.com/canonical/pebble/client" ) +const cmdRestartSummary = "Restart a service" +const cmdRestartDescription = "The restart command restarts the named service(s) in the correct order." + type cmdRestart struct { waitMixin Positional struct { @@ -28,13 +31,11 @@ type cmdRestart struct { func init() { AddCommand(&CmdInfo{ - Name: "restart", - Summary: "Restart a service", - Description: ` -The restart command restarts the named service(s) in the correct order. -`, - ArgsHelp: waitArgsHelp, - Builder: func() flags.Commander { return &cmdRestart{} }, + Name: "restart", + Summary: cmdRestartSummary, + Description: cmdRestartDescription, + ArgsHelp: waitArgsHelp, + Builder: func() flags.Commander { return &cmdRestart{} }, }) } diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index d5d10202..db70092e 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -19,6 +19,9 @@ import ( "github.com/canonical/pebble/client" ) +const cmdRmSummary = "Remove a file or directory" +const cmdRmDescription = "The rm command removes a file or directory." + type cmdRm struct { clientMixin Recursive bool `short:"r"` @@ -29,11 +32,9 @@ type cmdRm struct { func init() { AddCommand(&CmdInfo{ - Name: "rm", - Summary: "Remove a file or directory", - Description: ` -The rm command removes a file or directory. -`, + Name: "rm", + Summary: cmdRmSummary, + Description: cmdRmDescription, ArgsHelp: map[string]string{ "-r": "Remove all files and directories recursively in the specified path", }, diff --git a/internals/cli/cmd_run.go b/internals/cli/cmd_run.go index 6ad46899..bf62081a 100644 --- a/internals/cli/cmd_run.go +++ b/internals/cli/cmd_run.go @@ -47,16 +47,8 @@ var sharedRunEnterArgsHelp = map[string]string{ "--args": `Provide additional arguments to a service`, } -type cmdRun struct { - clientMixin - sharedRunEnterOpts -} - -func init() { - AddCommand(&CmdInfo{ - Name: "run", - Summary: "Run the pebble environment", - Description: ` +const cmdRunSummary = "Run the pebble environment" +const cmdRunDescription = ` The run command starts pebble and runs the configured environment. Additional arguments may be provided to the service command with the --args option, which @@ -65,9 +57,20 @@ are appended to the end of the service command, and replace any default argument in the service plan. For example: $ pebble run --args myservice --port 8080 \; --hold -`, - ArgsHelp: sharedRunEnterArgsHelp, - Builder: func() flags.Commander { return &cmdRun{} }, +` + +type cmdRun struct { + clientMixin + sharedRunEnterOpts +} + +func init() { + AddCommand(&CmdInfo{ + Name: "run", + Summary: cmdRunSummary, + Description: cmdRunDescription, + ArgsHelp: sharedRunEnterArgsHelp, + Builder: func() flags.Commander { return &cmdRun{} }, }) } diff --git a/internals/cli/cmd_services.go b/internals/cli/cmd_services.go index 57c23234..933ab371 100644 --- a/internals/cli/cmd_services.go +++ b/internals/cli/cmd_services.go @@ -21,6 +21,12 @@ import ( "github.com/canonical/pebble/client" ) +const cmdServicesSummary = "Query the status of configured services" +const cmdServicesDescription = ` +The services command lists status information about the services specified, or +about all services if none are specified. +` + type cmdServices struct { clientMixin timeMixin @@ -31,14 +37,11 @@ type cmdServices struct { func init() { AddCommand(&CmdInfo{ - Name: "services", - Summary: "Query the status of configured services", - Description: ` -The services command lists status information about the services specified, or -about all services if none are specified. -`, - ArgsHelp: timeArgsHelp, - Builder: func() flags.Commander { return &cmdServices{} }, + Name: "services", + Summary: cmdServicesSummary, + Description: cmdServicesDescription, + ArgsHelp: timeArgsHelp, + Builder: func() flags.Commander { return &cmdServices{} }, }) } diff --git a/internals/cli/cmd_signal.go b/internals/cli/cmd_signal.go index 558d496d..5e1ffb70 100644 --- a/internals/cli/cmd_signal.go +++ b/internals/cli/cmd_signal.go @@ -22,6 +22,14 @@ import ( "github.com/canonical/pebble/client" ) +const cmdSignalSummary = "Send a signal to one or more running services" +const cmdSignalDescription = ` +The signal command sends a signal to one or more running services. The signal +name must be uppercase, for example: + +pebble signal HUP mysql nginx +` + type cmdSignal struct { clientMixin Positional struct { @@ -32,15 +40,10 @@ type cmdSignal struct { func init() { AddCommand(&CmdInfo{ - Name: "signal", - Summary: "Send a signal to one or more running services", - Description: ` -The signal command sends a signal to one or more running services. The signal -name must be uppercase, for example: - -pebble signal HUP mysql nginx -`, - Builder: func() flags.Commander { return &cmdSignal{} }, + Name: "signal", + Summary: cmdSignalSummary, + Description: cmdSignalDescription, + Builder: func() flags.Commander { return &cmdSignal{} }, }) } diff --git a/internals/cli/cmd_start.go b/internals/cli/cmd_start.go index 82fc0f75..9167ff2c 100644 --- a/internals/cli/cmd_start.go +++ b/internals/cli/cmd_start.go @@ -20,6 +20,12 @@ import ( "github.com/canonical/pebble/client" ) +const cmdStartSummary = "Start a service and its dependencies" +const cmdStartDescription = ` +The start command starts the service with the provided name and +any other services it depends on, in the correct order. +` + type cmdStart struct { waitMixin Positional struct { @@ -29,14 +35,11 @@ type cmdStart struct { func init() { AddCommand(&CmdInfo{ - Name: "start", - Summary: "Start a service and its dependencies", - Description: ` -The start command starts the service with the provided name and -any other services it depends on, in the correct order. -`, - ArgsHelp: waitArgsHelp, - Builder: func() flags.Commander { return &cmdStart{} }, + Name: "start", + Summary: cmdStartSummary, + Description: cmdStartDescription, + ArgsHelp: waitArgsHelp, + Builder: func() flags.Commander { return &cmdStart{} }, }) } diff --git a/internals/cli/cmd_stop.go b/internals/cli/cmd_stop.go index 60626984..671dbff2 100644 --- a/internals/cli/cmd_stop.go +++ b/internals/cli/cmd_stop.go @@ -20,6 +20,12 @@ import ( "github.com/canonical/pebble/client" ) +const cmdStopSummary = "Stop a service and its dependents" +const cmdStopDescription = ` +The stop command stops the service with the provided name and +any other service that depends on it, in the correct order. +` + type cmdStop struct { waitMixin Positional struct { @@ -29,14 +35,11 @@ type cmdStop struct { func init() { AddCommand(&CmdInfo{ - Name: "stop", - Summary: "Stop a service and its dependents", - Description: ` -The stop command stops the service with the provided name and -any other service that depends on it, in the correct order. -`, - Builder: func() flags.Commander { return &cmdStop{} }, - ArgsHelp: waitArgsHelp, + Name: "stop", + Summary: cmdStopSummary, + Description: cmdStopDescription, + Builder: func() flags.Commander { return &cmdStop{} }, + ArgsHelp: waitArgsHelp, }) } diff --git a/internals/cli/cmd_version.go b/internals/cli/cmd_version.go index f69fa654..6e39c58d 100644 --- a/internals/cli/cmd_version.go +++ b/internals/cli/cmd_version.go @@ -23,6 +23,9 @@ import ( version "github.com/canonical/pebble/cmd" ) +const cmdVersionSummary = "Show version details" +const cmdVersionDescription = "The version command displays the versions of the running client and server." + type cmdVersion struct { clientMixin ClientOnly bool `long:"client"` @@ -30,11 +33,9 @@ type cmdVersion struct { func init() { AddCommand(&CmdInfo{ - Name: "version", - Summary: "Show version details", - Description: ` -The version command displays the versions of the running client and server. -`, + Name: "version", + Summary: cmdVersionSummary, + Description: cmdVersionDescription, ArgsHelp: map[string]string{ "--client": "Only display the client version", }, diff --git a/internals/cli/cmd_warnings.go b/internals/cli/cmd_warnings.go index a327526a..24db9ec1 100644 --- a/internals/cli/cmd_warnings.go +++ b/internals/cli/cmd_warnings.go @@ -31,6 +31,17 @@ import ( "github.com/canonical/pebble/internals/osutil" ) +const cmdWarningsSummary = "List warnings" +const cmdWarningsDescription = ` +The warnings command lists the warnings that have been reported to the system. + +Once warnings have been listed with 'pebble warnings', 'pebble okay' may be used to +silence them. A warning that's been silenced in this way will not be listed +again unless it happens again, _and_ a cooldown time has passed. + +Warnings expire automatically, and once expired they are forgotten. +` + type cmdWarnings struct { clientMixin timeMixin @@ -39,21 +50,21 @@ type cmdWarnings struct { Verbose bool `long:"verbose"` } +const cmdOkaySummary = "Acknowledge warnings" +const cmdOkayDescription = ` +The okay command acknowledges the warnings listed with 'pebble warnings'. + +Once acknowledged, a warning won't appear again unless it reoccurs and +sufficient time has passed. +` + type cmdOkay struct{ clientMixin } func init() { AddCommand(&CmdInfo{ - Name: "warnings", - Summary: "List warnings", - Description: ` -The warnings command lists the warnings that have been reported to the system. - -Once warnings have been listed with 'pebble warnings', 'pebble okay' may be used to -silence them. A warning that's been silenced in this way will not be listed -again unless it happens again, _and_ a cooldown time has passed. - -Warnings expire automatically, and once expired they are forgotten. -`, + Name: "warnings", + Summary: cmdWarningsSummary, + Description: cmdWarningsDescription, ArgsHelp: merge(timeArgsHelp, unicodeArgsHelp, map[string]string{ "--all": "Show all warnings", "--verbose": "Show more information", @@ -61,15 +72,10 @@ Warnings expire automatically, and once expired they are forgotten. Builder: func() flags.Commander { return &cmdWarnings{} }, }) AddCommand(&CmdInfo{ - Name: "okay", - Summary: "Acknowledge warnings", - Description: ` -The okay command acknowledges the warnings listed with 'pebble warnings'. - -Once acknowledged, a warning won't appear again unless it reoccurs and -sufficient time has passed. -`, - Builder: func() flags.Commander { return &cmdOkay{} }, + Name: "okay", + Summary: cmdOkaySummary, + Description: cmdOkayDescription, + Builder: func() flags.Commander { return &cmdOkay{} }, }) } From 8bc71be6ec06c4cee48e488f9ec609ef1735397d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Wed, 5 Jul 2023 10:07:47 +0200 Subject: [PATCH 16/19] cli: tweak flag regexp The following flags will pass: `-a`, `--long-flag`, `--b`, `--this-is-a-flag`; the following flags won't: `---`, `---c`, `--quasi--valid` --- internals/cli/cli.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index a5945f5e..14325385 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -192,7 +192,7 @@ func Parser(cli *client.Client) *flags.Parser { // Regular expressions for positional and flag arguments positionalRegexp := regexp.MustCompile(`^<[\w-]+>$`) - flagRegexp := regexp.MustCompile(`^-(\w|-[\w-]+)$`) + flagRegexp := regexp.MustCompile(`^-(\w|-[\w]+(-?[\w]+)*)$`) // Create debug command debugCmd, err := parser.AddCommand("debug", cmdDebugSummary, cmdDebugDescription, &cmdDebug{}) From 8417216102a1f9500b62da63da399c5be30107d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Fri, 7 Jul 2023 17:16:44 +0200 Subject: [PATCH 17/19] cli: minor changes --- internals/cli/cli.go | 35 ++++++++++++++--------------------- internals/cli/cmd_changes.go | 4 +++- internals/cli/cmd_exec.go | 27 +++++++++++++++------------ internals/cli/cmd_help.go | 4 +++- internals/cli/cmd_mkdir.go | 4 +++- internals/cli/cmd_restart.go | 4 +++- internals/cli/cmd_rm.go | 4 +++- internals/cli/cmd_run.go | 24 ++++++++++++------------ internals/cli/cmd_version.go | 4 +++- 9 files changed, 59 insertions(+), 51 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index 14325385..aab90ca4 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -87,8 +87,7 @@ type CmdInfo struct { PassAfterNonOption bool // When set, the command will be a subcommand of the `debug` command. - // Do not set this flag manually, use AddDebugCommand instead. - debug bool + Debug bool } // commands holds information about all the regular Pebble commands. @@ -102,12 +101,6 @@ func AddCommand(info *CmdInfo) { commands = append(commands, info) } -// AddDebugCommand adds a subcommand to the `debug` command. -func AddDebugCommand(info *CmdInfo) { - info.debug = true - debugCommands = append(debugCommands, info) -} - func lintDesc(cmdName, optName, desc, origDesc string) { if len(optName) == 0 { logger.Panicf("option on %q has no name", cmdName) @@ -191,18 +184,22 @@ func Parser(cli *client.Client) *flags.Parser { addHelp(parser) // Regular expressions for positional and flag arguments - positionalRegexp := regexp.MustCompile(`^<[\w-]+>$`) - flagRegexp := regexp.MustCompile(`^-(\w|-[\w]+(-?[\w]+)*)$`) + positionalRegexp := regexp.MustCompile(`^<\w+(-\w+)>$`) + flagRegexp := regexp.MustCompile(`^-\w|--\w+(-\w+)*$`) // Create debug command debugCmd, err := parser.AddCommand("debug", cmdDebugSummary, cmdDebugDescription, &cmdDebug{}) debugCmd.Hidden = true if err != nil { - logger.Panicf("cannot add command %q: %v", "debug", err) + logger.Panicf("internal error: cannot add command %q: %v", "debug", err) } // Add all commands - for _, c := range append(commands, debugCommands...) { + ncmds := len(commands) + allCmds := make([]*CmdInfo, ncmds, ncmds+len(debugCommands)) + copy(allCmds, commands) + copy(allCmds[ncmds:], debugCommands) + for _, c := range allCmds { obj := c.Builder() if x, ok := obj.(clientSetter); ok { x.setClient(cli) @@ -211,39 +208,35 @@ func Parser(cli *client.Client) *flags.Parser { x.setParser(parser) } - // Target either the `debug` command or the top-level parser depending on this command - // being or not marked as debug. var target *flags.Command - if c.debug { + if c.Debug { target = debugCmd } else { target = parser.Command } - cmd, err := target.AddCommand(c.Name, c.Summary, strings.TrimSpace(c.Description), obj) if err != nil { - logger.Panicf("cannot add command %q: %v", c.Name, err) + logger.Panicf("internal error: cannot add command %q: %v", c.Name, err) } cmd.PassAfterNonOption = c.PassAfterNonOption // Extract help for flags and positional arguments from ArgsHelp flagHelp := map[string]string{} positionalHelp := map[string]string{} - for specifier, help := range c.ArgsHelp { if flagRegexp.MatchString(specifier) { flagHelp[specifier] = help } else if positionalRegexp.MatchString(specifier) { positionalHelp[specifier] = help } else { - logger.Panicf("invalid help specifier from %q: %q", c.Name, specifier) + logger.Panicf("internal error: invalid help specifier from %q: %q", c.Name, specifier) } } // Make sure all argument descriptions are set opts := cmd.Options() if len(opts) != len(flagHelp) { - logger.Panicf("wrong number of flag descriptions for %q: expected %d, got %d", c.Name, len(opts), len(flagHelp)) + logger.Panicf("internal error: wrong number of flag descriptions for %q: expected %d, got %d", c.Name, len(opts), len(flagHelp)) } for _, opt := range opts { if description, ok := flagHelp["--"+opt.LongName]; ok { @@ -253,7 +246,7 @@ func Parser(cli *client.Client) *flags.Parser { lintDesc(c.Name, string(opt.ShortName), description, opt.Description) opt.Description = description } else if !opt.Hidden { - logger.Panicf("%q missing description for %q", c.Name, opt) + logger.Panicf("internal error: %q missing description for %q", c.Name, opt) } } diff --git a/internals/cli/cmd_changes.go b/internals/cli/cmd_changes.go index e5836d25..0e5fa935 100644 --- a/internals/cli/cmd_changes.go +++ b/internals/cli/cmd_changes.go @@ -25,7 +25,9 @@ import ( ) const cmdChangesSummary = "List system changes" -const cmdChangesDescription = "The changes command displays a summary of system changes performed recently." +const cmdChangesDescription = ` +The changes command displays a summary of system changes performed recently. +` type cmdChanges struct { clientMixin diff --git a/internals/cli/cmd_exec.go b/internals/cli/cmd_exec.go index 3a3821a2..07a947f4 100644 --- a/internals/cli/cmd_exec.go +++ b/internals/cli/cmd_exec.go @@ -30,6 +30,18 @@ import ( "github.com/canonical/pebble/internals/ptyutil" ) +const cmdExecSummary = "Execute a remote command and wait for it to finish" +const cmdExecDescription = ` +The exec command runs a remote command and waits for it to finish. The local +stdin is sent as the input to the remote process, while the remote stdout and +stderr are output locally. + +To avoid confusion, exec options may be separated from the command and its +arguments using "--", for example: + +pebble exec --timeout 10s -- echo -n foo bar +` + type cmdExec struct { clientMixin WorkingDir string `short:"w"` @@ -50,18 +62,9 @@ type cmdExec struct { func init() { AddCommand(&CmdInfo{ - Name: "exec", - Summary: "Execute a remote command and wait for it to finish", - Description: ` -The exec command runs a remote command and waits for it to finish. The local -stdin is sent as the input to the remote process, while the remote stdout and -stderr are output locally. - -To avoid confusion, exec options may be separated from the command and its -arguments using "--", for example: - -pebble exec --timeout 10s -- echo -n foo bar -`, + Name: "exec", + Summary: cmdExecSummary, + Description: cmdExecDescription, ArgsHelp: map[string]string{ "-w": "Working directory to run command in", "--env": "Environment variable to set (in 'FOO=bar' format)", diff --git a/internals/cli/cmd_help.go b/internals/cli/cmd_help.go index 93b436f0..fbab7e10 100644 --- a/internals/cli/cmd_help.go +++ b/internals/cli/cmd_help.go @@ -26,7 +26,9 @@ import ( ) const cmdHelpSummary = "Show help about a command" -const cmdHelpDescription = "The help command displays information about commands." +const cmdHelpDescription = ` +The help command displays information about commands. +` type cmdHelp struct { All bool `long:"all"` diff --git a/internals/cli/cmd_mkdir.go b/internals/cli/cmd_mkdir.go index 80dd3496..4e95edaf 100644 --- a/internals/cli/cmd_mkdir.go +++ b/internals/cli/cmd_mkdir.go @@ -25,7 +25,9 @@ import ( ) const cmdMkdirSummary = "Create a directory" -const cmdMkdirDescription = "The mkdir command creates the specified directory." +const cmdMkdirDescription = ` +The mkdir command creates the specified directory. +` type cmdMkdir struct { clientMixin diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index e629d061..70d00e9d 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -20,7 +20,9 @@ import ( ) const cmdRestartSummary = "Restart a service" -const cmdRestartDescription = "The restart command restarts the named service(s) in the correct order." +const cmdRestartDescription = ` +The restart command restarts the named service(s) in the correct order. +` type cmdRestart struct { waitMixin diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index db70092e..e5a4265f 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -20,7 +20,9 @@ import ( ) const cmdRmSummary = "Remove a file or directory" -const cmdRmDescription = "The rm command removes a file or directory." +const cmdRmDescription = ` +The rm command removes a file or directory. +` type cmdRm struct { clientMixin diff --git a/internals/cli/cmd_run.go b/internals/cli/cmd_run.go index bf62081a..c0519c22 100644 --- a/internals/cli/cmd_run.go +++ b/internals/cli/cmd_run.go @@ -31,6 +31,18 @@ import ( "github.com/canonical/pebble/internals/systemd" ) +const cmdRunSummary = "Run the pebble environment" +const cmdRunDescription = ` +The run command starts pebble and runs the configured environment. + +Additional arguments may be provided to the service command with the --args option, which +must be terminated with ";" unless there are no further Pebble options. These arguments +are appended to the end of the service command, and replace any default arguments defined +in the service plan. For example: + + $ pebble run --args myservice --port 8080 \; --hold +` + type sharedRunEnterOpts struct { CreateDirs bool `long:"create-dirs"` Hold bool `long:"hold"` @@ -47,18 +59,6 @@ var sharedRunEnterArgsHelp = map[string]string{ "--args": `Provide additional arguments to a service`, } -const cmdRunSummary = "Run the pebble environment" -const cmdRunDescription = ` -The run command starts pebble and runs the configured environment. - -Additional arguments may be provided to the service command with the --args option, which -must be terminated with ";" unless there are no further Pebble options. These arguments -are appended to the end of the service command, and replace any default arguments defined -in the service plan. For example: - - $ pebble run --args myservice --port 8080 \; --hold -` - type cmdRun struct { clientMixin sharedRunEnterOpts diff --git a/internals/cli/cmd_version.go b/internals/cli/cmd_version.go index 6e39c58d..f8a60042 100644 --- a/internals/cli/cmd_version.go +++ b/internals/cli/cmd_version.go @@ -24,7 +24,9 @@ import ( ) const cmdVersionSummary = "Show version details" -const cmdVersionDescription = "The version command displays the versions of the running client and server." +const cmdVersionDescription = ` +The version command displays the versions of the running client and server. +` type cmdVersion struct { clientMixin From 2e6637482a7101307f9f74118472f0d4cdf30478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Tue, 11 Jul 2023 12:13:25 +0200 Subject: [PATCH 18/19] cli: Remove vestigial code from `debug` support --- internals/cli/cli.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/internals/cli/cli.go b/internals/cli/cli.go index aab90ca4..e35a2baa 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -93,9 +93,6 @@ type CmdInfo struct { // commands holds information about all the regular Pebble commands. var commands []*CmdInfo -// debugCommands holds information about all the subcommands of the `pebble debug` command. -var debugCommands []*CmdInfo - // AddCommand adds a command to the top-level parser. func AddCommand(info *CmdInfo) { commands = append(commands, info) @@ -195,11 +192,7 @@ func Parser(cli *client.Client) *flags.Parser { } // Add all commands - ncmds := len(commands) - allCmds := make([]*CmdInfo, ncmds, ncmds+len(debugCommands)) - copy(allCmds, commands) - copy(allCmds[ncmds:], debugCommands) - for _, c := range allCmds { + for _, c := range commands { obj := c.Builder() if x, ok := obj.(clientSetter); ok { x.setClient(cli) From 472aee91338c4095b77cfc532409a9b88241202a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Tue, 1 Aug 2023 16:52:24 +0200 Subject: [PATCH 19/19] Fix imports --- internals/cli/cmd_add.go | 1 + internals/cli/cmd_checks.go | 1 + internals/cli/cmd_exec.go | 2 +- internals/cli/cmd_logs.go | 1 + internals/cli/cmd_restart.go | 1 + internals/cli/cmd_rm.go | 1 + internals/cli/cmd_services.go | 1 + internals/cli/cmd_signal.go | 1 + 8 files changed, 8 insertions(+), 1 deletion(-) diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index 88c01c12..3a0d3f6e 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -19,6 +19,7 @@ import ( "io/ioutil" "github.com/canonical/go-flags" + "github.com/canonical/pebble/client" ) diff --git a/internals/cli/cmd_checks.go b/internals/cli/cmd_checks.go index 9d95c15a..7da46f18 100644 --- a/internals/cli/cmd_checks.go +++ b/internals/cli/cmd_checks.go @@ -18,6 +18,7 @@ import ( "fmt" "github.com/canonical/go-flags" + "github.com/canonical/pebble/client" ) diff --git a/internals/cli/cmd_exec.go b/internals/cli/cmd_exec.go index a83e6cc6..d0d2fe43 100644 --- a/internals/cli/cmd_exec.go +++ b/internals/cli/cmd_exec.go @@ -22,9 +22,9 @@ import ( "strings" "time" + "github.com/canonical/go-flags" "golang.org/x/sys/unix" - "github.com/canonical/go-flags" "github.com/canonical/pebble/client" "github.com/canonical/pebble/internals/logger" "github.com/canonical/pebble/internals/ptyutil" diff --git a/internals/cli/cmd_logs.go b/internals/cli/cmd_logs.go index 33f1b08c..a44ba7e9 100644 --- a/internals/cli/cmd_logs.go +++ b/internals/cli/cmd_logs.go @@ -23,6 +23,7 @@ import ( "strconv" "github.com/canonical/go-flags" + "github.com/canonical/pebble/client" ) diff --git a/internals/cli/cmd_restart.go b/internals/cli/cmd_restart.go index 70d00e9d..69c996da 100644 --- a/internals/cli/cmd_restart.go +++ b/internals/cli/cmd_restart.go @@ -16,6 +16,7 @@ package cli import ( "github.com/canonical/go-flags" + "github.com/canonical/pebble/client" ) diff --git a/internals/cli/cmd_rm.go b/internals/cli/cmd_rm.go index e5a4265f..a971658a 100644 --- a/internals/cli/cmd_rm.go +++ b/internals/cli/cmd_rm.go @@ -16,6 +16,7 @@ package cli import ( "github.com/canonical/go-flags" + "github.com/canonical/pebble/client" ) diff --git a/internals/cli/cmd_services.go b/internals/cli/cmd_services.go index 933ab371..20c0cb4a 100644 --- a/internals/cli/cmd_services.go +++ b/internals/cli/cmd_services.go @@ -18,6 +18,7 @@ import ( "fmt" "github.com/canonical/go-flags" + "github.com/canonical/pebble/client" ) diff --git a/internals/cli/cmd_signal.go b/internals/cli/cmd_signal.go index 5e1ffb70..5b58bc43 100644 --- a/internals/cli/cmd_signal.go +++ b/internals/cli/cmd_signal.go @@ -19,6 +19,7 @@ import ( "strings" "github.com/canonical/go-flags" + "github.com/canonical/pebble/client" )