go-arg

repository·master·Indexed 25 days ago

https://github.com/alexflint/go-arg

A struct-based command line argument parsing library for Go. It allows developers to define CLI interfaces using standard Go structs and tags to map flags, environment variables, and positional arguments directly to struct fields. Features include support for subcommands, custom parsing via encoding.TextUnmarshaler, default values, and automated help/version text generation.

Tokens
3.2K
Snippets
12
Records
25
Agent score
81%

What's inside go-arg

  1. Implement subcommands

    master

    Subcommands allow grouping functions (like git checkout).

    Rules for subcommands:

    • The subcommand tag must be used with fields that are pointers to structs.
    • Any struct containing a subcommand must not contain positional arguments.
    • To make a subcommand mandatory, check p.Subcommand() == nil after parsing.
    type CheckoutCmd struct {
    	Branch string `arg:"positional"`
    	Track  bool   `arg:"-t"`
    }
    
    var args struct {
    	Checkout *CheckoutCmd `arg:"subcommand:checkout"` 
    	Quiet    bool         `arg:"-q"` // Global flag
    }
    
    arg.MustParse(&args)
    
    if args.Checkout != nil {
        // handle checkout
    }
  2. Basic usage of go-arg

    master

    Declare command line arguments by defining a struct and using arg.MustParse(&args). The fields in the struct automatically map to command line flags.

    var args struct {
    	Foo string
    	Bar bool
    }
    arg.MustParse(&args)
    fmt.Println(args.Foo, args.Bar)
  3. Use environment variables

    master

    You can map struct fields to environment variables using the arg:"env" tag.

    • To use a specific variable name: arg:"env:VAR_NAME".
    • To combine a flag name and an environment variable: arg:"--flag,env:VAR_NAME".
    • To provide multiple values via environment variables, use a comma-separated string (e.g., VAR=1,2,3).
    • You can set a global prefix for all environment variables using arg.Config{EnvPrefix: "PREFIX_"}.
    // Specific environment variable
    var args struct {
    	Workers int `arg:"env:NUM_WORKERS"`
    }
    
    // Combined flag and environment variable
    var args struct {
    	Workers int `arg:"--count,env:NUM_WORKERS"`
    }
    
    // Using a global prefix
    p, err := arg.NewParser(arg.Config{
        EnvPrefix: "MYAPP_",
    }, &args)
  4. Define required arguments

    master

    Use the arg:"required" tag to make a field mandatory. If the argument is missing, the parser will return an error and display usage information.

    var args struct {
    	ID      int `arg:"required"`
    	Timeout time.Duration
    }
    arg.MustParse(&args)
  5. Custom parsing with encoding.TextUnmarshaler

    master

    To define custom parsing logic for a type, implement the encoding.TextUnmarshaler interface. To ensure the default value is displayed correctly in the help text, also implement encoding.TextMarshaler.

    type NameDotName struct {
    	head, tail string
    }
    
    func (n *NameDotName) UnmarshalText(b []byte) error {
    	s := string(b)
    	// ... parsing logic ...
    	return nil
    }
    
    func (n *NameDotName) MarshalText() ([]byte, error) {
    	return []byte(fmt.Sprintf("%s.%s", n.head, n.tail)), nil
    }
  6. Define positional arguments

    master

    Use the arg:"positional" tag to treat a field as a positional argument rather than a named flag. This works for single values and slices (for multiple values).

    var args struct {
    	Input   string   `arg:"positional"`
    	Output  []string `arg:"positional"`
    }
    arg.MustParse(&args)
  7. Customize help text and usage strings

    master

    You can enhance the generated help output using several methods:

    • Help text: Use the help:"description" tag on struct fields.
    • Placeholders: Use the placeholder:"NAME" tag to change the text used in usage strings (e.g., [--optimize LEVEL] instead of [--optimize INT]).
    • Description: Implement a Description() string method on your args struct to add a header to the help text.
    • Epilogue: Implement an Epilogue() string method to add text to the end of the help text.
    type args struct {
    	Input string `arg:"positional" placeholder:"SRC"` 
    }
    
    func (args) Description() string {
    	return "this program does something"
    }
  8. Handle --help and --version programmatically

    master

    Instead of using arg.MustParse, use arg.NewParser and p.Parse(os.Args[1:]) to intercept help and version requests. This allows you to control how the program exits or how help is displayed (e.g., for subcommands).

    Common error signals:

    • arg.ErrHelp: User requested --help.
    • arg.ErrVersion: User requested --version.
    p, err := arg.NewParser(arg.Config{}, &args)
    err = p.Parse(os.Args[1:])
    switch {
    case err == arg.ErrHelp:
    	p.WriteHelp(os.Stdout)
    	os.Exit(0)
    case err == arg.ErrVersion:
    	fmt.Println(args.Version())
    	os.Exit(0)
    case err != nil:
    	fmt.Printf("error: %v\n", err)
    	p.WriteUsage(os.Stdout)
    	os.Exit(1)
    }
  9. Arguments with multiple values and maps

    master

    Support for complex types:

    • Slices: To accept multiple values for a single flag (e.g., --ids 1 2 3), use a slice type. Use the arg:"separate" tag if you want to allow the flag to be specified multiple times with separate values.
    • Maps: Use maps to accept key-value pairs (e.g., --userids john=123).
    // Multiple values
    var args struct {
    	Database string
    	IDs      []int64
    }
    
    // Multiple values with 'separate' tag
    var args struct {
        Commands  []string `arg:"-c,separate"` 
    }
    
    // Key-value pairs
    var args struct {
    	UserIDs map[string]int
    }
  10. Configure default values

    master

    Use the default:"value" tag to provide a fallback value. The precedence order is:

    1. Command line arguments
    2. Environment variables (if env tag is present)
    3. Default values

    You can ignore environment variables or default values globally by configuring arg.Config with IgnoreEnv: true or IgnoreDefault: true.

    var args struct {
        Test  string `arg:"-t,env:TEST" default:"something"`
    }
    arg.MustParse(&args)
  11. Configure the parser with Config

    master

    The arg.Config struct allows you to customize the behavior of the parser. Key options include:

    • Program: The name of the program used in help text.
    • IgnoreEnv: If true, the library will not read environment variables.
    • IgnoreDefault: If true, the library will not reset variables to their default values.
    • StrictSubcommands: If true, global commands are not allowed after a subcommand has been encountered.
    • EnvPrefix: A prefix applied to all environment variable names.
    • AllHaveEnv: If true, every field is assigned an environment variable (defaults to the uppercase field name).
    • DefaultEnvName: A function to dynamically determine the environment variable name for a field.
    • Exit: A function called to terminate the process (defaults to os.Exit).
    • Out: An io.Writer where help, usage, and error messages are printed (defaults to os.Stdout).