commandline

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Dec 6, 2020 License: MIT Imports: 5 Imported by: 0

README

commandline

A lightweight, command-oriented command line parser.

Description

Central Parser type registers Commands and invokes Handlers. Command can have optional or required Param definitions which can write directly to Go values and be analyzed in a Handler.

Commands can have Commands of their own allowing for a Command hierarchy.

Params can be Prefixed (specified by name) or Raw (specified by index and addressable by name).

Commandline's only dependency outside of stdlib is github.com/vedranvuk/strconvex which is a lightweight, reflect-based string to Go value converter used for converting command line arguments to their registered variables. Please see that package for details on how Commandline converts strings to Go values.

Examples

Example with panic functions
cl := New() // New Parser.
var barVal string // Receives value of 'bar' parameter.
// Command execution handler, in this example shared by multiple commands.
var cmdfunc = func(ctx Context) error {
	if ctx.Name() == "baz" && ctx.Arg("bat") != "bat" {
		return errors.New("I never asked for this.")
	}
	if ctx.Executed() && ctx.Name() == "baz" {
		fmt.Println("Hello from 'baz' Command.")
	}
	return nil
}
// Register a special 'global' command with an empty name used for preceeding 
// commands with params and register one prefixed param on it.
cl.MustAddCommand("", "", nil).MustAddParam("verbose", "v", "Verbose output.", false, nil)
// Register a 'foo' command with 'bar' prefixed param.
// Immediately register a 'baz' sub-command on 'foo' command with 'bat' raw paramater.
cl.MustAddCommand("foo", "Do the foo.", cmdfunc).MustAddParam("bar", "r", "Enable bar.", true, &barVal).
	MustAddCommand("baz", "Do the baz.", cmdfunc).MustAddRawParam("bat", "Enable bat.", false, nil)
// Parse parameters.
// Mark global empty command's verbose param as parsed.
// Invoke 'cmdfunc' for 'foo' command and set barVal to 'bar'.
// Invoke 'cmdfunc' for 'baz' command and set 'baz' parameter value to 'bat'.
if err := cl.Parse([]string{"--verbose", "foo", "--bar", "bar", "baz", "bat"}); err != nil {
	panic(err)
}
// Print the registered commands and their parameters.
fmt.Println(cl.Print())
// Output: Hello from 'baz' Command.

// [--verbose]     -v      Verbose output.

// foo     Do the foo.
// 		<--bar> -r      (string)        Enable bar.

// 		baz     Do the baz.
// 				[bat]   Enable bat.
Example with error functions
// Some variables that will receive values.
var (
	verbose     bool
	projectname string
	projectdir  string
)

// cmdGlobal gets invoked for "Global params" unnamed function.
func cmdGlobal(params Context) error {
	verbose = params.Parsed("verbose")
	return nil
}

// cmdCreate gets invoked for "Create project" command.
func cmdCreate(params Context) error {
	CreateProject(projectname, projectdir)
	return nil
}

// Create new parser. 
parser := New()

// Parser allows for a single unnamed command in root command definitions to
// allow the command line not to start with a command but parameters instead.
// If it is registered it must be the root command of all commands.
//
// Register a special "global flags" handler command that is automatically
// invoken if any of it's flags is specified by command line arguments and
// skipped if no "global flags" is given in arguments and the command line
// starts with a command.
cmd, err := parser.AddCommand("", "Global params", cmdGlobal)

// Register an optional "verbose" param on "global flags" command.
// It will not write to any Go value as pointer to one is nil.
cmd.AddParam("verbose", "v", "Be more verbose.", false, nil)

// Register a sub command for the "global flags" command so it can be invoken
// via arguments regardless if "global flags" executed.
cmd, err := cmd.AddCommand("create" "Create a project", cmdCreate)

// Add a prefixed parameter to "Create project" command that is required and
// converts an argument following the param to registered Go value projectname.
cmd.AddParam("name", "n", "Project name", true, &projectname)

// Add an optional raw param that isn't prefixed but is instead treated as a
// param value itself.
cmd.AddRawParam("directory", "Specify project directory", false, &projectdir)

// Parse command line, valid one would be "-v create --name myproject /home/me/myproject".
if err := parser.Parse(os.Args[1:]); err != nil {
	log.Fatal(err)
}

Status

Working as intended. No API changes except additions planned.

What's left:

  • Maybe support complex structures as parameters.
  • Maybe go:generate Parser definitions from Go composites.
  • Maybe go:generate command handlers from a Parser instance.

License

MIT

See included LICENSE file.

Documentation

Overview

Package commandline implements a command line parser.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoArgs is returned by Parse if no arguments were specified on
	// command line and there are defined Commands or Params.
	ErrNoArgs = errors.New("commandline: no arguments")
	// ErrInvalidName is returned by Add* methods when an invalid Command,
	// Param long or Param short name is specified.
	ErrInvalidName = errors.New("commandline: invalid name")
	// ErrInvalidValue is returned by Add* and Parse methods if an invalid
	// parameter is given for a Param value, i.e. not a valid Go value pointer.
	ErrInvalidValue = errors.New("commandline: invalid value")
)

Functions

This section is empty.

Types

type Command

type Command struct {
	Params   // Params are this Command's Params.
	Commands // Commands are this Command's Commands.
	// contains filtered or unexported fields
}

Command is a Command definition.

type CommandFunc

type CommandFunc = func(Context) error

CommandFunc is a prototype of a function that handles the event of a Command being parsed from command line arguments.

CommandFuncs of all Commands in the chain parsed on command line are visited during Parser.Parse(). Only the last matched command is marked as executed and can be discerned from visited CommandFuncs using Context.Executed().

If a CommandFunc returns a non-nil error further calling of parsed Commands CommandFuncs is aborted and the error is propagated to Parse method.

type Commands

type Commands struct {
	// contains filtered or unexported fields
}

Commands holds a set of Commands with a unique name.

func (*Commands) AddCommand

func (c *Commands) AddCommand(name, help string, f CommandFunc) (*Command, error)

AddCommand registers a new Command under specified name and help text that invokes f when parsed from arguments if it is not nil. Name is the only required parameter.

If Commands is the root set in a Parser it can register a single Command with an empty name to be an unnamed container in a global params pattern.

If a registration error occurs it is returned with a nil *Command.

func (*Commands) GetCommand

func (c *Commands) GetCommand(name string) (cmd *Command, ok bool)

GetCommand returns a *Command by name if found and truth if found.

func (*Commands) MustAddCommand added in v0.0.2

func (c *Commands) MustAddCommand(name, help string, f CommandFunc) *Command

MustAddCommand is like AddCommand except the function panics on error. Returns added *Command.

func (*Commands) MustGetCommand added in v0.0.2

func (c *Commands) MustGetCommand(name string) *Command

MustGetCommand is like GetCommand but panics if Command is not found.

type Context added in v0.0.3

type Context interface {
	// Name returns the name of Command which this handler was executed for.
	Name() string
	// Executed returns if this Command was the last matched Command and is
	// considered as executed. Matched Commands in the chain leading up to
	// last Command specified on command line are not marked as executed.
	//
	// All CommandFuncs defined for Commands in the command chain parsed from
	// command line arguments are visited and this property discerns the visited
	// Commands from the executed Command.
	Executed() bool
	// Parsed returns if the parameter under specified long name was parsed.
	// If the parameter under specified long name was not defined returns false.
	Parsed(string) bool
	// Arg returns the argument of parameter under specified long name if the
	// parameter is prefixed, or name if the parameter is raw.
	// If parameter was not parsed an empty string is returned.
	Arg(string) string
	// Args returns a slice of arguments passed to Command in the order as they
	// were parsed if Command has no defined parameters. It returns an empty
	// slice if Command has one or more defined parameters, prefixed or raw.
	Args() []string
	// Print prints sub Commands of the Command this Context belongs to.
	Print() string
}

Context is a CommandFunc context that provides info about Command execution.

type Param

type Param struct {
	// contains filtered or unexported fields
}

Param defines a Command parameter contained in a Params.

type Params

type Params struct {
	// contains filtered or unexported fields
}

A Params defines a set of Command Params unique by long name.

func (*Params) AddParam

func (p *Params) AddParam(long, short, help string, required bool, value interface{}) error

AddParam registers a new Param in these Params.

Long param name is required, short is optional and can be empty, as is help.

If required is specified value must be a pointer to a supported Go value which will be updated to a value parsed from an argument following param. If a required Param or its' value is not found in command line args an error is returned.

If Param is not marked as required, specifying a value parameter is optional but dictates that: If nil, a value for the Param will not be parsed from args. If valid, the parser will parse the argument following the Param into it.

If an error occurs Param is not registered.

func (*Params) AddRawParam

func (p *Params) AddRawParam(name, help string, required bool, value interface{}) error

AddRawParam registers a raw Param under specified name which must be unique in long Params names. Raw params can only be defined after prefixed params or other raw params. Calls to AddParam after AddRawParam will error.

Parsed arguments are applied to registered raw Params in order as they are defined. If value is a pointer to a valid Go value argument will be converted to that Go value. Specifying a value is optional and if nil, parsed argument will not be parsed into the value.

Marking a raw param as required does not imply that value must not be nil as is in prefixed params. Required flag solely returns a parse error if required raw param was not parsed and value is set only if non-nil.

A single non-required raw Param is allowed and it must be the last one.

If an error occurs it is returned and the Param is not registered.

func (*Params) MustAddParam added in v0.0.2

func (p *Params) MustAddParam(long, short, help string, required bool, value interface{}) *Command

MustAddParam is like AddParam except the function panics on error. Returns a Command that the param was added to.

func (*Params) MustAddRawParam added in v0.0.2

func (p *Params) MustAddRawParam(name, help string, required bool, value interface{}) *Command

MustAddRawParam is like AddRawParam except the function panics on error. Returns a Command that the param was added to.

type Parser

type Parser struct {

	// Commands is the root command set.
	Commands
	// contains filtered or unexported fields
}

Parser is a command line parser. Its' Parse method is to be invoked with a slice of command line arguments passed to program. For example:

err := Parser.Parse(os.Args[1:])

It is command oriented, meaning that one or more Command instances can be defined in Parser's Commands which when parsed from command line arguments invoke CommandFuncs registered for those Command instances. Command can have its' own Commands so a Command hierarchy can be defined.

Root Commands, as an exception, allow for one Command with an empty name to be defined. This is to allow that program args need not start with a Command and to allow Params to be passed first which can act as "global". e.g. "--verbose list users".

Command can have one or more Param instances defined in its' Params which can have names, help text, be required or optional and have an optional pointer to a Go value which is written from a value following Param in command line arguments.

If a pointer to a Go value is registered with a Param, the Param will require an argument following it that the parser will try to convert to the Go value registered with Param. Otherwise the Param will act as a simple flag which can be checked if parsed in the Command handler by checking the result of handler's Context.Parsed() method.

Parser supports prefixed and raw params which can be combined on a Command with a caveat that the Command that has one or more raw params registered cannot have sub-Commands because of ambiguities in parsing command names and raw parameters as well as the fact that one last raw param can be optional.

Prefixed params are explicitly addressed on a command line and can have short and long forms. They can be marked optional or required and be registered in any order, but must be defined before any raw params.

Short Param names have the "-" prefix, can be one character long and can be combined together following the short form prefix if none of the combined Params require a Param Value. All combined short params must all be optional.

Long Param names have the "--" prefix and cannot be combined.

Raw params are not addressed but are instead matched against registered raw Params in order of registration as they appear on command line, respectively.

Prefixed and raw params can both be registered for a Command but raw params must be registered last and specified after prefixed Params on the command line. e.g. "rmdir -v /home/me/stuff" where "rmdir" is a command, "-v" is a prefixed param and "/home/me/stuff" is a raw parameter.

If Params are defined as optional they do not cause a parse error if not parsed from program args and return a parse error if defined as required and not parsed from command line.

For specifics on how Params are parsed see AddParam and AddRawParam help.

Commands can have a CommandFunc registered optionaly so that a Command can serve solely as sub-Command selector. For more details see CommandFunc.

If no Params were defined on a Command all command line arguments following the command invocation will be passed to Command handler via Params.RawArgs.

If no params were defined on a Command and the command has no CommandFunc registered an error is returned.

Example
cl := New()
var barVal string
var cmdfunc = func(ctx Context) error {
	if ctx.Executed() && ctx.Name() == "baz" {
		fmt.Println("Hello from 'baz' Command.")
	}
	return nil
}
cl.MustAddCommand("", "", nil).MustAddParam("verbose", "v", "Verbose output.", false, nil)
cl.MustAddCommand("foo", "Do the foo.", nil).MustAddParam("bar", "r", "Enable bar.", true, &barVal).
	MustAddCommand("baz", "Do the baz.", cmdfunc).MustAddRawParam("bat", "Enable bat.", false, nil)
if err := cl.Parse([]string{"--verbose", "foo", "--bar", "bar", "baz", "bat"}); err != nil {
	panic(err)
}
fmt.Println(cl.Print())

func New

func New() *Parser

New returns a new instance of *Parser.

func (*Parser) Parse

func (p *Parser) Parse(args []string) error

Parse parses specified args, usually invoked as "Parse(os.Args[1:])". If a parse error occurs or an invoked Command handler returns an error it is returned. Returns ErrNoArgs if args are empty and there are defined Commands or Params.

func (Parser) Print

func (p Parser) Print() string

Print prints the Parser as currently configured. Returns output suitable for terminal display.

Jump to

Keyboard shortcuts

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