writ

package module
v0.8.9 Latest Latest
Warning

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

Go to latest
Published: Feb 11, 2016 License: MIT Imports: 9 Imported by: 15

README

Build Status Coverage Report Card GoDoc

Writ

Overview

Writ is a flexible option parser with thorough test coverage. It's meant to be simple and "just work". Applications using writ look and behave similar to common GNU command-line applications, making them comfortable for end-users.

Writ implements option decoding with GNU getopt_long conventions. All long and short-form option variations are supported: --with-x, --name Sam, --day=Friday, -i FILE, -vvv, etc.

Help output generation is supported using text/template. The default template can be overriden with a custom template.

API Promise

Minor breaking changes may occur prior to the 1.0 release. After the 1.0 release, the API is guaranteed to remain backwards compatible.

Basic Use

Please see the godocs for additional information.

This example uses writ.New() to build a command from the Greeter's struct fields. The resulting *writ.Command decodes and updates the Greeter's fields in-place. The Command.ExitHelp() method is used to display help content if --help is specified, or if invalid input arguments are received.

Source:

package main

import (
    "fmt"
    "github.com/bobziuchkovski/writ"
    "strings"
)

type Greeter struct {
    HelpFlag  bool   `flag:"help" description:"Display this help message and exit"`
    Verbosity int    `flag:"v, verbose" description:"Display verbose output"`
    Name      string `option:"n, name" default:"Everyone" description:"The person or people to greet"`
}

func main() {
    greeter := &Greeter{}
    cmd := writ.New("greeter", greeter)
    cmd.Help.Usage = "Usage: greeter [OPTION]... MESSAGE"
    cmd.Help.Header = "Greet users, displaying MESSAGE"

    // Use cmd.Decode(os.Args[1:]) in a real application
    _, positional, err := cmd.Decode([]string{"-vvv", "--name", "Sam", "How's it going?"})
    if err != nil || greeter.HelpFlag {
        cmd.ExitHelp(err)
    }

    message := strings.Join(positional, " ")
    fmt.Printf("Hi %s! %s\n", greeter.Name, message)
    if greeter.Verbosity > 0 {
        fmt.Printf("I'm feeling re%slly chatty today!\n", strings.Repeat("a", greeter.Verbosity))
    }

    // Output:
    // Hi Sam! How's it going?
    // I'm feeling reaaally chatty today!
}

Help output:

Usage: greeter [OPTION]... MESSAGE
Greet users, displaying MESSAGE

Available Options:
  --help                    Display this help message and exit
  -v, --verbose             Display verbose output
  -n, --name=ARG            The person or people to greet
Subcommands

Please see the godocs for additional information.

This example demonstrates subcommands in a busybox style. There's no requirement that subcommands implement the Run() method shown here. It's just an example of how subcommands might be implemented.

Source:

package main

import (
    "errors"
    "github.com/bobziuchkovski/writ"
    "os"
)

type GoBox struct {
    Link Link `command:"ln" alias:"link" description:"Create a soft or hard link"`
    List List `command:"ls" alias:"list" description:"List directory contents"`
}

type Link struct {
    HelpFlag bool `flag:"h, help" description:"Display this message and exit"`
    Symlink  bool `flag:"s" description:"Create a symlink instead of a hard link"`
}

type List struct {
    HelpFlag   bool `flag:"h, help" description:"Display this message and exit"`
    LongFormat bool `flag:"l" description:"Use long-format output"`
}

func (g *GoBox) Run(p writ.Path, positional []string) {
    // The user didn't specify a subcommand.  Give them help.
    p.Last().ExitHelp(errors.New("COMMAND is required"))
}

func (l *Link) Run(p writ.Path, positional []string) {
    if l.HelpFlag {
        p.Last().ExitHelp(nil)
    }
    if len(positional) != 2 {
        p.Last().ExitHelp(errors.New("ln requires two arguments, OLD and NEW"))
    }
    // Link operation omitted for brevity.  This would be os.Link or os.Symlink
    // based on the l.Symlink value.
}

func (l *List) Run(p writ.Path, positional []string) {
    if l.HelpFlag {
        p.Last().ExitHelp(nil)
    }
    // Listing operation omitted for brevity.  This would be a call to ioutil.ReadDir
    // followed by conditional formatting based on the l.LongFormat value.
}

func main() {
    gobox := &GoBox{}
    cmd := writ.New("gobox", gobox)
    cmd.Help.Usage = "Usage: gobox COMMAND [OPTION]... [ARG]..."
    cmd.Subcommand("ln").Help.Usage = "Usage: gobox ln [-s] OLD NEW"
    cmd.Subcommand("ls").Help.Usage = "Usage: gobox ls [-l] [PATH]..."

    path, positional, err := cmd.Decode(os.Args[1:])
    if err != nil {
        // Using path.Last() here ensures the user sees relevant help for their
        // command selection
        path.Last().ExitHelp(err)
    }

    // At this point, cmd.Decode() has already decoded option values into the gobox
    // struct, including subcommand values.  We just need to dispatch the command.
    // path.String() is guaranteed to represent the user command selection.
    switch path.String() {
    case "gobox":
        gobox.Run(path, positional)
    case "gobox ln":
        gobox.Link.Run(path, positional)
    case "gobox ls":
        gobox.List.Run(path, positional)
    default:
        panic("BUG: Someone added a new command and forgot to add it's path here")
    }
}

Help output, gobox:

Usage: gobox COMMAND [OPTION]... [ARG]...

Available Commands:
  ln                        Create a soft or hard link
  ls                        List directory contents

Help output, gobox ln:

Usage: gobox ln [-s] OLD NEW

Available Options:
  -h, --help                Display this message and exit
  -s                        Create a symlink instead of a hard link

Help output, gobox ls:

Usage: gobox ls [-l] [PATH]...

Available Options:
  -h, --help                Display this message and exit
  -l                        Use long-format output
Explicit Commands and Options

Please see the godocs for additional information.

This example demonstrates explicit Command and Option creation, along with explicit option grouping. It checks the host platform and dynamically adds a --bootloader option if the example is run on Linux. The same result could be achieved by using writ.New() to construct a Command, and then adding the platform-specific option to the resulting Command directly.

Source:

package main

import (
    "github.com/bobziuchkovski/writ"
    "os"
    "runtime"
)

type Config struct {
    help       bool
    verbosity  int
    bootloader string
}

func main() {
    config := &Config{}
    cmd := &writ.Command{Name: "explicit"}
    cmd.Help.Usage = "Usage: explicit [OPTION]... [ARG]..."
    cmd.Options = []*writ.Option{
        {
            Names:       []string{"h", "help"},
            Description: "Display this help text and exit",
            Decoder:     writ.NewFlagDecoder(&config.help),
            Flag:        true,
        },
        {
            Names:       []string{"v"},
            Description: "Increase verbosity; may be specified more than once",
            Decoder:     writ.NewFlagAccumulator(&config.verbosity),
            Flag:        true,
            Plural:      true,
        },
    }

    // Note the explicit option grouping.  Using writ.New(), a single option group is
    // created for all options/flags that have descriptions.  Without writ.New(), we
    // need to create the OptionGroup(s) ourselves.
    general := cmd.GroupOptions("help", "v")
    general.Header = "General Options:"
    cmd.Help.OptionGroups = append(cmd.Help.OptionGroups, general)

    // Dynamically add --bootloader on Linux
    if runtime.GOOS == "linux" {
        cmd.Options = append(cmd.Options, &writ.Option{
            Names:       []string{"bootloader"},
            Description: "Use the specified bootloader (grub, grub2, or lilo)",
            Decoder:     writ.NewOptionDecoder(&config.bootloader),
            Placeholder: "NAME",
        })
        platform := cmd.GroupOptions("bootloader")
        platform.Header = "Platform Options:"
        cmd.Help.OptionGroups = append(cmd.Help.OptionGroups, platform)
    }

    // Decode the options
    _, _, err := cmd.Decode(os.Args[1:])
    if err != nil || config.help {
        cmd.ExitHelp(err)
    }
}

Help output, Linux:

General Options:
  -h, --help                Display this help text and exit
  -v                        Increase verbosity; may be specified more than once

Platform Options:
  --bootloader=NAME         Use the specified bootloader (grub, grub2, or lilo)

Help output, other platforms:

General Options:
  -h, --help                Display this help text and exit
  -v                        Increase verbosity; may be specified more than once

Authors

Bob Ziuchkovski (@bobziuchkovski)

License (MIT)

Copyright (c) 2016 Bob Ziuchkovski

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Documentation

Overview

Package writ implements a flexible option parser with thorough test coverage. It's meant to be simple and "just work". Applications using writ look and behave similar to common GNU command-line applications, making them comfortable for end-users.

Writ implements option decoding with GNU getopt_long conventions. All long and short-form option variations are supported: --with-x, --name Sam, --day=Friday, -i FILE, -vvv, etc.

Help output generation is supported using text/template. The default template can be overriden with a custom template.

Basics

Writ uses the Command and Option types to represent available options and subcommands. Input arguments are decoded with Command.Decode().

For convenience, the New() function can parse an input struct into a Command with Options that represent the input struct's fields. It uses struct field tags to control the behavior. The resulting Command's Decode() method updates the struct's fields in-place when option arguments are decoded.

Alternatively, Commands and Options may be created directly. All fields on these types are exported.

Options

Options are specified via the "option" and "flag" struct tags. Both represent options, but fields marked "option" take arguments, whereas fields marked "flag" do not.

Every Option must have an OptionDecoder. Writ provides decoders for most basic types, as well as some convenience types. See the NewOptionDecoder() function docs for details.

Commands

New() parses an input struct to build a top-level Command. Subcommands are supported by using the "command" field tag. Fields marked with "command" must be of struct type, and are parsed the same way as top-level commands.

Help Output

Writ provides methods for generating help output. Command.WriteHelp() generates help content and writes to a given io.Writer. Command.ExitHelp() writes help content to stdout or stderr and terminates the program.

Writ uses a template to generate the help content. The default template mimics --help output for common GNU programs. See the documentation of the Help type for more details.

Field Tag Reference

The New() function recognizes the following combinations of field tags:

Option Fields:
	- option (required): a comma-separated list of names for the option
	- description: the description to display for help output
	- placeholder: the placeholder value to use next to the option names (e.g. FILE)
	- default: the default value for the field
	- env: the name of an environment variable, the value of which is used as a default for the field

Flag fields:
	- flag (required): a comma-separated list of names for the flag
	- description: the description to display for help output

Command fields:
	- name (required): a name for the command
	- aliases: a comma-separated list of alias names for the command
	- description: the description to display for help output

If both "default" and "env" are specified for an option field, the environment variable is consulted first. If the environment variable is present and decodes without error, that value is used. Otherwise, the value for the "default" tag is used. Values specified via parsed arguments take precedence over both types of defaults.

Example (Basic)

This example uses writ.New() to build a command from the Greeter's struct fields. The resulting *writ.Command decodes and updates the Greeter's fields in-place. The Command.ExitHelp() method is used to display help content if --help is specified, or if invalid input arguments are received.

package main

import (
	"fmt"
	"github.com/bobziuchkovski/writ"
	"strings"
)

type Greeter struct {
	HelpFlag  bool   `flag:"help" description:"Display this help message and exit"`
	Verbosity int    `flag:"v, verbose" description:"Display verbose output"`
	Name      string `option:"n, name" default:"Everyone" description:"The person or people to greet"`
}

// This example uses writ.New() to build a command from the Greeter's
// struct fields.  The resulting *writ.Command decodes and updates the
// Greeter's fields in-place.  The Command.ExitHelp() method is used to
// display help content if --help is specified, or if invalid input
// arguments are received.
func main() {
	greeter := &Greeter{}
	cmd := writ.New("greeter", greeter)
	cmd.Help.Usage = "Usage: greeter [OPTION]... MESSAGE"
	cmd.Help.Header = "Greet users, displaying MESSAGE"

	// Use cmd.Decode(os.Args[1:]) in a real application
	_, positional, err := cmd.Decode([]string{"-vvv", "--name", "Sam", "How's it going?"})
	if err != nil || greeter.HelpFlag {
		cmd.ExitHelp(err)
	}

	message := strings.Join(positional, " ")
	fmt.Printf("Hi %s! %s\n", greeter.Name, message)
	if greeter.Verbosity > 0 {
		fmt.Printf("I'm feeling re%slly chatty today!\n", strings.Repeat("a", greeter.Verbosity))
	}

	
Output:

Example (Convenience)

This example demonstrates some of the convenience features offered by writ. It uses writ's support for io types and default values to ensure the Input and Output fields are initialized. These default to stdin and stdout due to the default:"-" field tags. The user may specify -i or -o to read from or write to a file. Similarly, the Replacements map is initialized with key=value pairs for every -r/--replace option the user specifies.

package main

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/bobziuchkovski/writ"
	"io"
	"os"
	"strings"
)

type ReplacerCmd struct {
	Input        io.Reader         `option:"i" description:"Read input values from FILE (default: stdin)" default:"-" placeholder:"FILE"`
	Output       io.WriteCloser    `option:"o" description:"Write output to FILE (default: stdout)" default:"-" placeholder:"FILE"`
	Replacements map[string]string `option:"r, replace" description:"Replace occurrences of ORIG with NEW" placeholder:"ORIG=NEW"`
	HelpFlag     bool              `flag:"h, help" description:"Display this help text and exit"`
}

// This example demonstrates some of the convenience features offered by writ.
// It uses writ's support for io types and default values to ensure the Input
// and Output fields are initialized.  These default to stdin and stdout due
// to the default:"-" field tags.  The user may specify -i or -o to read from
// or write to a file.  Similarly, the Replacements map is initialized with
// key=value pairs for every -r/--replace option the user specifies.
func main() {
	replacer := &ReplacerCmd{}
	cmd := writ.New("replacer", replacer)
	cmd.Help.Usage = "Usage: replacer [OPTION]..."
	cmd.Help.Header = "Perform text replacement according to the -r/--replace option"
	cmd.Help.Footer = "By default, replacer reads from stdin and write to stdout.  Use the -i and -o options to override."

	// Decode input arguments
	_, positional, err := cmd.Decode(os.Args[1:])
	if err != nil || replacer.HelpFlag {
		cmd.ExitHelp(err)
	}
	if len(positional) > 0 {
		cmd.ExitHelp(errors.New("replacer does not accept positional arguments"))
	}

	// At this point, the ReplacerCmd's Input, Output, and Replacements fields are all
	// known-valid and initialized, so we can run the replacement.
	err = replacer.Replace()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(1)
	}
}

// The Replace() method performs the input/output replacements, but is
// not relevant to the example itself.
func (r ReplacerCmd) Replace() error {
	var pairs []string
	for k, v := range r.Replacements {
		pairs = append(pairs, k, v)
	}
	replacer := strings.NewReplacer(pairs...)
	scanner := bufio.NewScanner(r.Input)
	for scanner.Scan() {
		line := scanner.Text()
		_, err := io.WriteString(r.Output, replacer.Replace(line)+"\n")
		if err != nil {
			return err
		}
	}
	err := scanner.Err()
	if err != nil {
		return err
	}
	return r.Output.Close()

	// Help Output:
	// Usage: replacer [OPTION]...
	// Perform text replacement according to the -r/--replace option
	//
	// Available Options:
	//   -i FILE                   Read input values from FILE (default: stdin)
	//   -o FILE                   Write output to FILE (default: stdout)
	//   -r, --replace=ORIG=NEW    Replace occurrences of ORIG with NEW
	//   -h, --help                Display this help text and exit
	//
	// By default, replacer reads from stdin and write to stdout.  Use the -i and -o options to override.
}
Output:

Example (Explicit)

This example demonstrates explicit Command and Option creation, along with explicit option grouping. It checks the host platform and dynamically adds a --bootloader option if the example is run on Linux. The same result could be achieved by using writ.New() to construct a Command, and then adding the platform-specific option to the resulting Command directly.

package main

import (
	"github.com/bobziuchkovski/writ"
	"os"
	"runtime"
)

type Config struct {
	help       bool
	verbosity  int
	bootloader string
}

// This example demonstrates explicit Command and Option creation,
// along with explicit option grouping.  It checks the host platform
// and dynamically adds a --bootloader option if the example is run on
// Linux.  The same result could be achieved by using writ.New() to
// construct a Command, and then adding the platform-specific option
// to the resulting Command directly.
func main() {
	config := &Config{}
	cmd := &writ.Command{Name: "explicit"}
	cmd.Help.Usage = "Usage: explicit [OPTION]... [ARG]..."
	cmd.Options = []*writ.Option{
		{
			Names:       []string{"h", "help"},
			Description: "Display this help text and exit",
			Decoder:     writ.NewFlagDecoder(&config.help),
			Flag:        true,
		},
		{
			Names:       []string{"v"},
			Description: "Increase verbosity; may be specified more than once",
			Decoder:     writ.NewFlagAccumulator(&config.verbosity),
			Flag:        true,
			Plural:      true,
		},
	}

	// Note the explicit option grouping.  Using writ.New(), a single option group is
	// created for all options/flags that have descriptions.  Without writ.New(), we
	// need to create the OptionGroup(s) ourselves.
	general := cmd.GroupOptions("help", "v")
	general.Header = "General Options:"
	cmd.Help.OptionGroups = append(cmd.Help.OptionGroups, general)

	// Dynamically add --bootloader on Linux
	if runtime.GOOS == "linux" {
		cmd.Options = append(cmd.Options, &writ.Option{
			Names:       []string{"bootloader"},
			Description: "Use the specified bootloader (grub, grub2, or lilo)",
			Decoder:     writ.NewOptionDecoder(&config.bootloader),
			Placeholder: "NAME",
		})
		platform := cmd.GroupOptions("bootloader")
		platform.Header = "Platform Options:"
		cmd.Help.OptionGroups = append(cmd.Help.OptionGroups, platform)
	}

	// Decode the options
	_, _, err := cmd.Decode(os.Args[1:])
	if err != nil || config.help {
		cmd.ExitHelp(err)
	}

	// Help Output, Linux:
	// General Options:
	//   -h, --help                Display this help text and exit
	//   -v                        Increase verbosity; may be specified more than once
	//
	// Platform Options:
	//   --bootloader=NAME         Use the specified bootloader (grub, grub2, or lilo)
	//
	// Help Output, other platforms:
	// General Options:
	//   -h, --help                Display this help text and exit
	//   -v                        Increase verbosity; may be specified more than once

}
Output:

Example (Subcommand)

This example demonstrates subcommands in a busybox style. There's no requirement that subcommands implement the Run() method shown here. It's just an example of how subcommands might be implemented.

package main

import (
	"errors"
	"github.com/bobziuchkovski/writ"
	"os"
)

type GoBox struct {
	Link Link `command:"ln" alias:"link" description:"Create a soft or hard link"`
	List List `command:"ls" alias:"list" description:"List directory contents"`
}

type Link struct {
	HelpFlag bool `flag:"h, help" description:"Display this message and exit"`
	Symlink  bool `flag:"s" description:"Create a symlink instead of a hard link"`
}

type List struct {
	HelpFlag   bool `flag:"h, help" description:"Display this message and exit"`
	LongFormat bool `flag:"l" description:"Use long-format output"`
}

func (g *GoBox) Run(p writ.Path, positional []string) {
	// The user didn't specify a subcommand.  Give them help.
	p.Last().ExitHelp(errors.New("COMMAND is required"))
}

func (l *Link) Run(p writ.Path, positional []string) {
	if l.HelpFlag {
		p.Last().ExitHelp(nil)
	}
	if len(positional) != 2 {
		p.Last().ExitHelp(errors.New("ln requires two arguments, OLD and NEW"))
	}
	// Link operation omitted for brevity.  This would be os.Link or os.Symlink
	// based on the l.Symlink value.
}

func (l *List) Run(p writ.Path, positional []string) {
	if l.HelpFlag {
		p.Last().ExitHelp(nil)
	}
	// Listing operation omitted for brevity.  This would be a call to ioutil.ReadDir
	// followed by conditional formatting based on the l.LongFormat value.
}

// This example demonstrates subcommands in a busybox style.  There's no requirement
// that subcommands implement the Run() method shown here.  It's just an example of
// how subcommands might be implemented.
func main() {
	gobox := &GoBox{}
	cmd := writ.New("gobox", gobox)
	cmd.Help.Usage = "Usage: gobox COMMAND [OPTION]... [ARG]..."
	cmd.Subcommand("ln").Help.Usage = "Usage: gobox ln [-s] OLD NEW"
	cmd.Subcommand("ls").Help.Usage = "Usage: gobox ls [-l] [PATH]..."

	path, positional, err := cmd.Decode(os.Args[1:])
	if err != nil {
		// Using path.Last() here ensures the user sees relevant help for their
		// command selection
		path.Last().ExitHelp(err)
	}

	// At this point, cmd.Decode() has already decoded option values into the gobox
	// struct, including subcommand values.  We just need to dispatch the command.
	// path.String() is guaranteed to represent the user command selection.
	switch path.String() {
	case "gobox":
		gobox.Run(path, positional)
	case "gobox ln":
		gobox.Link.Run(path, positional)
	case "gobox ls":
		gobox.List.Run(path, positional)
	default:
		panic("BUG: Someone added a new command and forgot to add it's path here")
	}

	// Help output, gobox:
	// Usage: gobox COMMAND [OPTION]... [ARG]...
	//
	// Available Commands:
	//   ln                        Create a soft or hard link
	//   ls                        List directory contents
	//
	// Help output, gobox ln:
	// Usage: gobox ln [-s] OLD NEW
	//
	// Available Options:
	//   -h, --help                Display this message and exit
	//   -s                        Create a symlink instead of a hard link
	//
	// Help output, gobox ls:
	// Usage: gobox ls [-l] [PATH]...
	//
	// Available Options:
	//   -h, --help                Display this message and exit
	//   -l                        Use long-format output
}
Output:

Index

Examples

Constants

View Source
const HelpText = `` /* 1337-byte string literal not displayed */

HelpText is used by Command.WriteHelp() and Command.ExitHelp() to generate help content.

This copy of the template is used when compiling with go 1.6+. See template_legacy.go for the go < 1.6 template. Output is the same for both templates, but this one is easier to read.

Variables

View Source
var Version = struct {
	Major int
	Minor int
	Patch int
}{0, 8, 9}

Version records the writ package version.

Functions

This section is empty.

Types

type Command

type Command struct {
	// Required
	Name string

	// Optional
	Aliases     []string
	Options     []*Option
	Subcommands []*Command
	Help        Help
	Description string // Commands without descriptions are hidden
}

Command specifies program options and subcommands.

NOTE: If building a *Command directly without New(), the Help output will be empty by default. Most applications will want to set the Help.Usage and Help.CommandGroups / Help.OptionGroups fields as appropriate.

func New

func New(name string, spec interface{}) *Command

New reads the input spec, searching for fields tagged with "option", "flag", or "command". The field type and tags are used to construct a corresponding Command instance, which can be used to decode program arguments. See the package overview documentation for details.

NOTE: The spec value must be a pointer to a struct.

func (*Command) Decode

func (c *Command) Decode(args []string) (path Path, positional []string, err error)

Decode parses the given arguments according to GNU getopt_long conventions. It matches Option arguments, both short and long-form, and decodes those arguments with the matched Option's Decoder field. If the Command has associated subcommands, the subcommand names are matched and extracted from the start of the positional arguments.

To avoid ambiguity, subcommand matching terminates at the first unmatched positional argument. Similarly, option names are matched against the command hierarchy as it exists at the point the option is encountered. If command "first" has a subcommand "second", and "second" has an option "foo", then "first second --foo" is valid but "first --foo second" returns an error. If the two commands, "first" and "second", both specify a "bar" option, then "first --bar second" decodes "bar" on "first", whereas "first second --bar" decodes "bar" on "second".

As with GNU getopt_long, a bare "--" argument terminates argument parsing. All arguments after the first "--" argument are considered positional parameters.

func (*Command) ExitHelp

func (c *Command) ExitHelp(err error)

ExitHelp writes help output and terminates the program. If err is nil, the output is written to os.Stdout and the program terminates with a 0 exit code. Otherwise, both the help output and error message are written to os.Stderr and the program terminates with a 1 exit code.

func (*Command) GroupCommands

func (c *Command) GroupCommands(names ...string) CommandGroup

GroupCommands is used to build CommandGroups for help output. It searches the method receiver for the named subcommands and returns a corresponding CommandGroup. If any of the named subcommands are not found, GroupCommands panics.

func (*Command) GroupOptions

func (c *Command) GroupOptions(names ...string) OptionGroup

GroupOptions is used to build OptionGroups for help output. It searches the method receiver for the named options and returns a corresponding OptionGroup. If any of the named options are not found, GroupOptions panics.

func (*Command) Option

func (c *Command) Option(name string) *Option

Option locates options on the method receiver. It returns a match if any of the receiver's options have a matching name. Otherwise it returns nil. Options are searched only on the method receiver, not any of it's subcommands.

func (*Command) String

func (c *Command) String() string

String returns the command's name.

func (*Command) Subcommand

func (c *Command) Subcommand(name string) *Command

Subcommand locates subcommands on the method receiver. It returns a match if any of the receiver's subcommands have a matching name or alias. Otherwise it returns nil.

func (*Command) WriteHelp

func (c *Command) WriteHelp(w io.Writer) error

WriteHelp renders help output to the given io.Writer. Output is influenced by the Command's Help field. See the Help type for details.

type CommandGroup

type CommandGroup struct {
	Commands []*Command

	// Optional
	Name   string // Not displayed; for matching purposes within the template
	Header string // Displayed before the group
	Footer string // Displayed after the group
}

CommandGroup is used to customize help output. It groups related Commands for output. When New() parses an input spec, it creates a single CommandGroup for all parsed commands that have descriptions.

type Help

type Help struct {
	OptionGroups  []OptionGroup
	CommandGroups []CommandGroup

	// Optional
	Template *template.Template // Used to render output
	Usage    string             // Short message displayed at the top of output
	Header   string             // Displayed after Usage
	Footer   string             // Displayed at the end of output
}

The Help type is used for presentation purposes only, and does not affect argument parsing.

The Command.ExitHelp() and Command.WriteHelp() methods execute the template assigned to the Template field, passing the Command as input. If the Template field is nil, the writ package's default template is used.

type Option

type Option struct {
	// Required
	Names   []string
	Decoder OptionDecoder

	// Optional
	Flag        bool   // If set, the Option takes no arguments
	Plural      bool   // If set, the Option may be specified multiple times
	Description string // Options without descriptions are hidden
	Placeholder string // Displayed next to option in help output (e.g. FILE)
}

Option specifies program options and flags.

func (*Option) LongNames

func (o *Option) LongNames() []string

LongNames returns a filtered slice of the names that are longer than one rune in length.

func (*Option) ShortNames

func (o *Option) ShortNames() []string

ShortNames returns a filtered slice of the names that are exactly one rune in length.

func (*Option) String

func (o *Option) String() string

type OptionDecoder

type OptionDecoder interface {
	Decode(arg string) error
}

OptionDecoder is used for decoding Option arguments. Every Option must have an OptionDecoder assigned. New() constructs and assigns OptionDecoders automatically for supported field types.

func NewDefaulter

func NewDefaulter(decoder OptionDecoder, defaultArg string) OptionDecoder

NewDefaulter builds an OptionDecoder that implements OptionDefaulter. SetDefault calls decoder.Decode() with the value of defaultArg. If the value fails to decode, SetDefault panics.

func NewEnvDefaulter

func NewEnvDefaulter(decoder OptionDecoder, key string) OptionDecoder

NewEnvDefaulter builds an OptionDecoder that implements OptionDefaulter. SetDefault calls decoder.Decode() with the value of the environment variable named by key. If the environment variable isn't set or fails to decode, SetDefault checks if decoder implements OptionDefault. If so, SetDefault calls decoder.SetDefault(). Otherwise, no action is taken.

func NewFlagAccumulator

func NewFlagAccumulator(val *int) OptionDecoder

NewFlagAccumulator builds an OptionDecoder for int flag values. The int value is incremented every time the option is decoded.

func NewFlagDecoder

func NewFlagDecoder(val *bool) OptionDecoder

NewFlagDecoder builds an OptionDecoder for boolean flag values. The boolean value is set when the option is decoded.

func NewOptionDecoder

func NewOptionDecoder(val interface{}) OptionDecoder

NewOptionDecoder builds an OptionDecoder for supported value types. The val parameter must be a pointer to one of the following supported types:

int, int8, int16, int32, int64, uint, uint8, iunt16, uint32, uint64
float32, float64
string, []string
map[string]string
	Argument must be in key=value format.
io.Reader, io.ReadCloser
	Argument must be a path to an existing file, or "-" to specify os.Stdin
io.Writer, io.WriteCloser
	Argument will be used to create a new file, or "-" to specify os.Stdout.
	If a file already exists at the path specified, it will be overwritten.

type OptionDefaulter

type OptionDefaulter interface {
	SetDefault()
}

OptionDefaulter initializes option values to defaults. If an OptionDecoder implements the OptionDefaulter interface, its SetDefault() method is called prior to decoding options.

type OptionGroup

type OptionGroup struct {
	Options []*Option

	// Optional
	Name   string // Not displayed; for matching purposes within the template
	Header string // Displayed before the group
	Footer string // Displayed after the group
}

OptionGroup is used to customize help output. It groups related Options for output. When New() parses an input spec, it creates a single OptionGroup for all parsed options that have descriptions.

type Path

type Path []*Command

Path represents a parsed Command list as returned by Command.Decode(). It is used to differentiate between user selection of commands and subcommands.

func (Path) First

func (p Path) First() *Command

First returns the first command of the path. This is the top-level/root command where Decode() was invoked.

func (Path) Last

func (p Path) Last() *Command

Last returns the last command of the path. This is the user-selected command.

func (Path) String

func (p Path) String() string

String returns the names of each command joined by spaces.

Jump to

Keyboard shortcuts

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