Skip to content

Commit

Permalink
cli: remove AddHelpCategory and improve AddCommand
Browse files Browse the repository at this point in the history
 * AddHelpCategory() was removed in favor of an exported
   HelpCategories global.
 * AddCommand() now accepts a CmdInfo struct as its sole
   argument.
  • Loading branch information
anpep committed Jun 14, 2023
1 parent 8aa94a8 commit 34d185d
Show file tree
Hide file tree
Showing 23 changed files with 220 additions and 114 deletions.
104 changes: 43 additions & 61 deletions internals/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
// 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 {
Expand Down Expand Up @@ -192,53 +174,53 @@ 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)
}
if x, ok := obj.(parserSetter); ok {
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
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
Expand All @@ -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
Expand Down
8 changes: 7 additions & 1 deletion internals/cli/cmd_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}
8 changes: 7 additions & 1 deletion internals/cli/cmd_autostart.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
21 changes: 15 additions & 6 deletions internals/cli/cmd_changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion internals/cli/cmd_checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}
15 changes: 11 additions & 4 deletions internals/cli/cmd_enter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
14 changes: 10 additions & 4 deletions internals/cli/cmd_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
})
}
28 changes: 14 additions & 14 deletions internals/cli/cmd_help.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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"},
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion internals/cli/cmd_help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand Down
Loading

0 comments on commit 34d185d

Please sign in to comment.