getoptions

package module
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2019 License: MPL-2.0 Imports: 14 Imported by: 61

README

= go-getoptions
David Gamba, https://github.com/DavidGamba
:idprefix:
:name: go-getoptions
:toc: macro

Go option parser inspired on the flexibility of Perl’s GetOpt::Long.

image:https://godoc.org/github.com/DavidGamba/go-getoptions?status.svg[link="http://godoc.org/github.com/DavidGamba/go-getoptions"]
image:https://travis-ci.org/DavidGamba/go-getoptions.svg["Build Status", link="https://travis-ci.org/DavidGamba/go-getoptions"]
image:https://codecov.io/github/DavidGamba/go-getoptions/coverage.svg?branch=master["Coverage via Codecov", link="https://codecov.io/github/DavidGamba/go-getoptions?branch=release"]

toc::[]

[[quick_overview]]
== Quick overview

. Define your command line specification:
+
[source,go]
----
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/DavidGamba/go-getoptions"
)

var logger = log.New(ioutil.Discard, "DEBUG: ", log.LstdFlags)

func main() {
	var debug bool
	var greetCount int
	var list map[string]string
	opt := getoptions.New()
	opt.Bool("help", false, opt.Alias("h", "?"))
	opt.BoolVar(&debug, "debug", false)
	opt.IntVar(&greetCount, "greet", 0,
		opt.Required(),
		opt.Description("Number of times to greet."))
	opt.StringMapVar(&list, "list", 1, 99,
		opt.Description("Greeting list by language."))
	remaining, err := opt.Parse(os.Args[1:])
	if opt.Called("help") {
		fmt.Fprintf(os.Stderr, opt.Help())
		os.Exit(1)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
		fmt.Fprintf(os.Stderr, opt.Help(getoptions.HelpSynopsis))
		os.Exit(1)
	}

	// Use the passed command line options... Enjoy!
	if debug {
		logger.SetOutput(os.Stderr)
	}
	logger.Printf("Unhandled CLI args: %v\n", remaining)

	// Use the int variable
	for i := 0; i < greetCount; i++ {
		fmt.Println("Hello World, from go-getoptions!")
	}

	// Use the map[string]string variable
	if len(list) > 0 {
		fmt.Printf("Greeting List:\n")
		for k, v := range list {
			fmt.Printf("\t%s=%s\n", k, v)
		}
	}
}
----

. Call it:
+
.Show help
----
$ ./myscript --help
SYNOPSIS:
    myscript --greet <int> [--debug] [--help|-h|-?] [--list <key=value>...]...

REQUIRED PARAMETERS:
    --greet <int>                Number of times to greet.

OPTIONS:
    --debug                      (default: false)

    --help|-h|-?                 (default: false)

    --list <key=value>...        Greeting list by language. (default: {})

----
+
.Show errors
----
$ ./myscript
ERROR: Missing required option 'greet'!

SYNOPSIS:
    myscript --greet <int> [--debug] [--help|-h|-?] [--list <key=value>...]...
----
+
.Show errors
----
$ ./myscript -g
ERROR: Missing argument for option 'greet'!

SYNOPSIS:
    myscript --greet <int> [--debug] [--help|-h|-?] [--list <key=value>...]...
----
+
.Use of int option
----
$ ./myscript -g 3
Hello World, from go-getoptions!
Hello World, from go-getoptions!
Hello World, from go-getoptions!
----
+
.Use of bool option
----
$ ./myscript --debug -g 1 other stuff
DEBUG: 2019/07/14 23:20:22 Unhandled CLI args: [other stuff]
Hello World, from go-getoptions!
----
+
.Use of map option
----
./myscript -g 0 -l en='Hello World' es='Hola Mundo'
Greeting List:
        en=Hello World
        es=Hola Mundo
----

== Features

• Allow passing options and non-options in any order.

• Support for `--long` options.

• Support for short (`-s`) options with flexible behaviour (see the <<operation_modes>> section for details):

  - Normal (default)
  - Bundling
  - SingleDash

• `Called()` method indicates if the option was passed on the command line.

• Multiple aliases for the same option. e.g. `help`, `man`.

• `CalledAs()` method indicates what alias was used to call the option on the command line.

• Simple synopsis and option list automated help.

• Boolean, String, Int, Float64, Slice and Map type options.

• Negatable Boolean options.
+
For example: `--verbose`, `--no-verbose` or `--noverbose`.

• Options with Array arguments.
The same option can be used multiple times with different arguments.
The list of arguments will be saved into an Slice.

• Options with array arguments and multiple entries.
+
For example, instead of writing:
`color --r 10 --g 20 --b 30 --next-option`
or
`color --rgb 10 --rgb 20 --rgb 30 --next-option`
the input could be:
`color --rgb 10 20 30 --next-option`

• When using integer array options with multiple arguments, positive integer ranges are allowed.
+
For example, Instead of writing:
`csv --columns 1 2 3`
or
`csv --columns 1 --columns 2 --columns 3`
The input could be:
`csv --columns 1..3`

• Options with Key Value arguments.
This allows the same option to be used multiple times with arguments of key value type.
+
For example: `rpmbuild --define name=myrpm --define version=123`

• Options with key value arguments and multiple entries.
+
For example, instead of writing:
`connection --server hostname=serverIP --server port=123 --client hostname=localhost --client port=456`
the input could be:
`connection --server hostname=serverIP port=123 --client hostname=localhost port=456`

• Supports command line options with '='.
+
For example: You can use `--string=mystring` and `--string mystring`.

• Allows passing arguments to options that start with dash `-` when passed after equal.
+
For example: `--string=--hello` and `--int=-123`.

• Supports passing `--` to stop parsing arguments (everything after will be left in the `remaining []string`).

• Options with optional arguments.
If the default argument is not passed the default is set.
+
For example: You can call `--int 123` which yields `123` or `--int` which yields the given default.

• Allows abbreviations when the provided option is not ambiguous.
+
For example: An option called `build` can be called with `--b`, `--bu`, `--bui`, `--buil` and `--build` as long as there is no ambiguity.
In the case of ambiguity, the shortest non ambiguous combination is required.

• Support for the lonesome dash "-".
To indicate, for example, when to read input from STDIO.

• Incremental options.
Allows the same option to be called multiple times to increment a counter.

• Supports case sensitive options.
For example, you can use `v` to define `verbose` and `V` to define `Version`.

• Support indicating if an option is required and allows overriding default error message.

• Errors exposed as public variables to allow overriding them for internationalization.

• Supports subcommands (stop parsing arguments when non option is passed).

• Multiple ways of managing unknown options:
  - Fail on unknown (default).
  - Warn on unknown.
  - Pass through, allows for subcommands and can be combined with Require Order.

• Require order: Allows for subcommands. Stop parsing arguments when the first non-option is found.
When mixed with Pass through, it also stops parsing arguments when the first unmatched option is found.

== How to install it

. Get it from github:
+
`go get github.com/DavidGamba/go-getoptions`

. Then import it:
+
`import "github.com/DavidGamba/go-getoptions" // As getoptions`

. Enjoy!

== Dependencies

Go 1.10+

[[roadmap]]
== ROADMAP

* Create new error description for errors when parsing integer ranges (`1..3`).

* Option that runs a function?

* Case insensitive matching.

* Option values in the bundle: `-h1024w800` -> `-h 1024 -w 800`

* prefix and prefix_pattern.
The string that starts options.
Defaults to "--" and "-" but could include "/" to support Win32 style argument handling.

* Supports argument dividers other than '='.
For example: You could define ':' and use `--string=mystring`, `--string:mystring` and `--string mystring`.

* All other Perl's Getopt::Long goodies that seem reasonable to add!

== Introduction

NOTE: For a <<quick_overview>>, jump to that section in the TOC or review the http://godoc.org/github.com/DavidGamba/go-getoptions[GoDoc Documentation].

Option parsing is the act of taking command line arguments and converting them into meaningful structures within the program.

An option parser should support, at least, the following:

Boolean options::
`True` when passed on the command line.
For example:
+
`ls --all`
+
In `go-getoptions` this is accomplished with:
+
- `ptr := opt.Bool(name, default_value)`.
- `opt.BoolVar(&ptr, name, default_value)`.
- Additionally, if all you want to know is if the option was passed you can use: `opt.Bool(name, default_value)` (without capturing its return value) and then check `opt.Called(name)`.

Options with String arguments::
The option will accept a string argument.
For example:
+
`grepp --ignore .txt`
+
Additionally, arguments to options can be passed with the `=` symbol.
+
`grepp --ignore=.txt`
+
In `go-getoptions` this is accomplished with:
+
- `ptr := opt.String(name, default_value)`.
- `opt.StringVar(&ptr, name, default_value)`.

The features listed above are enough to create basic programs but an option parser should do better:

Options with Integer arguments::
Parse an option string argument into an Integer and provide an user error if the string provided is not an integer.
For example:
+
`grepp --contex-lines 3`
+
and:
+
`grepp --context-lines string`
+
  Error: 'string' is not a valid integer.
+
In `go-getoptions` this is accomplished with:
+
- `ptr := opt.Int(name, default_value)`.
- `opt.IntVar(&ptr, name, default_value)`.

Options with Floating point arguments::
Parse an option string argument into a Floating point value and provide an user error if the string provided is not a valid floating point.
For example:
+
`command --approximation 3.5`
+
and:
+
`command --approximation string`
+
  Error: 'string' is not a valid floating point value.
+
In `go-getoptions` this is accomplished with:
+
- `ptr := opt.Float64(name, default_value)`.
- `opt.Float64Var(&ptr, name, default_value)`.

The features listed above relieve the programmer from the cumbersome task of converting the option argument into the expected type.

Another feature a better option parser should have is the ability to set a flag to `False`.

Negatable boolean options::
`True` when passed on the command line without any modifier and `False` when the `--no-` modifier is prefixed.
For example:
+
`command --verbose`
+
and:
+
`command --no-verbose`, or `command --noverbose`
+
In `go-getoptions` this is accomplished with:
+
- `ptr := opt.NBool(name, default_value)` which automatically defines `no-name` and `noname`.
- `opt.NBoolVar(&ptr, name, default_value)` which automatically defines `no-name` and `noname`.

That covers the most basic set of features, but still it is not enough to get past a basic program.
The following features will allow for a more complete interface.

Options with array arguments::
This allows the same option to be used multiple times with different arguments.
The list of arguments will be saved into a Slice inside the program.
For example:
+
`list-files --exclude .txt --exclude .html --exclude .pdf`
+
In `go-getoptions` this is accomplished with:
+
- `ptr := opt.StringSlice(name, 1, 1)`.

Options with Key Value arguments::
This allows the same option to be used multiple times with arguments of key value type.
For example:
+
`rpmbuild --define name=myrpm --define version=123`
+
In `go-getoptions` this is accomplished with:
+
- `strMap := opt.StringMap(name, 1, 1)`.

Both features above should support the basic types listed before: string, integer and floating point.

`go-getoptions` has only implemented these two features for string.

The features above are useful when you have a variable amount of arguments, but it becomes cumbersome for the user when the number of entries is always the same.
The features described below are meant to handle the cases when each option has a known number of multiple entries.

Options with array arguments and multiple entries::
This allows the user to save typing.
For example:
+
Instead of writing: `color --r 10 --g 20 --b 30 --next-option` or `color --rgb 10 --rgb 20 --rgb 30 --next-option`
+
The input could be: `color --rgb 10 20 30 --next-option`.
+
The setup for this feature should allow for the user to continue using both versions of the input, that is passing one argument at a time or passing the 3 arguments at once, or allow the setup to force the user to have to use the 3 arguments at once version.
This is accomplished with the minimum and maximum setup parameters.
+
The minimum setup parameter indicates the minimum amount of parameters the user can pass at a time.
For the example above, the parameter could be set to 3 to force the user to have to pass the 3 arguments at once.
When set to 1, the user will be able to pass a single parameter per option call.
+
The maximum setup parameter indicates the maximum amount of parameters the user can pass at a time.
The option parser will leave any non option argument after the maximum in the `remaining` slice.
+
In `go-getoptions` this is accomplished with:
+
- `strSlice := opt.StringSlice(name, minArgs, maxArgs)`.
- `intSlice := opt.IntSlice(name, minArgs, maxArgs)`.
+
Additionally, in the case of integers, positive integer ranges are allowed.
For example:
+
Instead of writing: `csv --columns 1 2 3` or `csv --columns 1 --columns 2 --columns 3`
+
The input could be: `csv --columns 1..3`.
+
In `go-getoptions` this is currently enabled by default when using:
+
`intSlice := opt.IntSlice(name, minArgs, maxArgs)`

Options with key value arguments and multiple entries::
This allows the user to save typing.
For example:
+
Instead of writing: `connection --server hostname=serverIP --server port=123 --client hostname=localhost --client port=456`
+
The input could be: `connection --server hostname=serverIP port=123 --client hostname=localhost port=456`
+
In `go-getoptions` this is accomplished with:
+
- `strMap := opt.StringMap(name, minArgs, maxArgs)`.

That covers a complete user interface that is flexible enough to accommodate most programs.
The following are advanced features:

Stop parsing options when `--` is passed::
Useful when arguments start with dash `-` and you don't want them interpreted as options.
+
In `go-getoptions` this is the default behaviour.

Stop parsing options when a subcommand is passed::
A subcommand is assumed to be the first argument that is not an option or an argument to an option.
When a subcommand is found, stop parsing arguments and let a subcommand handler handle the remaining arguments.
For example:
+
`command --opt arg subcommand --subopt subarg`
+
In the example above, `--opt` is an option and `arg` is an argument to an option, making `subcommand` the first non option argument.
+
This method is useful when both the command and the subcommand have option handlers for the same option.
+
For example, with:
+
`command --help`
+
`--help` is handled by `command`, and with:
+
`command subcommand --help`
+
`--help` is not handled by `command` since there was a subcommand that caused the parsing to stop.
+
Additionally, when mixed with _pass through_, it will also stop parsing arguments when it finds the first unmatched option.
+
In `go-getoptions` this is accomplished with:
+
- `opt.SetRequireOrder()`.
+
And can be combined with:
+
- `opt.SetUnknownMode("pass")`.

Allow passing options and non-options in any order::
Some option parsers force you to put the options before or after the arguments.
That is really annoying!
+
In `go-getoptions` this is the default behaviour.

Allow pass through::
Have an option to pass through unmatched options.
Useful when writing programs with multiple options depending on the main arguments.
The initial parser will only capture the help or global options and pass through everything else.
Additional argument parsing calls are invoked on the remaining arguments based on the initial input.
+
In `go-getoptions` this is accomplished with:
+
- `opt.SetUnknownMode("pass")`.

Fail on unknown::
The opposite of the above option.
Useful if you want to ensure there are no input mistakes and force the application to stop.
+
In `go-getoptions` this is the default behaviour.

Warn on unknown::
Less strict parsing of options.
This will warn the user that the option used is not a valid option but it will not stop the rest of the program.
+
In `go-getoptions` this is accomplished with:
+
- `opt.SetUnknownMode("warn")`.

Option aliases::
Options should be allowed to have different aliases.
For example, the same option could be invoked with `--address` or `--hostname`.
+
In `go-getoptions`, pass `opt.Alias("my-alias")` to any option.
For example:
+
`opt.BoolVar(&flag, "flag", false, opt.Alias("alias", "alias-2"))`
+
Finally, to know with what alias an option was called with used `opt.CalledAs(<name>)`.

Required options::
Mark an option as required.
Return an error if the option is not called.
+
In `go-getoptions`, pass `opt.Required()` to any option.
For example:
+
`opt.BoolVar(&flag, "flag", false, opt.Required())`
+
Optionally, override the default error message with `opt.Required(msg)`.
For example:
+
`opt.BoolVar(&flag, "flag", false, opt.Required("Missing --flag!"))`

Incremental option::
Some options can be passed more than once to increment an internal counter.
For example:
+
`command --v --v --v`
+
Could increase the verbosity level each time the option is passed.
+
In `go-getoptions` this is accomplished with:
+
- `ptr := opt.Increment(name, default_value)`.
- `opt.IncrementVar(&ptr, name, default_value)`.

Additional types::
The option parser could provide converters to additional types.
The disadvantage of providing non basic types is that the option parser grows in size.
+
Not yet implemented in `go-getoptions`.

Options with optional arguments::
With regular options, when the argument is not passed (for example: `--level` instead of `--level=debug`) you will get a _Missing argument_ error.
When using options with optional arguments, If the argument is not passed, the option will set the default value for the option type.
For this feature to be fully effective in strong typed languages where types have defaults, there must be a means to query the option parser to determine whether or not the option was called or not.
+
In `go-getoptions` this is accomplished with:
+
  - `ptr := opt.StringOptional(name, default_value)`.
  - `ptr := opt.IntOptional(name, default_value)`.
  - Not yet implemented for `float64`.
  - The above should be used in combination with `opt.Called(name)`.
+
For example, for the following definition:
+
`ptr := opt.StringOptional("level", "info")`
+
* If the option `level` is called with just `--level`, the value of `*ptr` is the default `"info"` and querying `opt.Called("level")` returns `true`.
* If the option `level` is called with `--level=debug`, the value of `*ptr` is `"debug"` and querying `opt.Called("level")` returns `true`.
* Finally, If the option `level` is not called, the value of `*ptr` is the default `"info"` and querying `opt.Called("level")` returns `false`.

Option flags that call a method internally::
If all the flag is doing is call a method or function when present, then having a way to call that function directly saves the programmer some time.
+
Not yet implemented in `go-getoptions`.

Notice how so far only long options (options starting with double dash `--`) have been mentioned.
There are 3 main ways to handle short options (options starting with only one dash `-`), see the <<operation_modes>> section for details.

[[operation_modes]]
== Operation Modes

The behaviour for long options (options starting with double dash `--`) is consistent across operation modes.
The behaviour for short options (options starting with only one dash `-`) depends on the _operation mode_.
The sections below show the different operation modes.

=== Normal Mode (default)

|===
|Given argument |Interpretation

|--opt
a|option: `"opt"`,  argument: `nil`

|--opt=arg
a|option: `"opt"`, argument: `"arg"` footnote:[Argument gets type casted depending on option definition.]

|-opt
a|option: `"opt"`, argument: `nil`

|-opt=arg
a|option: `"opt"`, argument: `"arg"` footnote:[Argument gets type casted depending on option definition.]

|===

=== Bundling Mode

Set by defining `opt.SetMode("bundling")`.

|===
|Given option |Interpretation

|--opt
a|option: `"opt"`,  argument: `nil`

|--opt=arg
a|option: `"opt"`, argument: `"arg"` footnote:[Argument gets type casted depending on option definition.]

|-opt
a|option: `"o"`, argument: `nil` +
option: `"p"`, argument: `nil` +
option: `"t"`, argument: `nil`

|-opt=arg
a|option: `"o"`, argument: `nil` +
option: `"p"`, argument: `nil` +
option: `"t"`, argument: `"arg"` footnote:[Argument gets type casted depending on option definition.]

|===

=== Enforce Single Dash Mode

Set by defining `opt.SetMode("singleDash")`.

|===
|Given option |Interpretation

|--opt
a|option: `"opt"`,  argument: `nil`

|--opt=arg
a|option: `"opt"`, argument: `"arg"` footnote:[Argument gets type casted depending on option definition.]

|-opt
a|option: `"o"`, argument: `"pt"` footnote:[Argument gets type casted depending on option definition.]

|-opt=arg
a|option: `"o"`, argument: `"pt=arg"` footnote:[Argument gets type casted depending on option definition.]

|===

== Biggest option parser misfeature - Automatically generate help

The biggest misfeature an option parser can have is to automatically generate the help message for the programmer.
This seemingly helpful feature has caused most tools not to have proper man pages anymore and to have all verbose descriptions mixed in the help synopsis.

If you are writing a mid to large tool, don't be lazy, write a man page for your program!
If you are looking for options, link:http://asciidoctor.org/[asciidoctor] has a manpage backend that can generate manpages written in the Asciidoc markup.

For the help synopsis, however, use the automated help.

== Command behaviour

This section describes how the parser resolves ambiguities between the program and the command.

Given a definition like:

		func main() {
			var profile, password string
			opt := New()
			opt.SetUnknownMode(Pass)
			opt.StringVar(&profile, "profile", "")
			command := NewCommand()
			command.StringVar(&password, "password", "")
			opt.Command(command.Self("command", "").SetCommandFn(commandFn))
			remaining, err := opt.Parse(os.Args[1:])
			...
			err = opt.Dispatch("help", remaining)
			...
		}

		func commandFn(opt *getoptions.GetOpt, args []string) error {
			args, err := opt.Parse(remaining)
			...
		}

There is an option at the parent, `profile` and one at the command, `password`.
Passing `--p <arg>` is ambiguous and results in an error.
At minimum, `--pr <arg>` and `--pa <arg>` are required.

Given a definition like:

		func main() {
			var profile, password string
			opt := New()
			opt.SetUnknownMode(Pass)
			opt.StringVar(&profile, "profile", "")
			command := NewCommand()
			command.StringVar(&password, "password", "", opt.Alias("p"))
			opt.Command(command.Self("command", "").SetCommandFn(commandFn))
			remaining, err := opt.Parse(os.Args[1:])
			...
			err = opt.Dispatch("help", remaining)
			...
		}

		func commandFn(opt *getoptions.GetOpt, args []string) error {
			args, err := opt.Parse(remaining)
			...
		}

There is an option at the parent, `profile` and one at the command, `password` with alias `p`.
Passing `--p <arg>` at the parent results in the parent `opt.Parse` call to leave the `--p <arg>` option unhandled and leave it in the remaining slice.
The `opt.Dispatch` call gets the `-p <arg>` option and throws an error.
At minimum, `--pr <arg>` is required to call `profile` at the parent and command options must be passed after the command declaration.

For example, the call below is correct:

	./program -pr <profile> command -p <password>

But the following one is incorrect:

	./program -pr <profile> -p <password> command

== License

This file is part of go-getoptions.

Copyright (C) 2015-2019  David Gamba Rios

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

Documentation

Overview

Package getoptions - Go option parser inspired on the flexibility of Perl’s GetOpt::Long.

It will operate on any given slice of strings and return the remaining (non used) command line arguments. This allows to easily subcommand.

Usage

The following is a basic example:

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/DavidGamba/go-getoptions"
)

var logger = log.New(os.Stderr, "DEBUG: ", log.LstdFlags)

func main() {
	// Declare the variables you want your options to update
	var debug bool
	var greetCount int

	// Declare the GetOptions object
	opt := getoptions.New()

	// Options definition
	opt.Bool("help", false, opt.Alias("h", "?")) // Aliases can be defined
	opt.BoolVar(&debug, "debug", false)
	opt.IntVar(&greetCount, "greet", 0,
		opt.Required(), // Mark option as required
		opt.Description("Number of times to greet."), // Set the automated help description
		opt.ArgName("number"),                        // Change the help synopsis arg from <int> to <number>
	)
	greetings := opt.StringMap("list", 1, 99,
		opt.Description("Greeting list by language."),
		opt.ArgName("lang=msg"), // Change the help synopsis arg from <key=value> to <lang=msg>
	)

	// Parse cmdline arguments or any provided []string
	remaining, err := opt.Parse(os.Args[1:])

	// Handle help before handling user errors
	if opt.Called("help") {
		fmt.Fprintf(os.Stderr, opt.Help())
		os.Exit(1)
	}

	// Handle user errors
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
		fmt.Fprintf(os.Stderr, opt.HelpSynopsis())
		os.Exit(1)
	}
	if !debug {
		logger.SetOutput(ioutil.Discard)
	}
	logger.Printf("Remaining: %v\n", remaining)

	for i := 0; i < greetCount; i++ {
		fmt.Println("Hello World, from go-getoptions!")
	}
	if len(greetings) > 0 {
		fmt.Printf("Greeting List:\n")
		for k, v := range greetings {
			fmt.Printf("\t%s=%s\n", k, v)
		}
	}
}

Features

• Allow passing options and non-options in any order.

• Support for `--long` options.

• Support for short (`-s`) options with flexible behaviour (see https://github.com/DavidGamba/go-getoptions#operation_modes for details):

  • Normal (default)
  • Bundling
  • SingleDash

• `Called()` method indicates if the option was passed on the command line.

• Multiple aliases for the same option. e.g. `help`, `man`.

• `CalledAs()` method indicates what alias was used to call the option on the command line.

• Simple synopsis and option list automated help.

• Boolean, String, Int and Float64 type options.

• Negatable Boolean options. For example: `--verbose`, `--no-verbose` or `--noverbose`.

• Options with Array arguments. The same option can be used multiple times with different arguments. The list of arguments will be saved into an Array like structure inside the program.

• Options with array arguments and multiple entries. For example: `color --rgb 10 20 30 --next-option`

• When using integer array options with multiple arguments, positive integer ranges are allowed. For example: `1..3` to indicate `1 2 3`.

• Options with key value arguments and multiple entries.

• Options with Key Value arguments. This allows the same option to be used multiple times with arguments of key value type. For example: `rpmbuild --define name=myrpm --define version=123`.

• Supports passing `--` to stop parsing arguments (everything after will be left in the `remaining []string`).

• Supports command line options with '='. For example: You can use `--string=mystring` and `--string mystring`.

• Allows passing arguments to options that start with dash `-` when passed after equal. For example: `--string=--hello` and `--int=-123`.

• Options with optional arguments. If the default argument is not passed the default is set. For example: You can call `--int 123` which yields `123` or `--int` which yields the given default.

• Allows abbreviations when the provided option is not ambiguous. For example: An option called `build` can be called with `--b`, `--bu`, `--bui`, `--buil` and `--build` as long as there is no ambiguity. In the case of ambiguity, the shortest non ambiguous combination is required.

• Support for the lonesome dash "-". To indicate, for example, when to read input from STDIO.

• Incremental options. Allows the same option to be called multiple times to increment a counter.

• Supports case sensitive options. For example, you can use `v` to define `verbose` and `V` to define `Version`.

• Support indicating if an option is required and allows overriding default error message.

• Errors exposed as public variables to allow overriding them for internationalization.

• Supports subcommands (stop parsing arguments when non option is passed).

• Multiple ways of managing unknown options:

  • Fail on unknown (default).
  • Warn on unknown.
  • Pass through, allows for subcommands and can be combined with Require Order.

• Require order: Allows for subcommands. Stop parsing arguments when the first non-option is found. When mixed with Pass through, it also stops parsing arguments when the first unmatched option is found.

Panic

The library will panic if it finds that the programmer (not end user):

• Defined the same alias twice.

• Defined wrong min and max values for SliceMulti methods.

Example
// Declare the variables you want your options to update
var flag bool
var str string
var i int
var f float64

// Declare the GetOptions object
opt := getoptions.New()

// Options definition
opt.Bool("help", false, opt.Alias("?"))
opt.BoolVar(&flag, "flag", false, opt.Alias("f", "alias2")) // Aliases can be defined
opt.StringVar(&str, "string", "", opt.Required())           // Mark option as required
opt.IntVar(&i, "i", 456)
opt.Float64Var(&f, "float", 0)

// Parse cmdline arguments or any provided []string
// Normally you would run Parse on `os.Args[1:]`:
// remaining, err := opt.Parse(os.Args[1:])
remaining, err := opt.Parse([]string{
	"non-option", // Non options can be mixed with options at any place
	"-f",
	"--string=mystring", // Arguments can be passed with equals
	"--float", "3.14",   // Or with space
	"non-option2",
	"--", "--not-parsed", // -- indicates end of parsing
})

// Handle help before handling user errors
if opt.Called("help") {
	// ...
}

// Handle user errors
if err != nil {
	fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
	os.Exit(1)
}

// The remaining slice holds non-options and anything after --
fmt.Printf("remaining: %v\n", remaining)

if flag {
	fmt.Println("flag is true")
}

// Called method tells you if an option was actually called or not
if opt.Called("string") {
	fmt.Printf("srt is %s\n", str)
}

// When the option is not called, it will have the provided default
if !opt.Called("i") {
	fmt.Printf("i is %d\n", i)
}

fmt.Printf("f is %.2f", f)
Output:

remaining: [non-option non-option2 --not-parsed]
flag is true
srt is mystring
i is 456
f is 3.14

Index

Examples

Constants

This section is empty.

Variables

Debug Logger instance set to `ioutil.Discard` by default. Enable debug logging by setting: `Debug.SetOutput(os.Stderr)`.

Functions

This section is empty.

Types

type CommandFn added in v0.15.0

type CommandFn func(*GetOpt, []string) error

CommandFn - Function signature for commands

type GetOpt

type GetOpt struct {

	// CommandFn
	CommandFn CommandFn

	// Debugging
	Writer io.Writer // io.Writer to write warnings to. Defaults to os.Stderr.
	// contains filtered or unexported fields
}

GetOpt - main object.

func New

func New() *GetOpt

New returns an empty object of type GetOpt. This is the starting point when using go-getoptions. For example:

opt := getoptions.New()

func NewCommand added in v0.15.0

func NewCommand() *GetOpt

func (*GetOpt) Alias added in v0.12.0

func (gopt *GetOpt) Alias(alias ...string) ModifyFn

Alias - Adds aliases to an option.

func (*GetOpt) ArgName added in v0.13.0

func (gopt *GetOpt) ArgName(name string) ModifyFn

ArgName - Add an argument name to an option for use in automated help. For example, by default a string option will have a default synopsis as follows:

--host <string>

If ArgName("hostname") is used, the synopsis will read:

--host <hostname>

func (*GetOpt) Bool

func (gopt *GetOpt) Bool(name string, def bool, fns ...ModifyFn) *bool

Bool - define a `bool` option and its aliases. It returns a `*bool` pointing to the variable holding the result. If the option is found, the result will be the opposite of the provided default.

func (*GetOpt) BoolVar

func (gopt *GetOpt) BoolVar(p *bool, name string, def bool, fns ...ModifyFn)

BoolVar - define a `bool` option and its aliases. The result will be available through the variable marked by the given pointer. If the option is found, the result will be the opposite of the provided default.

func (*GetOpt) Called

func (gopt *GetOpt) Called(name string) bool

Called - Indicates if the option was passed on the command line. If the `name` is an option that wasn't declared it will return false.

func (*GetOpt) CalledAs added in v0.13.0

func (gopt *GetOpt) CalledAs(name string) string

CalledAs - Returns the alias used to call the option. Empty string otherwise.

If the `name` is an option that wasn't declared it will return an empty string.

For options that can be called multiple times, the last alias used is returned.

func (*GetOpt) Command added in v0.14.0

func (gopt *GetOpt) Command(options *GetOpt)

Command - Allows defining a child command.

func (*GetOpt) CustomCompletion added in v0.14.0

func (gopt *GetOpt) CustomCompletion(list []string) *GetOpt

CustomCompletion - Add a custom completion list.

func (*GetOpt) Description added in v0.13.0

func (gopt *GetOpt) Description(msg string) ModifyFn

Description - Add a description to an option for use in automated help.

func (*GetOpt) Dispatch added in v0.15.0

func (gopt *GetOpt) Dispatch(helpOptionName string, args []string) error

Dispatch -

func (*GetOpt) Float64

func (gopt *GetOpt) Float64(name string, def float64, fns ...ModifyFn) *float64

Float64 - define an `float64` option and its aliases.

func (*GetOpt) Float64Var

func (gopt *GetOpt) Float64Var(p *float64, name string, def float64, fns ...ModifyFn)

Float64Var - define an `float64` option and its aliases. The result will be available through the variable marked by the given pointer.

func (*GetOpt) Help added in v0.13.0

func (gopt *GetOpt) Help(sections ...HelpSection) string

Help - Default help string that is composed of the HelpSynopsis and HelpOptionList.

func (*GetOpt) HelpCommand added in v0.15.0

func (gopt *GetOpt) HelpCommand(description string) *GetOpt

HelpCommand - Adds a help command with completion for all other commands. NOTE: Define after all other commands have been defined.

func (*GetOpt) Increment

func (gopt *GetOpt) Increment(name string, def int, fns ...ModifyFn) *int

Increment - When called multiple times it increments the int counter defined by this option.

func (*GetOpt) IncrementVar

func (gopt *GetOpt) IncrementVar(p *int, name string, def int, fns ...ModifyFn)

IncrementVar - When called multiple times it increments the provided int.

func (*GetOpt) Int

func (gopt *GetOpt) Int(name string, def int, fns ...ModifyFn) *int

Int - define an `int` option and its aliases.

func (*GetOpt) IntOptional

func (gopt *GetOpt) IntOptional(name string, def int, fns ...ModifyFn) *int

IntOptional - define a `int` option and its aliases.

IntOptional will set the int to the provided default value when no value is given. For example, when called with `--intOpt 123`, the value is `123`. when called with `--intOpt` the value is the given default.

func (*GetOpt) IntSlice added in v0.11.0

func (gopt *GetOpt) IntSlice(name string, min, max int, fns ...ModifyFn) *[]int

IntSlice - define a `[]int` option and its aliases.

IntSlice will accept multiple calls to the same option and append them to the `[]int`. For example, when called with `--intRpt 1 --intRpt 2`, the value is `[]int{1, 2}`.

Additionally, IntSlice will allow to define a min and max amount of arguments to be passed at once. For example, when min is 1 and max is 3 and called with `--strRpt 1 2 3`, the value is `[]int{1, 2, 3}`. It could also be called with `--strRpt 1 --strRpt 2 --strRpt 3` for the same result.

When min is bigger than 1, it is required to pass the amount of arguments defined by min at once. For example: with `min = 2`, you at least require `--strRpt 1 2 --strRpt 3`

Finally, positive integer ranges are allowed. For example, Instead of writing: `csv --columns 1 2 3` or `csv --columns 1 --columns 2 --columns 3` The input could be: `csv --columns 1..3`.

func (*GetOpt) IntSliceVar added in v0.11.0

func (gopt *GetOpt) IntSliceVar(p *[]int, name string, min, max int, fns ...ModifyFn)

IntSliceVar - define a `[]int` option and its aliases.

IntSliceVar will accept multiple calls to the same option and append them to the `[]int`. For example, when called with `--intRpt 1 --intRpt 2`, the value is `[]int{1, 2}`.

Additionally, IntSliceVar will allow to define a min and max amount of arguments to be passed at once. For example, when min is 1 and max is 3 and called with `--strRpt 1 2 3`, the value is `[]int{1, 2, 3}`. It could also be called with `--strRpt 1 --strRpt 2 --strRpt 3` for the same result.

When min is bigger than 1, it is required to pass the amount of arguments defined by min at once. For example: with `min = 2`, you at least require `--strRpt 1 2 --strRpt 3`

Finally, positive integer ranges are allowed. For example, Instead of writing: `csv --columns 1 2 3` or `csv --columns 1 --columns 2 --columns 3` The input could be: `csv --columns 1..3`.

func (*GetOpt) IntVar

func (gopt *GetOpt) IntVar(p *int, name string, def int, fns ...ModifyFn)

IntVar - define an `int` option and its aliases. The result will be available through the variable marked by the given pointer.

func (*GetOpt) IntVarOptional

func (gopt *GetOpt) IntVarOptional(p *int, name string, def int, fns ...ModifyFn)

IntVarOptional - define a `int` option and its aliases. The result will be available through the variable marked by the given pointer.

IntOptional will set the int to the provided default value when no value is given. For example, when called with `--intOpt 123`, the value is `123`. when called with `--intOpt` the value is the given default.

func (*GetOpt) NBool

func (gopt *GetOpt) NBool(name string, def bool, fns ...ModifyFn) *bool

NBool - define a *Negatable* `bool` option and its aliases.

NBool automatically makes aliases with the prefix 'no' and 'no-' to the given name and aliases. If the option is found, when the argument is prefixed by 'no' (or by 'no-'), for example '--no-nflag', the value is set to the provided default. Otherwise, with a regular call, for example '--nflag', it is set to the opposite of the default.

func (*GetOpt) NBoolVar

func (gopt *GetOpt) NBoolVar(p *bool, name string, def bool, fns ...ModifyFn)

NBoolVar - define a *Negatable* `bool` option and its aliases. The result will be available through the variable marked by the given pointer.

NBoolVar automatically makes aliases with the prefix 'no' and 'no-' to the given name and aliases. If the option is found, when the argument is prefixed by 'no' (or by 'no-'), for example '--no-nflag', the value is set to the provided default. Otherwise, with a regular call, for example '--nflag', it is set to the opposite of the default.

func (*GetOpt) Option

func (gopt *GetOpt) Option(name string) *option.Option

Option - Returns the *option.Option for name.

func (*GetOpt) Parse

func (gopt *GetOpt) Parse(args []string) ([]string, error)

Parse - Call the parse method when done describing. It will operate on any given slice of strings and return the remaining (non used) command line arguments. This allows to easily subcommand.

Parsing style is controlled by the `Set` methods (SetMode, SetRequireOrder, etc).

// Declare the GetOptions object
opt := getoptions.New()
...
// Parse cmdline arguments or any provided []string
remaining, err := opt.Parse(os.Args[1:])

func (*GetOpt) Required added in v0.12.0

func (gopt *GetOpt) Required(msg ...string) ModifyFn

Required - Automatically return an error if the option is not called. Optionally provide an error message if the option is not called. A default error message will be used otherwise.

func (*GetOpt) Self added in v0.14.0

func (gopt *GetOpt) Self(name string, description string) *GetOpt

Self - Set a custom name and description that will show in the automated help. If name is an empty string, it will only use the description and use the name as the executable name.

func (*GetOpt) SetCommandFn added in v0.15.0

func (gopt *GetOpt) SetCommandFn(fn CommandFn) *GetOpt

func (*GetOpt) SetMapKeysToLower added in v0.11.0

func (gopt *GetOpt) SetMapKeysToLower()

SetMapKeysToLower - StringMap keys captured from StringMap are lower case. For example:

command --opt key=value

And:

command --opt KEY=value

Would both return `map[string]string{"key":"value"}`.

func (*GetOpt) SetMode

func (gopt *GetOpt) SetMode(mode Mode)

SetMode - Sets the Operation Mode. The operation mode only affects options starting with a single dash '-'. The available operation modes are: normal, bundling or singleDash.

The following table shows the different operation modes given the string "-opt=arg".

.Operation Modes for string "-opt=arg"
|===
|Mode             |Description

|normal           |option: opt
                    argument: arg

|bundling         |option: o
                    argument: nil
                   option: p
                    argument: nil
                   option: t
                    argument: arg

|singleDash       |option: o
                    argument: pt=arg

|===

See https://github.com/DavidGamba/go-getoptions#operation_modes for more details.

func (*GetOpt) SetOption added in v0.14.0

func (gopt *GetOpt) SetOption(opts ...*option.Option) *GetOpt

SetOption - Sets a given *option.Option

func (*GetOpt) SetRequireOrder

func (gopt *GetOpt) SetRequireOrder()

SetRequireOrder - Stop parsing options when a subcommand is passed. Put every remaining argument, including the subcommand, in the `remaining` slice.

A subcommand is assumed to be the first argument that is not an option or an argument to an option. When a subcommand is found, stop parsing arguments and let a subcommand handler handle the remaining arguments. For example:

command --opt arg subcommand --subopt subarg

In the example above, `--opt` is an option and `arg` is an argument to an option, making `subcommand` the first non option argument.

This method is useful when both the command and the subcommand have option handlers for the same option.

For example, with:

command --help

`--help` is handled by `command`, and with:

command subcommand --help

`--help` is not handled by `command` since there was a subcommand that caused the parsing to stop. In this case, the `remaining` slice will contain `['subcommand', '--help']` and that can be passed directly to a subcommand's option parser.

func (*GetOpt) SetUnknownMode

func (gopt *GetOpt) SetUnknownMode(mode UnknownMode)

SetUnknownMode - Determines how to behave when encountering an unknown option.

• 'fail' (default) will make 'Parse' return an error with the unknown option information.

• 'warn' will make 'Parse' print a user warning indicating there was an unknown option. The unknown option will be left in the remaining array.

• 'pass' will make 'Parse' ignore any unknown options and they will be passed onto the 'remaining' slice. This allows for subcommands. TODO: Add aliases

func (*GetOpt) String

func (gopt *GetOpt) String(name, def string, fns ...ModifyFn) *string

String - define a `string` option and its aliases. If not called, the return value will be that of the given default `def`.

func (*GetOpt) StringMap

func (gopt *GetOpt) StringMap(name string, min, max int, fns ...ModifyFn) map[string]string

StringMap - define a `map[string]string` option and its aliases.

StringMap will accept multiple calls of `key=value` type to the same option and add them to the `map[string]string` result. For example, when called with `--strMap k=v --strMap k2=v2`, the value is `map[string]string{"k":"v", "k2": "v2"}`.

Additionally, StringMap will allow to define a min and max amount of arguments to be passed at once. For example, when min is 1 and max is 3 and called with `--strMap k=v k2=v2 k3=v3`, the value is `map[string]string{"k":"v", "k2": "v2", "k3": "v3"}`. It could also be called with `--strMap k=v --strMap k2=v2 --strMap k3=v3` for the same result.

When min is bigger than 1, it is required to pass the amount of arguments defined by min at once. For example: with `min = 2`, you at least require `--strMap k=v k2=v2 --strMap k3=v3`

func (*GetOpt) StringMapVar added in v0.14.0

func (gopt *GetOpt) StringMapVar(m *map[string]string, name string, min, max int, fns ...ModifyFn)

StringMapVar - define a `map[string]string` option and its aliases.

StringMapVar will accept multiple calls of `key=value` type to the same option and add them to the `map[string]string` result. For example, when called with `--strMap k=v --strMap k2=v2`, the value is `map[string]string{"k":"v", "k2": "v2"}`.

Additionally, StringMapVar will allow to define a min and max amount of arguments to be passed at once. For example, when min is 1 and max is 3 and called with `--strMap k=v k2=v2 k3=v3`, the value is `map[string]string{"k":"v", "k2": "v2", "k3": "v3"}`. It could also be called with `--strMap k=v --strMap k2=v2 --strMap k3=v3` for the same result.

When min is bigger than 1, it is required to pass the amount of arguments defined by min at once. For example: with `min = 2`, you at least require `--strMap k=v k2=v2 --strMap k3=v3`

func (*GetOpt) StringOptional

func (gopt *GetOpt) StringOptional(name string, def string, fns ...ModifyFn) *string

StringOptional - define a `string` option and its aliases.

StringOptional will set the string to the provided default value when no value is given. For example, when called with `--strOpt value`, the value is `value`. when called with `--strOpt` the value is the given default.

func (*GetOpt) StringSlice

func (gopt *GetOpt) StringSlice(name string, min, max int, fns ...ModifyFn) *[]string

StringSlice - define a `[]string` option and its aliases.

StringSlice will accept multiple calls to the same option and append them to the `[]string`. For example, when called with `--strRpt 1 --strRpt 2`, the value is `[]string{"1", "2"}`.

Additionally, StringSlice will allow to define a min and max amount of arguments to be passed at once. For example, when min is 1 and max is 3 and called with `--strRpt 1 2 3`, the value is `[]string{"1", "2", "3"}`. It could also be called with `--strRpt 1 --strRpt 2 --strRpt 3` for the same result.

When min is bigger than 1, it is required to pass the amount of arguments defined by min at once. For example: with `min = 2`, you at least require `--strRpt 1 2 --strRpt 3`

func (*GetOpt) StringSliceVar added in v0.11.0

func (gopt *GetOpt) StringSliceVar(p *[]string, name string, min, max int, fns ...ModifyFn)

StringSliceVar - define a `[]string` option and its aliases.

StringSliceVar will accept multiple calls to the same option and append them to the `[]string`. For example, when called with `--strRpt 1 --strRpt 2`, the value is `[]string{"1", "2"}`.

Additionally, StringSliceVar will allow to define a min and max amount of arguments to be passed at once. For example, when min is 1 and max is 3 and called with `--strRpt 1 2 3`, the value is `[]string{"1", "2", "3"}`. It could also be called with `--strRpt 1 --strRpt 2 --strRpt 3` for the same result.

When min is bigger than 1, it is required to pass the amount of arguments defined by min at once. For example: with `min = 2`, you at least require `--strRpt 1 2 --strRpt 3`

func (*GetOpt) StringVar

func (gopt *GetOpt) StringVar(p *string, name, def string, fns ...ModifyFn)

StringVar - define a `string` option and its aliases. The result will be available through the variable marked by the given pointer. If not called, the return value will be that of the given default `def`.

func (*GetOpt) StringVarOptional

func (gopt *GetOpt) StringVarOptional(p *string, name, def string, fns ...ModifyFn)

StringVarOptional - define a `string` option and its aliases. The result will be available through the variable marked by the given pointer.

StringVarOptional will set the string to the provided default value when no value is given. For example, when called with `--strOpt value`, the value is `value`. when called with `--strOpt` the value is the given default.

func (*GetOpt) Stringer

func (gopt *GetOpt) Stringer() string

Stringer - print a nice looking representation of the resulting `Option` map.

func (*GetOpt) Value added in v0.14.0

func (gopt *GetOpt) Value(name string) interface{}

Value - Returns the value of the given option.

Type assertions are required in cases where the compiler can't determine the type by context. For example: `opt.Value("flag").(bool)`.

type HelpSection added in v0.14.0

type HelpSection int

HelpSection - Indicates what portion of the help to return.

const (
	HelpName HelpSection
	HelpSynopsis
	HelpCommandList
	HelpOptionList
)

Help Output Types

type Mode added in v0.14.0

type Mode int

Mode - Operation mode for short options

const (
	Normal Mode = iota
	Bundling
	SingleDash
)

Operation modes

type ModifyFn added in v0.12.0

type ModifyFn func(*option.Option)

ModifyFn - Function signature for functions that modify an option.

type UnknownMode added in v0.14.0

type UnknownMode int

UnknownMode - Unknown option mode

const (
	Fail UnknownMode = iota
	Warn
	Pass
)

Unknown option modes

Directories

Path Synopsis
Package completion - provides a Tree structure that can be used to define a program's completions.
Package completion - provides a Tree structure that can be used to define a program's completions.
examples
Package option - internal option struct and methods.
Package option - internal option struct and methods.
Package text - User facing strings
Package text - User facing strings

Jump to

Keyboard shortcuts

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