Getting Started with goopt

Quick Start

1. Installation

go get github.com/napalu/goopt

2. Choose Your Style

Struct-First Approach

Names are optional, but if you want to use them, you can use the name tag to override the default name. If the name is not provided, goopt will use the default FlagNameConverter to convert the field name to a valid flag name in lowerCamelCase.

// Define your CLI structure using struct tags
type Options struct {
    // Global flags
    Verbose bool   `goopt:"short:v;desc:Enable verbose output"`
    Output  string `goopt:"short:o;desc:Output file;required:true"`
    
    // Commands and their flags
    Create struct {
        User struct {
            Name     string `goopt:"short:n;desc:Username to create;required:true"`
            Password string `goopt:"short:p;desc:User password;secure:true"`
        } `goopt:"kind:command;desc:Create a new user"`
    } `goopt:"kind:command;desc:Create resources"`
}

func main() {
    opts := &Options{}
    parser, _ := goopt.NewParserFromStruct(opts)
    
    if ok := parser.Parse(os.Args); !ok {
        fmt.Fprintln(os.Stderr, "Invalid command-line arguments:")
        for _, err := range parser.Errors() {
            fmt.Fprintf(os.Stderr, " - %s\n", err)
        }
        parser.PrintUsageWithGroups(os.Stdout)
        os.Exit(1)
    }
    
    // Access values directly through the struct
    if opts.Verbose {
        fmt.Println("Verbose mode enabled")
    }
}

Builder Approach

func main() {
    parser := goopt.NewParser()
    
    // Add global flags
    parser.AddFlag("verbose", goopt.NewArg(
        goopt.WithDescription("Enable verbose output"),
        goopt.WithShort("v"),
    ))
    
    // Add commands and their flags
    create := parser.AddCommand(goopt.NewCommand(
        goopt.WithName("create"),
        goopt.WithDescription("Create resources"),
    ))
    user := create.AddCommand(goopt.NewCommand(
        goopt.WithName("user"),
        goopt.WithDescription("Create a new user"),
    ))
    user.AddFlag(goopt.NewArg(
        goopt.WithShortFlag("n"),
        goopt.WithDescription("Username to create"),
        goopt.WithRequired(true),
    ))
    
    if !parser.Parse(os.Args) {
        parser.PrintUsageWithGroups(os.Stdout)
        return
    }
    
    // Access values through the parser
    if verbose, _ := parser.Get("verbose"); verbose == "true" {
        fmt.Println("Verbose mode enabled")
    }

    // Or access it as a boolean
    if v, _ := parser.GetBool("verbose"); v {
        fmt.Println("Verbose mode enabled")
    }

    // Or check if the flag is present and provide a default value
    if vd := parser.GetOrDefault("verbose", "false"); vd == "false" {
        fmt.Println("Verbose mode is disabled")
    }
}

Programmatic Definition with Commands

package main

import (
	"os"
	"fmt"
	"github.com/napalu/goopt"
    "github.com/napalu/goopt/types"
)

func main() {
	parser := goopt.NewParser()

	// Define flags
	parser.AddFlag("output", goopt.NewArg(
        goopt.WithDescription("Output file"),
        goopt.WithType(types.Single),
        goopt.WithRequired(true),
    ))

	// Define commands and subcommands
	createCmd := &goopt.Command{
		Name: "create",
		Subcommands: []goopt.Command{
			{Name: "user"},
			{Name: "group"},
		},
	}

	parser.AddCommand(createCmd)

	// Parse the command-line arguments
	if !parser.Parse(os.Args) {
		parser.PrintUsage(os.Stdout)
		return
	}

	// Access parsed flags
	output, _ := parser.Get("output")
	fmt.Println("Output:", output)

	// Access parsed commands
	cmdValue, _ := parser.GetCommandValue("create user")
	fmt.Println("Command value:", cmdValue)
}

Initialization using option functions

The library provides an interface for defining flags and commands.

package main

import (
	"os"
	"github.com/napalu/goopt"
    "github.com/napalu/goopt/types"
)

func main() {
	parser, _ := goopt.NewParser(
		goopt.WithFlag("testFlag", goopt.NewArg(goopt.WithType(types.Single))),
		goopt.WithCommand(
			goopt.NewCommand(goopt.WithName("testCommand")),
		),
	)

	parser.Parse(os.Args)
}

This interface allows for dynamic and flexible construction of command-line parsers.

3. Add Shell Completion (Optional)

import (
    "os"
    "log"
    "github.com/napalu/goopt"
    c "github.com/napalu/goopt/completion"
)

func main() {
    // ... parser setup as above ...
    
    // Add completion support
    exec, err := os.Executable()
    if err != nil {
        log.Fatal(err)
    }

    manager, err := c.NewManager("fish", exec)
    if err != nil {
        log.Fatal(err)
    }
    manager.Accept(parser.GetCompletionData())
    err = manager.Save()
    if err != nil {
        log.Fatal(err)
    }
    // depending on the shell, you may need to source the completion file

    // ... rest of your code ...
}

4. Environment Variables (Optional)

func main() {
    // ... parser setup as above ...
    
    // Enable environment variable support
    parser.SetEnvNameConverter(func(s string) string {
        // default flag name converter is lowerCamelCase
        return parser.DefaultFlagNameConverter(s)
    })
    
    // ... rest of your code ...
}

Version Compatibility

Go Version goopt Version

goopt supports all Go versions from 1.18 onward. See our compatibility policy for details.

Next Steps