Desertbit/grumble

From NovaOrdis Knowledge Base
Revision as of 05:29, 23 November 2024 by Ovidiu (talk | contribs) (→‎Context)
Jump to navigation Jump to search

External

Internal

Overview

Concepts

Context

grumble.Context is passed to a command's Run function as argument. The context contains the values for flags and arguments for one command run instance, and it passed to a command's Run function.

Flags

Flag Types

Arguments

The arguments that don't have a grumble.Default() ArgOption are mandatory and must be specified on command line.

Mandatory arguments not allowed after the optional ones.

Argument Types

Command

The values for the flags and arguments come via the Context instance passed to the command's Run function (func(c *grumble.Context) error).

Programming Model

Define an app

app := grumble.New(&grumble.Config{
	Name:                  "someapp",
	Description:           "A grumble app",
	HistoryFile:           "/tmp/someapp.history",
	Prompt:                "smapp> ",
	PromptColor:           color.New(color.FgBlue, color.Bold),
	HelpHeadlineColor:     color.New(color.FgBlack, color.Bold),
	HelpHeadlineUnderline: true,
	HelpSubCommands:       true,
	Flags: func(f *grumble.Flags) {
		// App-level flags
	},
})

TODO: more about app-level flags.

Define a Number of Commands

gc := &grumble.Command{
	Name:     "create",
	Help:     "creates a widget.",
	LongHelp: "creates a widget with the specified color, size. The widget is disabled by default.",
	Aliases:  []string{"c"},
	Flags: func(f *grumble.Flags) {
		f.String("c", "color", "blue", "A color")
		f.Int("s", "size", 10, "A size")
		f.Bool("e", "enabled", false, "Whether is enabled or disabled by default")
	},
	Args: func(a *grumble.Args) {
		a.String("arg1", "First string arg") // no Default, mandatory argument
		a.Int("arg2", "Second int arg", grumble.Default(20))
		a.Bool("arg3", "Third bool arg", grumble.Default(true))
	},
	Run: func(c *grumble.Context) error {
		clr := c.Flags.String("color")
		size := c.Flags.Int("size")
		enabled := c.Flags.Bool("enabled")
		arg1 := c.Args.String("arg1")
		arg2 := c.Args.Int("arg2")
		arg3 := c.Args.Bool("arg3")
		_, err := c.App.Printf("creating a %s widget of size %d, enabled: %t [%v, %v, %v] ...\n", clr, size, enabled, arg1, arg2, arg3)
		if err != nil {
			return err
		}
		return nil
	},
}

Add Commands to app

app.AddCommand(gc)

Run the app

To handle the errors by yourself:

err := app.Run()

To have the errors handled for you:

grumble.Main(app)

Run an Individual Command Programmatically

app.RunCommand([]string{"somecommand", "--someflag", "some value")})

Unit Testing Commands

These options do not capture the command output, just side effects:

Option 1

command := somepackage.SomeCommand(...)
app := grumble.New(&grumble.Config{Name: "test"})
app.AddCommand(command)
args := []string{
    "somecommand",
    "--arg1", "test1",
    "--arg2", "test2",
}
err := app.RunCommand(args)

Option 2

In this case, a flag must be registered, even if it has a zero value, otherwise the attempt to get the flag will panic the runtime.

flags := map[string]*grumble.FlagMapItem{
	"arg1":    return &grumble.FlagMapItem{Value: arg1},
	"arg2":    return &grumble.FlagMapItem{Value: arg2},
}
ctx := &grumble.Context{
	Flags:   flags,
	Context: context.Background(),
}
command := somepackage.SomeCommand(...)
err := command.Run(ctx)

Capture and Test Output