modalflag

package
v0.24.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2023 License: GPL-3.0, GPL-3.0 Imports: 5 Imported by: 0

Documentation

Overview

Package modalflag is a wrapper for the flag package in the Go standard library. It provides a convenient method of handling program modes (and sub-modes) and allows different flags for each mode.

At it's simplest it can be used as a replacement for the flag package, with some differences. Whereas, with flag.FlagSet you call Parse() with the array of strings as the only argument, with modalflag you first NewArgs() with the array of arguments and then Parse() with no arguments. For example (note that no error handling of the Parse() function is shown here):

md = Modes{Output: os.Stdout}
md.NewArgs(os.Args[1:])
_, _ = md.Parse()

The reason for his difference is to allow effective parsing of modes and sub-modes. We'll come to program modes in a short while.

In the above example, once the arguments have been parsed, non-flag arguments can be retrieved with the RemainingArgs() or GetArg() function. For example, handling exactly one argument:

switch len(md.RemainingArgs()) {
case 0:
	return fmt.Errorf("argument required")
case 1:
	Process(md.GetArg(0))
default:
	return fmt.Errorf("too many arguments")
}

Adding flags is similar to the flag package. Adding a boolean flag:

verbose := md.AddBool("verbose", false, "print additional log messages")

These flag functions return a pointer to a variable of the specified type. The initial value of these variables if the default value, the second argument in the function call above. The Parse() function will set these values appropriately according what the user has requested, for example:

if *verbose {
	fmt.Println(additionalLogMessage)
}

The most important difference between the standard flag package and the modalflag package is the ability of the latter to handle "modes". In this context, a mode is a special command line argument that when specified, puts the program into a different mode of operation. The best and most relevant example I can think of is the go command. The go command has many different modes: build, doc, get, test, etc. Each of these modes are different enough to require a different set of flags and expected arguments.

The modalflag package handles sub-modes with the AddSubModes() function. This function takes any number of string arguments, each one the name of a mode.

md.AddSubModes("run", "test", "debug")

For simplicity, all sub-mode comparisons are case insensitive.

Subsequent calls to Parse() will then process flags in the normal way but unlike the regular flag.Parse() function will check to see if the first argument after the flags is one of these modes. If it is, then the RemainingArgs() function will return all the arguments after the flags AND the mode selector.

So, for example:

md.Parse()
switch md.Mode() {
	case "RUN":
		runMode(*verbose)
	default:
		fmt.Printf("%s not yet implemented", md.Mode())
}

Now that we've decided on what mode we're in, we can again call Parse() to process the remaining arguments. This example shows how we can handle return state and errors from the Parse() function:

func runMode(verbose bool) {
	md.NewMode()
	md.AddDuration("runtime", time.ParseDuration("10s"), "max run time")
	p, err := md.Parse
	switch p {
		case ParseError:
			fmt.Println(err)
			return
		case ParseHelp:
			return
	}
	doRun(md.RemainingArguments)
}

This second call to Parse() will check for any additional flags and any further sub-modes (none in this example).

We can chain modes together as deep as we want. For example, the "test" mode added above could be divided into several different modes:

md = Modes{Output: os.Stdout}
md.NewArgs(os.Args[1:])
md.AddSubModes("run", "test", "debug")
_, _ = md.Parse()
switch md.Mode() {
	case "TEST":
		md.NewMode()
		md.AddSubModes("A", "B", "C")
		_, _ = md.Parse()
		switch md.Mode() {
			case "A":
				testA()
			case "B":
				testB()
			case "C":
				testC()
		}
	default:
		fmt.Printf("%s not yet implemented", md.Mode())
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Modes

type Modes struct {
	// where to print output (help messages etc). defaults to os.Stdout
	Output io.Writer
	// contains filtered or unexported fields
}

Modes provides an easy way of handling command line arguments. The Output field should be specified before calling Parse() or you will not see any help messages.

func (*Modes) AddBool

func (md *Modes) AddBool(name string, value bool, usage string) *bool

AddBool flag for next call to Parse().

func (*Modes) AddDefaultSubMode

func (md *Modes) AddDefaultSubMode(defSubMode string)

AddDefaultSubMode to list of sub-modes.

func (*Modes) AddDuration

func (md *Modes) AddDuration(name string, value time.Duration, usage string) *time.Duration

AddDuration flag for next call to Parse().

func (*Modes) AddFloat64

func (md *Modes) AddFloat64(name string, value float64, usage string) *float64

AddFloat64 flag for next call to Parse().

func (*Modes) AddInt

func (md *Modes) AddInt(name string, value int, usage string) *int

AddInt flag for next call to Parse().

func (*Modes) AddInt64

func (md *Modes) AddInt64(name string, value int64, usage string) *int64

AddInt64 flag for next call to Parse().

func (*Modes) AddString

func (md *Modes) AddString(name string, value string, usage string) *string

AddString flag for next call to Parse().

func (*Modes) AddSubModes

func (md *Modes) AddSubModes(submodes ...string)

AddSubModes to list of submodes for next parse. The first sub-mode in the list is considered to be the default sub-mode. If you need more control over this, AddDefaultSubMode() can be used.

Note that sub-mode comparisons are case insensitive.

func (*Modes) AddUint

func (md *Modes) AddUint(name string, value uint, usage string) *uint

AddUint flag for next call to Parse().

func (*Modes) AddUint64

func (md *Modes) AddUint64(name string, value uint64, usage string) *uint64

AddUint64 flag for next call to Parse().

func (*Modes) AdditionalHelp

func (md *Modes) AdditionalHelp(help string)

AdditionalHelp allows you to add extensive help text to be displayed in addition to the regular help on available flags.

func (*Modes) GetArg

func (md *Modes) GetArg(i int) string

GetArg returns the numbered argument that isn't a flag or listed sub-mode.

func (*Modes) MinMax added in v0.12.1

func (md *Modes) MinMax(min int, max int)

MinMax specifies the minimum and maximum number of non-flags arguments that are required.

func (*Modes) Mode

func (md *Modes) Mode() string

Mode returns the last mode to be encountered.

func (*Modes) NewArgs

func (md *Modes) NewArgs(args []string)

NewArgs with a string of arguments (from the command line for example).

func (*Modes) NewMode

func (md *Modes) NewMode()

NewMode indicates that further arguments should be considered part of a new mode.

func (*Modes) Parse

func (md *Modes) Parse() (ParseResult, error)

Parse the top level layer of arguments. Returns a value of ParseResult. The idiomatic usage is as follows:

p, err := md.Parse()
switch p {
case modalflag.ParseHelp:
	// help message has already been printed
	return
case modalflag.ParseError:
	printError(err)
	return
}

Help messages are handled automatically by the function. The return value ParseHelp is to help you guide your program appropriately. The above pattern suggests it should be treated similarly to an error and without the need to display anything further to the user.

Note that the Output field of the Modes struct *must* be specified in order for any help messages to be visible. The most common and useful value of the field is os.Stdout.

func (*Modes) Parsed

func (md *Modes) Parsed() bool

Parsed returns false if Parse() has not yet been called since either a call to NewArgs() or NewMode(). Note that, a Modes struct is considered to be Parsed() even if Parse() results in an error.

func (*Modes) Path

func (md *Modes) Path() string

Path returns a string all the modes encountered during parsing.

func (*Modes) RemainingArgs

func (md *Modes) RemainingArgs() []string

RemainingArgs after a call to Parse() ie. arguments that aren't flags or a listed sub-mode.

func (*Modes) String

func (md *Modes) String() string

func (*Modes) Visit

func (md *Modes) Visit(fn func(flag string))

Visit visits the flags in lexicographical order, calling fn for each. It visits only those flags that have been set.

type ParseResult

type ParseResult int

ParseResult is returned from the Parse() function.

const (
	// Continue with command line processing. How this result should be
	// interpreted depends on the context, which the caller of the Parse()
	// function knows best. However, generally we can say that if sub-modes
	// were specified in the preceding call to NewMode() then the Mode field
	// of the Modes struct should be checked.
	ParseContinue ParseResult = iota

	// The wrong number of non-flag arguments have been specified.
	ParseTooFewArgs
	ParseTooManyArgs

	// Help was requested and has been printed.
	ParseHelp

	// an error has occurred and is returned as the second return value.
	ParseError
)

a list of valid ParseResult values.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL