flago

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jan 26, 2024 License: MIT Imports: 14 Imported by: 0

README ¶

test list Go Reference

Parse command line flags into a struct with tags

The library is a wrapper around the standard library's flag package providing a way to parse command line flags into a struct fields

The main features are:

  • Ignore unknown flags
  • Distinguish not passed flags from default values that is difficult with the standard flag package
  • More convenient way to define flags using struct tags
  • Using nested structs for similar flag groups

Example

go get github.com/cardinalby/go-struct-flags
Define your flags struct with tags:
import (
    flago "github.com/cardinalby/go-struct-flags"
)

type MyFlags struct {
    // Verbose can be filled both by "-v" and "-verbose" flags
    Verbose   int      `flags:"verbose,v" flagUsage:"verbose mode: 1,2,3"`
	
    // Login is optional, it will be set only if passed
    Login     *string  `flag:"login" flagUsage:"user login"`
	
    // FileNames will contain flag.Args() after Parse()
    FileNames []string `flagArgs:"true"`
}

// This is the way to set defaults:
myFlags := MyFlags{}
Create new FlagSet and register the struct:
flagSet := flago.NewFlagSet("myApp", flag.ExitOnError)
if err := flagSet.StructVar(&myFlags); err != nil {
    // error can happen if struct tags are invalid
    panic(err)
}
Parse command line flags:
// Use short form of "-v"
// Normally you would use os.Args[1:] instead of hardcoded values
if err := flagSet.Parse([]string{"-v", "2", "--login", "user1", "file1", "file2"}); err != nil {
    // Parse has default behavior
    panic(err)
}

// myFlags.Verbose == 2
// *myFlags.Login == "user1"
// myFlags.FileNames == []string{"file1", "file2"}
Check if flag is passed

Using pointer fields enables you to distinguish not passed flags from default values:

// Use long form of "--verbose" and don't pass "--login"
if err := flagSet.Parse([]string{"--verbose", "2"}); err != nil {
    // Parse has default behavior
    panic(err)
}

// myFlags.Verbose == 2
// myFlags.Login == nil
// len(myFlags.FileNames) == 0
Set defaults

Unlike std flag package the library doesn't provide a way to explicitly set "default" values.

You can do it in native way just assigning them to struct fields before parsing (both for pointer and non-pointer fields)

defaultLogin := "admin"
myFlags := MyFlags{
    Verbose: 1,
    Login: &defaultLogin,
}

// No flags are passed
if err := flagSet.Parse("file1", "file2"); err != nil {
    // Parse has default behavior
    panic(err)
}

// myFlags.Verbose == 1       <--- hasn't been changed
// *myFlags.Login == "admin"  <--- hasn't been changed
// myFlags.FileNames == []string{"file1", "file2"}
Using nested structs

You can create logically similar flag groups assigning them a prefix using nested structs:

type PersonFlags struct {
    Name  string `flag:"name" flagUsage:"person name"`
    Email string `flag:"email" flagUsage:"person email"`
}
type MyParentFlags struct {
    Sender   PersonFlags `flagPrefix:"sender-" flagUsagePrefix:"sender "`
    Receiver PersonFlags `flagPrefix:"receiver-" flagUsagePrefix:"receiver "`
}

flagSet := NewFlagSet("myApp", flag.ExitOnError)
myFlags := MyParentFlags{}
if err := flagSet.StructVar(&myFlags); err != nil {
    panic(err)
}

if err := flagSet.Parse([]string{
    "--sender-name", "John",
    "--sender-email", "j@email.com",
    "--receiver-name", "Dave",
    "--receiver-email", "d@email.com",
}); err != nil {
    panic(err)
}

// myFlags.Sender.Name == "John"
// myFlags.Sender.Email == "j@email.com"
// myFlags.Receiver.Name == "Dave"
// myFlags.Receiver.Email == "d@email.com"

See tests for more examples.

Constructing

The library provides two constructors for flago.FlagSet:

  • Wrap(*flag.FlagSet) that wraps the existing std flag.FlagSet instance that can have some flags already registered or be used to register new flags using its methods.
  • NewFlagSet() creates new flag.FlagSet instance and sets its Usage to flago.DefaultUsage
  • Functions with the names matching flago.FlagSet method names for a default flago.CommandLine FlagSet instance are available in the same manner as in the standard flag package.

Configure Parse() behavior

🔹 Ignore unknown flags

SetIgnoreUnknown(true) method call will make Parse() ignore unknown flags instead of returning an error.

To retrieve unknown flags that have been ignored, call GetIgnoredArgs() after Parse().

With unknown flags it's not always clear how to treat them: as bool flags or as flags with the following values. See docs for SetIgnoreUnknownAmbiguousAsBoolFlags(...) for details.

🔹 Allow parsing multiple aliases

SetAllowParsingMultipleAliases(true) method call will make Parse() not return an error if multiple aliases of the same field are passed. The last passed value will be used.

Default behavior is to return an error containing flago.ErrMultipleAliases.

Supported struct tags

To parse flags and args to struct fields you should use StructVar() or StructVarWithPrefix() methods.

The methods accept optional arguments of pointers to ignored fields. These fields will not be registered as flags.

The struct fields that don't have any "flag" tags will be ignored.

Define named flag(s) for a field

🔻 flag="name"

Defines flag name for a field. Unlike json package, if the name is not set, the field will be ignored.

  • Field should have type supported by flag package or be pointer to such type.
  • If the field is a pointer, it will be set only if the flag is passed to Parse().
  • If it's not a pointer and is the correspondent flag is not passed, its default value will remain.
🔻 flags="name1,name2"

Same as flag but defines multiple comma-separated flag names (aliases) for a field.

  • You should use either flag or flags tag for a field, not both.
  • By default, Parse() will return an error containing flago.ErrMultipleAliases if multiple aliases of the same field are passed. You can change this behavior using SetAllowParsingMultipleAliases(true)
🔸 flagUsage="message"

Defines flag usage message for a field. Should be used only for fields with flag or flags tag.

🔸 flagRequired="true"

Defines that the field is required and Parse() will return an error containing flago.ErrIsRequired if the flag is not passed and doesn't have a default value (field is not initialized by non-zero value at the moment of registration)

Assign remaining args

🔻 flagArgs="true"

Field will be filled with flag.Args() (remaining command line args after named flags) after Parse().

  • Other "flag" tags should not be used for such fields.

Describe nested structs

The library parses fields in nested structs if explicitly instructed with flagPrefix tag on a field containing another struct.

🔻 flagPrefix="pref"

Instructs the library to parse fields in nested struct.

  • All resulting flag names (specified by flag and flags tags) in the nested struct will have the specified prefix.
  • With flagPrefix="" nested struct will still be parsed but without using prefix for its fields.
  • The prefix does not affect fields tagged with flagArgs.
🔸 flagUsagePrefix="usage_pref"

This tag is used only for nested struct fields with flagPrefix tag.

Instructs the library to use the specified prefix for flag usage messages of fields in nested struct.

Usage help message

If you use flago.NewFlagSet() constructor, resulting FlagSet will assign own default implementation of Usage that prints help message in the same manner as the standard flag package but grouping aliases assigned to a field using flags tag in one line.

If you use flago.Wrap() constructor, it doesn't override default Usage of the standard FlagSet. You can do it manually: flagSet.Usage = flago.DefaultUsage

Field types support
  • StructVar() method parses fields and their tags and calls the correspondent FlagSet.***Var() methods depending on the field type.
  • So fields should have types supported by flag package or be pointers to such types.
  • Fields implementing flag.Value and func(string) error fields are also supported (but can't be pointers).
Special case

If a field has encoding.TextUnmarshaler interface, it also should implement encoding.TextMarshaler.

The library will call FlagSet.TextVar() on such fields that requires a default "marshaler" value.

cmdargs sub-package

Provides helper tools for manipulating command line arguments:

  • Iterate over arguments as tokens with known roles
  • Iterate over flags with values, unnamed args, ...
  • Lookup for flags by name
  • Delete flag by name
  • Upsert flag by name
  • Mutate flags (make it inline, change value, name, ...)
  • Strip unknown flags

Documentation ¶

Index ¶

Constants ¶

This section is empty.

Variables ¶

View Source
var CommandLine = Wrap(flag.CommandLine)

CommandLine is a default FlagSet that is used by the package functions. It's a wrapper around flag.CommandLine to follow the same pattern as in the stdlib.

View Source
var ErrFlagRedefined = errors.New("flag redefined")
View Source
var ErrIsRequired = errors.New("flag is required")
View Source
var ErrMultipleAliases = errors.New("multiple aliases for the same flag are used")
View Source
var Usage = func() {
	printUsageTitle(CommandLine.FlagSet, os.Args[0])
	PrintDefaults()
}

Functions ¶

func DefaultUsage ¶

func DefaultUsage(flagSet *FlagSet)

DefaultUsage prints the default FlagSet usage to flagSet.Output grouping alternative flag names

func GetIgnoredArgs ¶ added in v1.0.1

func GetIgnoredArgs() []string

GetIgnoredArgs returns a slice of arguments that were ignored during the last call to Parse() because of SetIgnoreUnknown(true), nil otherwise

func Parse ¶

func Parse() error

Parse parses the command-line flags using the default FlagSet

func PrintDefaults ¶

func PrintDefaults()

PrintDefaults prints the default FlagSet usage to stdout grouping alternative flag names

func PrintFlagSetDefaults ¶

func PrintFlagSetDefaults(flagSet *FlagSet)

PrintFlagSetDefaults prints flag names and usage grouping alternative flag names

func SetAllowParsingMultipleAliases ¶

func SetAllowParsingMultipleAliases(allow bool)

SetAllowParsingMultipleAliases sets the behavior of Parse() when multiple tag names assigned to same field are passed. If `true`, it will be ignored and only the last value will be used. If `false`, Parse() will return an error. Default value is `false`.

func SetIgnoreUnknown ¶ added in v1.0.0

func SetIgnoreUnknown(ignore bool)

SetIgnoreUnknown sets the behavior of Parse() when unknown flags are passed. If `true`, they will be ignored. If `false`, Parse() will return an error. Default value is `false`.

func SetIgnoreUnknownAmbiguousAsBoolFlags ¶ added in v1.1.0

func SetIgnoreUnknownAmbiguousAsBoolFlags(treatAsBool bool)

SetIgnoreUnknownAmbiguousAsBoolFlags sets the behavior of Parse() when unknown flags are passed, and they are ambiguous with known bool flags. If `true`, they will be treated as bool flags. If `false`, Parse() will return an error. Default value is `false`.

func StructVar ¶

func StructVar(p any, ignoredFields ...any) error

StructVar registers the given struct with the default FlagSet `ignoredFields` is a slice of pointers to fields that should be ignored and not registered as flags See FlagSet.StructVar

func StructVarWithPrefix ¶

func StructVarWithPrefix(p any, flagsPrefix string, ignoredFields ...any) error

StructVarWithPrefix registers the given struct with the default FlagSet using the given prefix for flag names. `ignoredFields` is a slice of pointers to fields that should be ignored and not registered as flags See FlagSet.StructVarWithPrefix

Types ¶

type FlagSet ¶

type FlagSet struct {
	*flag.FlagSet
	// contains filtered or unexported fields
}

FlagSet is a wrapper around *flag.FlagSet that allows to register structs parsing their fields as flags.

func NewFlagSet ¶

func NewFlagSet(name string, errorHandling flag.ErrorHandling) *FlagSet

NewFlagSet creates a new FlagSet wrapping new flag.FlagSet with the given name and error handling policy and assigns its Usage to the own implementation that groups alternative flag names

func Wrap ¶

func Wrap(stdFlagSet *flag.FlagSet) *FlagSet

Wrap creates a new FlagSet wrapping the given `stdFlagSet` and does not set stdFlagSet.Usage

func (*FlagSet) GetIgnoredArgs ¶ added in v1.0.1

func (fls *FlagSet) GetIgnoredArgs() []string

GetIgnoredArgs returns a slice of arguments that were ignored during the last call to Parse() because of SetIgnoreUnknown(true), nil otherwise

func (*FlagSet) Parse ¶

func (fls *FlagSet) Parse(arguments []string) error

Parse parses the command-line flags calling Parse on the wrapped FlagSet and then sets values of the registered structs fields for flags that were actually parsed.

func (*FlagSet) PrintDefaults ¶

func (fls *FlagSet) PrintDefaults()

PrintDefaults prints the default FlagSet usage to wrapped FlagSet.Output grouping alternative flag names

func (*FlagSet) SetAllowParsingMultipleAliases ¶

func (fls *FlagSet) SetAllowParsingMultipleAliases(allow bool)

SetAllowParsingMultipleAliases sets the behavior of Parse() when multiple tag names assigned to same field are passed. If `true`, it will be ignored and only the last value will be used. If `false`, Parse() will return an error. Default value is `false`.

func (*FlagSet) SetIgnoreUnknown ¶ added in v1.0.0

func (fls *FlagSet) SetIgnoreUnknown(ignore bool)

SetIgnoreUnknown sets the behavior of Parse() when unknown flags are passed. If `true`, they will be ignored. If `false`, Parse() will return an error. Default value is `false`.

func (*FlagSet) SetIgnoreUnknownAmbiguousAsBoolFlags ¶ added in v1.1.0

func (fls *FlagSet) SetIgnoreUnknownAmbiguousAsBoolFlags(treatAsBool bool)

SetIgnoreUnknownAmbiguousAsBoolFlags specifies behaviour of stripping ambiguous unknown flags if SetIgnoreUnknown(true) is set. Unknown flag without inline value can be treated as bool flag or as flag name that should be followed by value. If the flag is unknown, we can't know if it's bool flag or not. Example: "-a -b" can be treated as: 1. {a: "-b"} - id - if treatAsBool == false OR 2. {a: true, b: true} - if treatAsBool == true Default values is `false`. It doesn't affect flags from fields that are defined in a registered struct but were passed as ignored to Parse() call. Information about their type will be used to determine if they are bool flags or not.

func (*FlagSet) StructVar ¶

func (fls *FlagSet) StructVar(p any, ignoredFields ...any) error

StructVar registers the fields of the given struct as a flags `ignoredFields` is a slice of pointers to fields that should be ignored and not registered as flags

func (*FlagSet) StructVarWithPrefix ¶

func (fls *FlagSet) StructVarWithPrefix(p any, flagsPrefix string, ignoredFields ...any) (err error)

StructVarWithPrefix registers the fields of the given struct as a flags with names prefixed with `flagsPrefix` `ignoredFields` is a slice of pointers to fields that should be ignored and not registered as flags

Directories ¶

Path Synopsis

Jump to

Keyboard shortcuts

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