cmdline

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Feb 8, 2022 License: Apache-2.0 Imports: 13 Imported by: 16

README

Cmdline

Cmdline is a Go CLI parsing and execution framework based on the idea that you create structs containing the fields you want the user to provide, and then the framework handles all the details of accepting those from the command-line or from YAML configuration files. Methods of the structs are called in user-defined phases to execute their functions.

Motivation

Go already has good command line packages, so why write another? The main reason I wrote this was that I could not find a package where it was easy to provide multiple "things" that should all be executed at once. My use case was less like git clone|add|commit|etc... and more like receptor --listen 1.2.3.4:80 --listen 4.5.6.7:8080. I don't want a single command with subcommands, I want many different configuration sections, each modifying the execution of a main program.

Subsequent work on this has made it more generally useful: you could implement a CLI with subcommands like git. And the paradigm of writing structs, receiver functions and execution phases has turned out to be fairly useful. So I don't claim this is better than existing libraries, just that it is different, and perhaps it will be handy for your particular use case.

Example

A simple example is provided in cmd/example.go. This program pretends to draw shapes. (It doesn't actually draw anything.) On the command line, the user can specify one or more of different shape types, each with their own properties. For example, the rectangle is defined with the following struct:

type rectangle struct {
	Width  float64 `description:"Width of the rectangle." required:"yes"`
	Height float64 `description:"Height of the rectangle." required:"yes"`
	Color  string  `description:"Color to use when drawing the rectangle" default:"white"`
}

This tells the library that a rectangle must be given a width and height, and can optionally also be given a color. The rectangle is registered to the cmdline system with the following call:

cl.AddConfigType("rectangle", "Rectangle Shape", rectangle{})

This tells the library that this item should be instantiated when the user gives a --rectangle command, that the help description should describe this as a Rectangle Shape, and that the rectangle struct contains the configuration details. Once registered, users can give CLI parameters like --rectangle width=3 height=4.

Once all our CLI parameter objects are registered, the main function of the library is invoked:

err := cl.ParseAndRun(os.Args[1:], []string{"Check", "Draw"}, cmdline.ShowHelpIfNoArgs)

This parses the command-line arguments, and then runs two execution phases. ShowHelpIfNoArgs means that if the user provides no command line arguments, we should show the help and exit.

An execution phase simply calls receiver methods on the configuration objects that have the same name as the phase. These methods must take no parameters and return an error value. For example, here is the rectangle's Check method:

func (r rectangle) Check() error {
	if r.Height < 0 || r.Width < 0 {
		return fmt.Errorf("rectangle height and width cannot be negative")
	}
	return nil
}

Phases are run in the order given, so the Check method will be run on all instantiated objects (that have one), and if they all succeed, then the Draw method will be run. Any error stops the whole process.

YAML config files

Users can supply a YAML config file instead of specifying all the arguments on the command line, by using --config <filename> or -c <filename>. The YAML is expected to be formatted as a map of options, with the keys corresponding to config types and the values corresponding to the field values of the config types. For example, a YAML config file for rectangle would look like this:

---
- rectangle:
    height: 3.0
    width: 4.0

This will be processed the same as if the user entered --rectangle height=3.0 width=4.0 on the command line.

Options for config types

When registering a config type with AddConfigType, the following options can be specified:

  • Required: At least one of this item must appear on the command line.
  • Singleton: Only one of this item can be instantiated.
  • Exclusive: If this item is on the command line, then it must be the only one.
  • Hidden: Do not include this item in help or command line completion.
  • Section: Group this item within a given section in the help output.

Options for configuration items

Fields within a config type struct use struct tags to control their function. The following tags can be applied to a struct field:

  • description: Description to show to the user in help output.
  • required: If true, the field must be provided.
  • default: Default value to use if the user does not specify one.
  • barevalue: If true, this field can be used as a bare value.
    (A bare value is like --item 37 rather than --item id=37.)
  • ignore: If true, do not use this field for command line processing at all.
    (This can be used for private data to be passed between phases, etc.)

Data types

The cmdline library attempts to handle a large variety of data types by using the type conversion capabilities of the reflect package. In most cases you can just declare the struct field as the type you want, and the string from the CLI will be converted to it.

If the destination field is a slice or map, then the user can either supply a JSON string on the command line itself, or use a YAML configuration file to define the list or dict. Complex data types are possible, but become cumbersome when not using YAML configuration files.

In the special case where a struct field is a []string, the library will combine multiple single-string values. For example, if you have:

type listen struct {
	IP []string `description:"IP address to listen on"`
}

then the user can do --listen ip=1.2.3.4 ip=2.3.4.5, and the struct field will be filled in with a list of the provided values.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Exclusive

func Exclusive(param *ConfigType)

Exclusive means if this config type exists, none other is allowed

func Hidden

func Hidden(param *ConfigType)

Hidden means this config type is not listed in help or bash completion

func RegisterConfigTypeForApp

func RegisterConfigTypeForApp(appName string, name string, description string, configType interface{},
	options ...func(*ConfigType))

RegisterConfigTypeForApp globally registers a new config type that can be used with a named application

func Required

func Required(param *ConfigType)

Required means this config type must be provided

func Section

func Section(section *ConfigSection) func(param *ConfigType)

Section means this config type should be listed within a section in the help

func ShowHelpIfNoArgs

func ShowHelpIfNoArgs(pro *parseAndRunOptions)

ShowHelpIfNoArgs means that if the user provides no arguments, print the help instead of doing anything

func Singleton

func Singleton(param *ConfigType)

Singleton means there can only be one of this config type

Types

type Cmdline

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

Cmdline is a command-line processor object

func NewCmdline

func NewCmdline() *Cmdline

NewCmdline constructs a new cmdline object

func (*Cmdline) AddConfigType

func (cl *Cmdline) AddConfigType(name string, description string, configType interface{}, options ...func(*ConfigType))

AddConfigType registers a new config type with the system

func (*Cmdline) AddRegisteredConfigTypes

func (cl *Cmdline) AddRegisteredConfigTypes(appName string)

AddRegisteredConfigTypes adds the registered config types for an app to the system

func (*Cmdline) BashCompletion

func (cl *Cmdline) BashCompletion() error

BashCompletion outputs a Bash script for command-line completion of the current cmdline configuration.

func (*Cmdline) ParseAndRun

func (cl *Cmdline) ParseAndRun(args []string, phases []string, options ...func(*parseAndRunOptions)) error

ParseAndRun parses the command line configuration and runs the selected actions. Phases is a list of function names that will be called on each config objects. If some objects need to be configured before others, use multiple phases. Each phase is run against all objects before moving to the next phase. The return value is the name of the exclusive object that was run, if any, or an empty string if the normal, non-exclusive command ran.

func (*Cmdline) SetOutput

func (cl *Cmdline) SetOutput(out io.Writer)

SetOutput configures where the output of a Cmdline instance will go

func (*Cmdline) ShowHelp

func (cl *Cmdline) ShowHelp() error

ShowHelp prints command line help. It does NOT exit. If out is nil, writes to stdout.

func (*Cmdline) WhatRan

func (cl *Cmdline) WhatRan() string

WhatRan returns the name of an exclusive command, if any, that ran on the last invocation of ParseAndRun

type ConfigSection

type ConfigSection struct {
	Description string
	Order       int
}

ConfigSection defines a section of the help output, for grouping commands together

type ConfigType

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

ConfigType describes a kind of parameter that can be used on the command line

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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