### Example Help Output Source: https://github.com/peterbourgon/ff/blob/main/README.md Illustrates the expected help text output for a command with nested flag sets. This output is generated when the -h or --help flag is used or when parsing fails. ```shell $ childcommand -h NAME childcommand FLAGS (childcommand) -c, --compress enable compression -t, --transform enable transformation --refresh DURATION refresh interval (default: 15s) FLAGS (parentcommand) -l, --log STRING log level: debug, info, error (default: info) --config STRING config file (optional) err=parse args: flag: help requested ``` -------------------------------- ### Create Hierarchical Flag Sets with SetParent Source: https://context7.com/peterbourgon/ff/llms.txt Use SetParent to assign a parent flag set to a child, enabling the child to inherit flags from the parent. This is useful for command trees where subcommands need access to parent flags. The example demonstrates parsing both child and parent flags. ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { // Parent flag set with global options parentfs := ff.NewFlagSet("parentcommand") var ( loglevel = parentfs.StringEnum('l', "log", "log level: debug, info, error", "info", "debug", "error") _ = parentfs.StringLong("config", "", "config file (optional)") ) // Child flag set inherits parent flags childfs := ff.NewFlagSet("childcommand").SetParent(parentfs) var ( compress = childfs.Bool('c', "compress", "enable compression") transform = childfs.Bool('t', "transform", "enable transformation") refresh = childfs.DurationLong("refresh", 15*time.Second, "refresh interval") ) // Parse child flag set - will accept both child and parent flags err := ff.Parse(childfs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(childfs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("loglevel=%v compress=%v transform=%v refresh=%v\n", *loglevel, *compress, *transform, *refresh) } // Command: childcommand --log=debug --refresh=1s -c // Output: loglevel=debug compress=true transform=false refresh=1s // Help output shows both child and parent flags: // NAME // childcommand // // FLAGS (childcommand) // -c, --compress enable compression // -t, --transform enable transformation // --refresh DURATION refresh interval (default: 15s) // // FLAGS (parentcommand) // -l, --log STRING log level: debug, info, error (default: info) // --config STRING config file (optional) ``` -------------------------------- ### Define Flags from Struct Tags with AddStruct Source: https://context7.com/peterbourgon/ff/llms.txt Use AddStruct to define flags from a struct with `ff:` tags. Each tagged field becomes a flag, supporting short names, long names, usage text, default values, and placeholders. The example shows parsing flags into a struct and printing the values. ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) type Config struct { Listen string `ff:"short=l, long=listen, usage='listen address', default=localhost:8080"` Timeout time.Duration `ff:"long=timeout, usage='request timeout', default=30s"` Debug bool `ff:"short=d, long=debug, usage='enable debug mode'"` Count int `ff:"short=n, long=count, usage='number of retries', default=3"` Config string `ff:"long=config, usage='config file path'"` } func main() { var cfg Config fs := ff.NewFlagSetFrom("myprogram", &cfg) err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("MYPROGRAM"), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("listen=%s timeout=%v debug=%v count=%d\n", cfg.Listen, cfg.Timeout, cfg.Debug, cfg.Count) } // Command: myprogram -l :9090 --timeout=1m -d -n 5 // Output: listen=:9090 timeout=1m0s debug=true count=5 // Struct tag format: // ff:"short=X, long=name, usage='help text', default=value, placeholder=PH, nodefault, noplaceholder" ``` -------------------------------- ### Build CLI Applications with ff.Command Source: https://context7.com/peterbourgon/ff/llms.txt Demonstrates building a CLI application with root and subcommands using ff.Command. Includes flag parsing and execution logic. ```go package main import ( "context" "fmt" "os" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { // Root command with global flags rootFlags := ff.NewFlagSet("textctl") verbose := rootFlags.Bool('v', "verbose", "increase log verbosity") rootCmd := &ff.Command{ Name: "textctl", Usage: "textctl [FLAGS] ", Flags: rootFlags, } // Repeat subcommand repeatFlags := ff.NewFlagSet("repeat").SetParent(rootFlags) n := repeatFlags.IntShort('n', 3, "how many times to repeat") repeatCmd := &ff.Command{ Name: "repeat", Usage: "textctl repeat [-n TIMES] ", ShortHelp: "repeatedly print the first argument to stdout", Flags: repeatFlags, Exec: func(ctx context.Context, args []string) error { if len(args) == 0 { return fmt.Errorf("repeat requires an argument") } if *verbose { fmt.Fprintf(os.Stderr, "repeating %q %d times\n", args[0], *n) } for i := 0; i < *n; i++ { fmt.Println(args[0]) } return nil }, } rootCmd.Subcommands = append(rootCmd.Subcommands, repeatCmd) // Count subcommand countFlags := ff.NewFlagSet("count").SetParent(rootFlags) countCmd := &ff.Command{ Name: "count", Usage: "textctl count [ ... ]", ShortHelp: "count the number of bytes in the arguments", Flags: countFlags, Exec: func(ctx context.Context, args []string) error { var total int for _, arg := range args { total += len(arg) } fmt.Printf("%d bytes\n", total) return nil }, } rootCmd.Subcommands = append(rootCmd.Subcommands, countCmd) // Parse and run if err := rootCmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil { fmt.Fprintf(os.Stderr, "%s\n", ffhelp.Command(rootCmd)) fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } } ``` ```text Command: textctl repeat -n 5 hello Output: hello hello hello hello hello ``` ```text Command: textctl -v repeat -n 2 world Output: repeating "world" 2 times world world ``` ```text Command: textctl count foo bar baz Output: 9 bytes ``` ```text Command: textctl -h Output: COMMAND textctl USAGE textctl [FLAGS] SUBCOMMANDS repeat repeatedly print the first argument to stdout count count the number of bytes in the arguments FLAGS (textctl) -v, --verbose increase log verbosity ``` -------------------------------- ### Define ff.Command with Subcommands Source: https://github.com/peterbourgon/ff/blob/main/README.md Shows how to define a root command with flags and subcommands using ff.Command. Use this structure for building complex CLI applications with multiple operations. ```go // textctl -- root command textctlFlags := ff.NewFlagSet("textctl") verbose := textctlFlags.Bool('v', "verbose", "increase log verbosity") textctlCmd := &ff.Command{ Name: "textctl", Usage: "textctl [FLAGS] SUBCOMMAND ...", Flags: textctlFlags, } // textctl repeat -- subcommand repeatFlags := ff.NewFlagSet("repeat").SetParent(textctlFlags) // <-- set parent flag set n := repeatFlags.IntShort('n', 3, "how many times to repeat") repeatCmd := &ff.Command{ Name: "repeat", Usage: "textctl repeat [-n TIMES] ARG", ShortHelp: "repeatedly print the first argument to stdout", Flags: repeatFlags, Exec: func(ctx context.Context, args []string) error { /* ... */ }, } textctlCmd.Subcommands = append(textctlCmd.Subcommands, repeatCmd) // <-- append to parent subcommands // ... if err := textctlCmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil { fmt.Fprintf(os.Stderr, "%s\n", ffhelp.Command(textctlCmd)) fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } ``` -------------------------------- ### Generate Help Text for ff Commands Source: https://context7.com/peterbourgon/ff/llms.txt Use ffhelp.Command to generate comprehensive help output for commands, including subcommand listings, usage information, and hierarchical flag documentation. This is useful for creating user-friendly command-line interfaces. ```go package main import ( "context" "fmt" "os" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { rootFlags := ff.NewFlagSet("kubectl") rootFlags.StringLong("kubeconfig", "", "path to kubeconfig file") rootFlags.StringLong("context", "", "kubernetes context to use") rootFlags.Bool('v', "verbose", "verbose output") rootCmd := &ff.Command{ Name: "kubectl", Usage: "kubectl [FLAGS] [args...]", ShortHelp: "Kubernetes command-line tool", LongHelp: "kubectl controls the Kubernetes cluster manager.\n\nFind more information at: https://kubernetes.io/docs/reference/kubectl/", Flags: rootFlags, } // Add subcommands getFlags := ff.NewFlagSet("get").SetParent(rootFlags) getFlags.StringShort('o', "json", "output format (json, yaml, wide)") getCmd := &ff.Command{ Name: "get", Usage: "kubectl get [name]", ShortHelp: "Display one or many resources", Flags: getFlags, Exec: func(ctx context.Context, args []string) error { return nil }, } applyFlags := ff.NewFlagSet("apply").SetParent(rootFlags) applyFlags.StringShort('f', "", "filename or directory") applyCmd := &ff.Command{ Name: "apply", Usage: "kubectl apply -f ", ShortHelp: "Apply a configuration to a resource", Flags: applyFlags, Exec: func(ctx context.Context, args []string) error { return nil }, } rootCmd.Subcommands = []*ff.Command{getCmd, applyCmd} // Show help fmt.Println(ffhelp.Command(rootCmd)) } ``` -------------------------------- ### Generate Help Text for Flag Sets with ffhelp Source: https://context7.com/peterbourgon/ff/llms.txt Use ffhelp.Flags to generate formatted help text for flag sets, including hierarchical parent flag sets. Provide a usage string for the command. ```go package main import ( "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { // Global flags globalFs := ff.NewFlagSet("global") globalFs.BoolLong("verbose", "enable verbose output") globalFs.StringLong("config", "", "path to config file") // Application flags with parent appFs := ff.NewFlagSet("myapp").SetParent(globalFs) appFs.String('h', "host", "localhost", "server hostname") appFs.Int('p', "port", 8080, "server port") appFs.DurationLong("timeout", 30*time.Second, "request timeout") appFs.StringEnum('l', "log-level", "logging level", "info", "debug", "warn", "error") appFs.BoolLong("dry-run", "simulate without making changes") // Generate help with usage lines help := ffhelp.Flags(appFs, "myapp [FLAGS] [args...]") fmt.Println(help) os.Exit(0) } ``` -------------------------------- ### Parse Flags and Emit Help Source: https://github.com/peterbourgon/ff/blob/main/README.md Demonstrates parsing flags with a parent-child flag set structure and emitting help text using ffhelp when an error occurs. Use when you need to handle nested flag sets and provide user-friendly help messages. ```go parentfs := ff.NewFlagSet("parentcommand") var ( loglevel = parentfs.StringEnum('l', "log", "log level: debug, info, error", "info", "debug", "error") _ = parentfs.StringLong("config", "", "config file (optional)") ) childfs := ff.NewFlagSet("childcommand").SetParent(parentfs) var ( compress = childfs.Bool('c', "compress", "enable compression") transform = childfs.Bool('t', "transform", "enable transformation") refresh = childfs.DurationLong("refresh", 15*time.Second, "refresh interval") ) if err := ff.Parse(childfs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ); err != nil { fmt.Printf("%s\n", ffhelp.Flags(childfs)) fmt.Printf("err=%v\n", err) } else { fmt.Printf("loglevel=%v compress=%v transform=%v refresh=%v\n", *loglevel, *compress, *transform, *refresh) } ``` -------------------------------- ### Parse .env Config Files with ffenv Source: https://context7.com/peterbourgon/ff/llms.txt Use ffenv.Parse to load configuration from .env files. Keys are matched using environment variable naming conventions (e.g., MYAPP_API_KEY). Supports quoted strings and escape sequences. ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffenv" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { fs := ff.NewFlagSet("myapp") var ( apiKey = fs.StringLong("api-key", "", "API key for authentication") timeout = fs.DurationLong("timeout", 30*time.Second, "request timeout") debug = fs.BoolLong("debug", "enable debug mode") _ = fs.StringLong("config", ".env", "path to .env file") ) err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("MYAPP"), // Match MYAPP_API_KEY, MYAPP_TIMEOUT, etc. ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ffenv.Parse), ff.WithConfigAllowMissingFile(), ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("api-key=%s timeout=%v debug=%v\n", *apiKey, *timeout, *debug) } // .env file: // # API Configuration // MYAPP_API_KEY=sk-1234567890abcdef // MYAPP_TIMEOUT=60s // MYAPP_DEBUG=true // // # Quoted values support escape sequences // MYAPP_MESSAGE="Hello\nWorld" // Command: myapp --config=.env // Output: api-key=sk-1234567890abcdef timeout=1m0s debug=true ``` -------------------------------- ### Parse Plain Text Config Files with ff.PlainParser Source: https://context7.com/peterbourgon/ff/llms.txt Utilizes ff.PlainParser to read configuration from plain text files. Supports comments, boolean flags, and inline comments. Command-line flags override config file settings. ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { fs := ff.NewFlagSet("myapp") var ( timeout = fs.DurationLong("timeout", time.Second, "request timeout") retries = fs.IntLong("retries", 3, "number of retries") verbose = fs.BoolLong("verbose", "enable verbose logging") host = fs.StringLong("host", "localhost", "server host") _ = fs.StringLong("config", "", "config file") ) err := ff.Parse(fs, os.Args[1:], ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ff.WithConfigAllowMissingFile(), // don't error if config file doesn't exist ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("timeout=%v retries=%d verbose=%v host=%s\n", *timeout, *retries, *verbose, *host) } ``` ```text Config file (app.conf): # This is a comment timeout 30s retries 5 verbose # boolean flag, equivalent to 'verbose true' host api.example.com # inline comment ``` ```text Command: myapp --config=app.conf Output: timeout=30s retries=5 verbose=true host=api.example.com ``` ```text Command line flags override config file: Command: myapp --config=app.conf --timeout=1m Output: timeout=1m0s retries=5 verbose=true host=api.example.com ``` -------------------------------- ### ff.FlagSet with short and long flags Source: https://github.com/peterbourgon/ff/blob/main/README.md ff.FlagSet offers a getopts(3)-inspired interface with short (-f) and long (--foo) flag names, and more flexible flag types. It integrates with environment variables and config files similarly to flag.FlagSet. ```go fs := ff.NewFlagSet("myprogram") var ( addrs = fs.StringSet('a', "addr", "remote address (repeatable)") compress = fs.Bool('c', "compress", "enable compression") transform = fs.Bool('t', "transform", "enable transformation") loglevel = fs.StringEnum('l', "log", "log level: debug, info, error", "info", "debug", "error") _ = fs.StringLong("config", "", "config file (optional)") ) ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ) fmt.Printf("addrs=%v compress=%v transform=%v loglevel=%v\n", *addrs, *compress, *transform, *loglevel) ``` -------------------------------- ### Configure ff Parsing Behavior Source: https://context7.com/peterbourgon/ff/llms.txt Configure ff parsing behavior using various options to control environment variable handling, config file options, and error handling strategies. The priority order for configuration sources is command-line arguments, environment variables, and then config files. ```go package main import ( "embed" "errors" "fmt" "os" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) //go:embed config/* var configFS embed.FS func main() { fs := ff.NewFlagSet("myapp") var ( host = fs.StringLong("host", "localhost", "server host") port = fs.IntLong("port", 8080, "server port") timeout = fs.StringLong("timeout", "30s", "request timeout") _ = fs.StringLong("config", "", "config file") ) err := ff.Parse(fs, os.Args[1:], // Environment variable options ff.WithEnvVarPrefix("MYAPP"), // Require MYAPP_ prefix ff.WithEnvVarSplit(","), // Split env values on comma: MYAPP_HOSTS=a,b,c ff.WithEnvVarCaseSensitive(), // Match exact case: MYAPP_Host not MYAPP_HOST ff.WithEnvVarShortNames(), // Also match short flag names: MYAPP_H for -h // Config file options ff.WithConfigFileFlag("config"), // Use --config flag value as config path ff.WithConfigFileParser(ff.PlainParser), ff.WithConfigAllowMissingFile(), // Don't error if config doesn't exist ff.WithConfigIgnoreUndefinedFlags(), // Ignore unknown flags in config file ff.WithFilesystem(configFS), // Use embedded filesystem // Advanced config options ff.WithConfigIgnoreFlagNames(), // Only match by env var names in config ff.WithConfigIgnoreEnvVars(), // Only match by flag names in config ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("host=%s port=%d timeout=%s\n", *host, *port, *timeout) } ``` -------------------------------- ### Parse YAML Config Files with ffyaml Source: https://context7.com/peterbourgon/ff/llms.txt Use ffyaml.Parse to load configuration from YAML files. Ensure the config file path is provided via the --config flag. ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" "github.com/peterbourgon/ff/v4/ffyaml" ) func main() { fs := ff.NewFlagSet("myapp") var ( appName = fs.StringLong("app.name", "myapp", "application name") appEnv = fs.StringLong("app.environment", "development", "environment") host = fs.StringLong("server.host", "localhost", "server host") port = fs.IntLong("server.port", 8080, "server port") timeout = fs.DurationLong("server.timeout", 30*time.Second, "request timeout") _ = fs.StringLong("config", "", "YAML config file") ) err := ff.Parse(fs, os.Args[1:], ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ffyaml.Parse), ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("app: %s (%s)\n", *appName, *appEnv) fmt.Printf("server: %s:%d (timeout: %v)\n", *host, *port, *timeout) } ``` ```yaml app: name: production-api environment: production server: host: 0.0.0.0 port: 443 timeout: 120s ``` -------------------------------- ### ff.Parse - Parse flags from args, env vars, and config files Source: https://context7.com/peterbourgon/ff/llms.txt The central function `ff.Parse` populates a flag set from multiple sources with configurable priority. It accepts either an `ff.FlagSet` or a standard library `flag.FlagSet`, along with options to control parsing behavior including environment variable prefixes and config file settings. ```APIDOC ## ff.Parse - Parse flags from args, env vars, and config files ### Description Populates a flag set from multiple sources with configurable priority. Supports standard library `flag.FlagSet` or `ff.FlagSet`. ### Method `ff.Parse(fs flag.FlagSet | ff.FlagSet, args []string, opts ...ff.Option) error` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Options (`ff.Option`) - `ff.WithEnvVarPrefix(prefix string)`: Specifies a prefix for environment variables. - `ff.WithConfigFileFlag(name string)`: Specifies the flag name for the config file. - `ff.WithConfigFileParser(parser ff.ConfigParser)`: Sets the configuration file parser (e.g., `ff.PlainParser`, `ff.JSONParser`). - `ff.WithConfigFileParserForSuffix(suffix string, parser ff.ConfigParser)`: Sets a parser for a specific file suffix. ### Request Example ```go package main import ( "errors" "flag" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { // Using standard library flag.FlagSet fs := flag.NewFlagSet("myprogram", flag.ContinueOnError) var ( listenAddr = fs.String("listen", "localhost:8080", "listen address") refresh = fs.Duration("refresh", 15*time.Second, "refresh interval") debug = fs.Bool("debug", false, "log debug information") _ = fs.String("config", "", "config file (optional)") ) err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), // MY_PROGRAM_LISTEN, MY_PROGRAM_DEBUG, etc. ff.WithConfigFileFlag("config"), // read config from --config flag value ff.WithConfigFileParser(ff.PlainParser), // use plain text config format ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(ff.NewFlagSetFrom("myprogram", fs))) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("listen=%s refresh=%s debug=%v\n", *listenAddr, *refresh, *debug) } ``` ### Response #### Success Response (200) Populated flag set. #### Response Example ``` listen=localhost:9090 refresh=15s debug=false ``` #### Error Response - `ff.ErrHelp`: If the help flag is present. - Other errors related to parsing or configuration. ``` -------------------------------- ### Parse TOML Config Files with fftoml Source: https://context7.com/peterbourgon/ff/llms.txt Use fftoml.Parse to load configuration from TOML files. Supports nested objects similar to the JSON parser. ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" "github.com/peterbourgon/ff/v4/fftoml" ) func main() { fs := ff.NewFlagSet("myapp") var ( serverHost = fs.StringLong("server.host", "localhost", "server hostname") serverPort = fs.IntLong("server.port", 8080, "server port") serverTimeout = fs.DurationLong("server.timeout", 30*time.Second, "server timeout") logLevel = fs.StringLong("logging.level", "info", "log level") logFormat = fs.StringLong("logging.format", "text", "log format") _ = fs.StringLong("config", "", "TOML config file") ) err := ff.Parse(fs, os.Args[1:], ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(fftoml.Parse), ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("server: %s:%d (timeout: %v)\n", *serverHost, *serverPort, *serverTimeout) fmt.Printf("logging: level=%s format=%s\n", *logLevel, *logFormat) } // config.toml: // [server] // host = "api.example.com" // port = 443 // timeout = "60s" // // [logging] // level = "debug" // format = "json" // Command: myapp --config=config.toml // Output: // server: api.example.com:443 (timeout: 1m0s) // logging: level=debug format=json ``` -------------------------------- ### Parse JSON Config Files with ffjson Source: https://context7.com/peterbourgon/ff/llms.txt Use ffjson.Parse to load configuration from JSON files. Supports nested objects where keys are joined by a delimiter (default '.') to form flag names. ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" "github.com/peterbourgon/ff/v4/ffjson" ) func main() { fs := ff.NewFlagSet("myapp") var ( serverHost = fs.StringLong("server.host", "localhost", "server hostname") serverPort = fs.IntLong("server.port", 8080, "server port") serverTimeout = fs.DurationLong("server.timeout", 30*time.Second, "server timeout") dbHost = fs.StringLong("database.host", "localhost", "database host") dbPort = fs.IntLong("database.port", 5432, "database port") debug = fs.BoolLong("debug", "enable debug mode") _ = fs.StringLong("config", "", "JSON config file") ) err := ff.Parse(fs, os.Args[1:], ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ffjson.Parse), ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("server: %s:%d (timeout: %v)\n", *serverHost, *serverPort, *serverTimeout) fmt.Printf("database: %s:%d\n", *dbHost, *dbPort) fmt.Printf("debug: %v\n", *debug) } // config.json: // { // "server": { // "host": "api.example.com", // "port": 443, // "timeout": "60s" // }, // "database": { // "host": "db.example.com", // "port": 5432 // }, // "debug": true // } // Command: myapp --config=config.json // Output: // server: api.example.com:443 (timeout: 1m0s) // database: db.example.com:5432 // debug: true ``` -------------------------------- ### Create Enhanced FlagSet with ff.NewFlagSet Source: https://context7.com/peterbourgon/ff/llms.txt Creates a getopts-style flag set supporting short (-f) and long (--foo) flag names, with helper methods for common types. Useful for complex CLIs requiring more control over flag definitions. ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { fs := ff.NewFlagSet("myprogram") var ( // Short and long names: -a/--addr addrs = fs.StringSet('a', "addr", "remote address (repeatable)") // Both short and long: -c/--compress compress = fs.Bool('c', "compress", "enable compression") // Both: -t/--transform transform = fs.Bool('t', "transform", "enable transformation") // Enum with valid values: -l/--log loglevel = fs.StringEnum('l', "log", "log level: debug, info, error", "info", "debug", "error") // Long name only timeout = fs.DurationLong("timeout", 30*time.Second, "request timeout") // Short name only verbose = fs.BoolShort('v', "verbose output") // Config file flag _ = fs.StringLong("config", "", "config file (optional)") ) err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("addrs=%v compress=%v transform=%v loglevel=%v timeout=%v verbose=%v\n", *addrs, *compress, *transform, *loglevel, *timeout, *verbose) } // Command: myprogram -afoo -a bar --addr=baz --addr qux -ct -v --log=debug // Output: addrs=[foo bar baz qux] compress=true transform=true loglevel=debug timeout=30s verbose=true // With environment: MY_PROGRAM_LOG=debug myprogram // Output: addrs=[] compress=false transform=false loglevel=debug timeout=30s verbose=false ``` -------------------------------- ### Parse flag.FlagSet with ff Source: https://github.com/peterbourgon/ff/blob/main/README.md Use ff.Parse instead of flag.FlagSet.Parse to load flags from command-line arguments, environment variables, and config files. Configure parsing behavior with options like environment variable prefixes and config file handling. ```go fs := flag.NewFlagSet("myprogram", flag.ContinueOnError) var ( listenAddr = fs.String("listen", "localhost:8080", "listen address") refresh = fs.Duration("refresh", 15*time.Second, "refresh interval") debug = fs.Bool("debug", false, "log debug information") _ = fs.String("config", "", "config file (optional)") ) ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ) fmt.Printf("listen=%s refresh=%s debug=%v\n", *listen, *refresh, *debug) ``` -------------------------------- ### Parse Flags with ff.Parse Source: https://context7.com/peterbourgon/ff/llms.txt Populates a flag set from command-line arguments, environment variables, and config files with configurable priority. Use with standard library flag.FlagSet for basic CLI applications. ```go package main import ( "errors" "flag" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { // Using standard library flag.FlagSet fs := flag.NewFlagSet("myprogram", flag.ContinueOnError) var ( listenAddr = fs.String("listen", "localhost:8080", "listen address") refresh = fs.Duration("refresh", 15*time.Second, "refresh interval") debug = fs.Bool("debug", false, "log debug information") _ = fs.String("config", "", "config file (optional)") ) err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), // MY_PROGRAM_LISTEN, MY_PROGRAM_DEBUG, etc. ff.WithConfigFileFlag("config"), // read config from --config flag value ff.WithConfigFileParser(ff.PlainParser), // use plain text config format ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(ff.NewFlagSetFrom("myprogram", fs))) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("listen=%s refresh=%s debug=%v\n", *listenAddr, *refresh, *debug) } // Command line: myprogram -listen=localhost:9090 // Output: listen=localhost:9090 refresh=15s debug=false // Environment: MY_PROGRAM_DEBUG=1 myprogram // Output: listen=localhost:8080 refresh=15s debug=true // Config file (my.conf): // refresh 30s // debug // Command: myprogram -config=my.conf // Output: listen=localhost:8080 refresh=30s debug=true ``` -------------------------------- ### ff.NewFlagSet - Create a getopts-style flag set Source: https://context7.com/peterbourgon/ff/llms.txt `ff.NewFlagSet` creates an enhanced flag set that supports both short (-f) and long (--foo) flag names, with type-specific helper methods for common flag types including bool, string, int, duration, and collections. ```APIDOC ## ff.NewFlagSet - Create a getopts-style flag set ### Description Creates an enhanced `FlagSet` supporting short (-f) and long (--foo) flag names, with type-specific helpers for various data types. ### Method `ff.NewFlagSet(name string) *ff.FlagSet` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### FlagSet Methods - `StringSet(short rune, long, usage string) *[]string`: Defines a repeatable string flag. - `Bool(short rune, long string, usage string) *bool`: Defines a boolean flag. - `StringEnum(short rune, long, usage string, defaultVal string, valid ...string) *string`: Defines an enum string flag. - `DurationLong(long string, defaultVal time.Duration, usage string) *time.Duration`: Defines a duration flag with a long name. - `BoolShort(short rune, usage string) *bool`: Defines a boolean flag with a short name. - `StringLong(long string, defaultVal string, usage string) *string`: Defines a string flag with a long name. ### Request Example ```go package main import ( "errors" "fmt" "os" "time" "github.com/peterbourgon/ff/v4" "github.com/peterbourgon/ff/v4/ffhelp" ) func main() { fs := ff.NewFlagSet("myprogram") var ( // Short and long names: -a/--addr addrs = fs.StringSet('a', "addr", "remote address (repeatable)") // Both short and long: -c/--compress compress = fs.Bool('c', "compress", "enable compression") // Both: -t/--transform transform = fs.Bool('t', "transform", "enable transformation") // Enum with valid values: -l/--log loglevel = fs.StringEnum('l', "log", "log level: debug, info, error", "info", "debug", "error") // Long name only timeout = fs.DurationLong("timeout", 30*time.Second, "request timeout") // Short name only verbose = fs.BoolShort('v', "verbose output") // Config file flag _ = fs.StringLong("config", "", "config file (optional)") ) err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ) if errors.Is(err, ff.ErrHelp) { fmt.Println(ffhelp.Flags(fs)) os.Exit(0) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Printf("addrs=%v compress=%v transform=%v loglevel=%v timeout=%v verbose=%v\n", *addrs, *compress, *transform, *loglevel, *timeout, *verbose) } ``` ### Response #### Success Response (200) Populated flag set. #### Response Example ``` addrs=[foo bar baz qux] compress=true transform=true loglevel=debug timeout=30s verbose=true ``` #### Error Response - `ff.ErrHelp`: If the help flag is present. - Other errors related to parsing or configuration. ``` -------------------------------- ### Hierarchical ff.FlagSet parsing Source: https://github.com/peterbourgon/ff/blob/main/README.md ff.FlagSet supports parent flag sets, allowing child flag sets to inherit and parse parent flags. This enables structured configuration for nested commands or components. ```go parentfs := ff.NewFlagSet("parentcommand") var ( loglevel = parentfs.StringEnum('l', "log", "log level: debug, info, error", "info", "debug", "error") _ = parentfs.StringLong("config", "", "config file (optional)") ) childfs := ff.NewFlagSet("childcommand").SetParent(parentfs) var ( compress = childfs.Bool('c', "compress", "enable compression") transform = childfs.Bool('t', "transform", "enable transformation") refresh = childfs.DurationLong("refresh", 15*time.Second, "refresh interval") ) ff.Parse(childfs, os.Args[1:], ff.WithEnvVarPrefix("MY_PROGRAM"), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser), ) fmt.Printf("loglevel=%v compress=%v transform=%v refresh=%v\n", *loglevel, *compress, *transform, *refresh) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.