argparse

package module
Version: v0.0.0-...-ac7ac3d Latest Latest
Warning

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

Go to latest
Published: Nov 26, 2019 License: MIT Imports: 5 Imported by: 0

README

Golang argparse

GoDoc Go Report Card Coverage Status Build Status

Let's be honest -- Go's standard command line arguments parser flag terribly sucks. It cannot come anywhere close to the Python's argparse module. This is why this project exists.

The goal of this project is to bring ease of use and flexibility of argparse to Go. Which is where the name of this package comes from.

Installation

To install and start using argparse simply do:

$ go get -u -v github.com/akamensky/argparse

You are good to go to write your first command line tool! See Usage and Examples sections for information how you can use it

Usage

To start using argparse in Go see above instructions on how to install. From here on you can start writing your first program. Please check out examples from examples/ directory to see how to use it in various ways.

Here is basic example of print command (from examples/print/ directory):

package main

import (
	"fmt"
	"github.com/akamensky/argparse"
	"os"
)

func main() {
	// Create new parser object
	parser := argparse.NewParser("print", "Prints provided string to stdout")
	// Create string flag
	s := parser.String("s", "string", &argparse.Options{Required: true, Help: "String to print"})
	// Parse input
	err := parser.Parse(os.Args)
	if err != nil {
		// In case of error print error and print usage
		// This can also be done by passing -h or --help flags
		fmt.Print(parser.Usage(err))
	}
	// Finally print the collected string
	fmt.Println(*s)
}
Basic options

Create your parser instance and pass it program name and program description. Program name if empty will be taken from os.Args[0] (which is okay in most cases). Description can be as long as you wish and will be used in --help output

parser := argparse.NewParser("progname", "Description of my awesome program. It can be as long as I wish it to be")

String will allow you to get a string from arguments, such as $ progname --string "String content"

var myString *string = parser.String("s", "string", ...)

Flag will tell you if a simple flag was set on command line (true is set, false is not). For example $ progname --force

var myFlag *bool = parser.Flag("f", "force", ...)

List allows to collect multiple values into the slice of strings by repeating same flag multiple times. Such as $ progname --host hostname1 --host hostname2 -H hostname3

var myList *[]string = parser.List("H", "hostname", ...)

Selector works same as a string, except that it will only allow specific values. For example like this $ progname --debug-level WARN

var mySelector *string = parser.Selector("d", "debug-level", []string{"INFO", "DEBUG", "WARN"}, ...)

File will validate that file exists and will attempt to open it with provided privileges. To be used like this $ progname --log-file /path/to/file.log

var myLogFile *os.File = parser.File("l", "log-file", os.O_RDWR, 0600, ...)

You can implement sub-commands in your CLI using parser.NewCommand() or go even deeper with command.NewCommand(). Since parser inherits from command, every command supports exactly same options as parser itself, thus allowing to add arguments specific to that command or more global arguments added on parser itself!

Caveats

There are a few caveats (or more like design choices) to know about:

  • Shorthand arguments MUST be a single character. Shorthand arguments are prepended with single dash "-"
  • If not convenient shorthand argument can be completely skipped by passing empty string "" as first argument
  • Shorthand arguments ONLY for parser.Flag() can be combined into single argument same as ps -aux or rm -rf
  • Long arguments must be specified and cannot be empty. They are prepended with double dash "--"
  • You cannot define two same arguments. Only first one will be used. For example doing parser.Flag("t", "test", nil) followed by parser.String("t", "test2", nil) will not work as second String argument will be ignored (note that both have "t" as shorthand argument). However since it is case-sensitive library, you can work arounf it by capitalizing one of the arguments
  • There is a pre-defined argument for -h|--help, so from above attempting to define any argument using h as shorthand will fail
  • parser.Parse() returns error in case of something going wrong, but it is not expected to cover ALL cases
  • Any arguments that left un-parsed will be regarded as error
Contributing

Can you write in Go? Then this projects needs your help!

Take a look at open issues, specially the ones tagged as help-wanted. If you have any improvements to offer, please open an issue first to ensure this improvement is discussed.

There are following tasks to be done:

  • Add more examples
  • Improve code quality (it is messy right now and could use a major revamp to improve gocyclo report)
  • Add more argument options (such as numbers parsing)
  • Improve test coverage
  • Write a wiki for this project

However note that the logic outlined in method comments must be preserved as the the library must stick with backward compatibility promise!

Acknowledgments

Thanks to Python developers for making a great argparse which inspired this package to match for greatness of Go

Documentation

Overview

Package argparse provides users with more flexible and configurable option for command line arguments parsing.

Index

Examples

Constants

View Source
const DisableDescription = "DISABLEDDESCRIPTIONWILLNOTSHOWUP"

DisableDescription can be assigned as a command or arguments description to hide it from the Usage output

Variables

This section is empty.

Functions

This section is empty.

Types

type Arg

type Arg interface {
	GetOpts() *Options
	GetSname() string
	GetLname() string
}

Arg interface provides exporting of arg structure, while exposing it

type Command

type Command struct {
	HelpFunc func(c *Command, msg interface{}) string
	// contains filtered or unexported fields
}

Command is a basic type for this package. It represents top level Parser as well as any commands and sub-commands Command MUST NOT ever be created manually. Instead one should call NewCommand method of Parser or Command, which will setup appropriate fields and call methods that have to be called when creating new command.

func (*Command) File

func (o *Command) File(short string, long string, flag int, perm os.FileMode, opts *Options) *os.File

File creates new file argument, which is when provided will check if file exists or attempt to create it depending on provided flags (same as for os.OpenFile). It takes same as all other arguments short and long names, additionally it takes flags that specify in which mode the file should be open (see os.OpenFile for details on that), file permissions that will be applied to a file and argument options. Returns a pointer to os.File which will be set to opened file on success. On error the Parser.Parse will return error and the pointer might be nil.

func (*Command) Flag

func (o *Command) Flag(short string, long string, opts *Options) *bool

Flag Creates new flag type of argument, which is boolean value showing if argument was provided or not. Takes short name, long name and pointer to options (optional). Short name must be single character, but can be omitted by giving empty string. Long name is required. Returns pointer to boolean with starting value `false`. If Parser finds the flag provided on Command line arguments, then the value is changed to true. Only for Flag shorthand arguments can be combined together such as `rm -rf`

func (*Command) Float

func (o *Command) Float(short string, long string, opts *Options) *float64

Float creates new float argument, which will attempt to parse following argument as float64. Takes as arguments short name (must be single character or an empty string) long name and (optional) options. If parsing fails parser.Parse() will return an error.

func (Command) GetArgs

func (o Command) GetArgs() (args []Arg)

GetArgs exposes Command's args field

func (Command) GetCommands

func (o Command) GetCommands() []*Command

GetCommands exposes Command's commands field

func (Command) GetDescription

func (o Command) GetDescription() string

GetDescription exposes Command's description field

func (Command) GetName

func (o Command) GetName() string

GetName exposes Command's name field

func (Command) GetParent

func (o Command) GetParent() *Command

GetParent exposes Command's parent field

func (*Command) Happened

func (o *Command) Happened() bool

Happened shows whether Command was specified on CLI arguments or not. If Command did not "happen", then all its descendant commands and arguments are not parsed. Returns a boolean value.

func (*Command) Help

func (o *Command) Help(msg interface{}) string

Help calls the overriddable Command.HelpFunc on itself, called when the help argument strings are passed via CLI

Example
parser := NewParser("parser", "")
parser.HelpFunc = func(c *Command, msg interface{}) string {
	return fmt.Sprintf("Name: %s\n", c.GetName())
}
fmt.Println(parser.Help(nil))
Output:

Name: parser
Example (SubcommandDefaulting)
parser := NewParser("parser", "")
parser.HelpFunc = func(c *Command, msg interface{}) string {
	helpString := fmt.Sprintf("Name: %s\n", c.GetName())
	for _, com := range c.GetCommands() {
		// Calls parser.HelpFunc, because command.HelpFuncs are nil
		helpString += com.Help(nil)
	}
	return helpString
}
parser.NewCommand("subcommand1", "")
parser.NewCommand("subcommand2", "")
fmt.Println(parser.Help(nil))
Output:

Name: parser
Name: subcommand1
Name: subcommand2
Example (SubcommandHelpFuncs)
parser := NewParser("parser", "")
parser.HelpFunc = func(c *Command, msg interface{}) string {
	helpString := fmt.Sprintf("Name: %s\n", c.GetName())
	for _, com := range c.GetCommands() {
		// Calls command.HelpFunc, because command.HelpFuncs are not nil
		helpString += com.Help(nil)
	}
	return helpString
}
com1 := parser.NewCommand("subcommand1", "Test description")
com1.HelpFunc = func(c *Command, msg interface{}) string {
	helpString := fmt.Sprintf("Name: %s, Description: %s\n", c.GetName(), c.GetDescription())
	return helpString
}
com2 := parser.NewCommand("subcommand2", "")
com2.String("s", "string", &Options{Required: false})
com2.String("i", "integer", &Options{Required: true})
com2.HelpFunc = func(c *Command, msg interface{}) string {
	helpString := fmt.Sprintf("Name: %s\n", c.GetName())
	for _, arg := range c.GetArgs() {
		helpString += fmt.Sprintf("\tLname: %s, Required: %t\n", arg.GetLname(), arg.GetOpts().Required)
	}
	return helpString
}
fmt.Print(parser.Help(nil))
fmt.Print(com1.Help(nil))
fmt.Print(com2.Help(nil))
Output:

Name: parser
Name: subcommand1, Description: Test description
Name: subcommand2
	Lname: string, Required: false
	Lname: integer, Required: true
Name: subcommand1, Description: Test description
Name: subcommand2
	Lname: string, Required: false
	Lname: integer, Required: true

func (*Command) Int

func (o *Command) Int(short string, long string, opts *Options) *int

Int creates new int argument, which will attempt to parse following argument as int. Takes as arguments short name (must be single character or an empty string) long name and (optional) options. If parsing fails parser.Parse() will return an error.

func (*Command) List

func (o *Command) List(short string, long string, opts *Options) *[]string

List creates new list argument. This is the argument that is allowed to be present multiple times on CLI. All appearances of this argument on CLI will be collected into the list of strings. If no argument provided, then the list is empty. Takes same parameters as String Returns a pointer to the list of strings.

func (*Command) NewCommand

func (o *Command) NewCommand(name string, description string) *Command

NewCommand will create a sub-command and propagate all necessary fields. All commands are always at the beginning of the arguments. Parser can have commands and those commands can have sub-commands, which allows for very flexible workflow. All commands are considered as required and all commands can have their own argument set. Commands are processed Parser -> Command -> sub-Command. Arguments will be processed in order of sub-Command -> Command -> Parser.

func (*Command) PosString

func (o *Command) PosString(name string, opts *Options) *PosStringResult

PosString creates an argument which collects any strings remaining after parsing all other flags. The strings will be stored in the results array. We use a custom type for PosStringResult in order to enable correct rendering of the help text in the usage() switch statement. The 'name' parameter value is provided in the user-visible help text; see examples/positionals/positionals.go.

Any unparsed strings which start with '-' are indistinguishable from an erroneous flag, so will trigger an error message and halt parsing.

Returns a pointer to the list of strings.

func (*Command) Selector

func (o *Command) Selector(short string, long string, options []string, opts *Options) *string

Selector creates a selector argument. Selector argument works in the same way as String argument, with the difference that the string value must be from the list of options provided by the program. Takes short and long names, argument options and a slice of strings which are allowed values for CLI argument. Returns a pointer to a string. If argument is not required (as in argparse.Options.Required), and argument was not provided, then the string is empty.

func (*Command) String

func (o *Command) String(short string, long string, opts *Options) *string

String creates new string argument, which will return whatever follows the argument on CLI. Takes as arguments short name (must be single character or an empty string) long name and (optional) options

func (*Command) Usage

func (o *Command) Usage(msg interface{}) string

Usage returns a multiline string that is the same as a help message for this Parser or Command. Since Parser is a Command as well, they work in exactly same way. Meaning that usage string can be retrieved for any level of commands. It will only include information about this Command, its sub-commands, current Command arguments and arguments of all preceding commands (if any)

Accepts an interface that can be error, string or fmt.Stringer that will be prepended to a message. All other interface types will be ignored

type Options

type Options struct {
	Required bool
	Validate func(args []string) error
	Help     string
	Default  interface{}
}

Options are specific options for every argument. They can be provided if necessary. Possible fields are:

Options.Required - tells Parser that this argument is required to be provided. useful when specific Command requires some data provided.

Options.Validate - is a validation function. Using this field anyone can implement a custom validation for argument. If provided and argument is present, then function is called. If argument also consumes any following values (e.g. as String does), then these are provided as args to function. If validation fails the error must be returned, which will be the output of `Parser.Parse` method.

Options.Help - A help message to be displayed in Usage output. Can be of any length as the message will be formatted to fit max screen width of 100 characters.

Options.Default - A default value for an argument. This value will be assigned to the argument at the end of parsing in case if this argument was not supplied on command line. File default value is a string which it will be open with provided options. In case if provided value type does not match expected, the error will be returned on run-time.

type Parser

type Parser struct {
	Command
}

Parser is a top level object of argparse. It MUST NOT ever be created manually. Instead one should use argparse.NewParser() method that will create new parser, propagate necessary private fields and call needed functions.

func NewParser

func NewParser(name string, description string) *Parser

NewParser creates new Parser object that will allow to add arguments for parsing It takes program name and description which will be used as part of Usage output Returns pointer to Parser object

func (*Parser) Parse

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

Parse method can be applied only on Parser. It takes a slice of strings (as in os.Args) and it will process this slice as arguments of CLI (the original slice is not modified). Returns error on any failure. In case of failure recommended course of action is to print received error alongside with usage information (might want to check which Command was active when error happened and print that specific Command usage). In case no error returned all arguments should be safe to use. Safety of using arguments before Parse operation is complete is not guaranteed.

type PosStringResult

type PosStringResult []string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL