urfave/cli

repository·main·Indexed 12 days ago

https://github.com/urfave/cli

A declarative Go library for building command-line applications. It provides support for command hierarchies, subcommands, flag parsing, shell completion for bash, zsh, fish, and powershell, and multiple input sources including environment variables and files. The library is designed to be simple, fast, and has no dependencies outside of the Go standard library.

Tokens
59.8K
Snippets
181
Records
239
Agent score
97%

What's inside urfave/cli

  1. Overview of urfave/cli features

    main

    urfave/cli is a declarative Go package for building command line interfaces. It is designed to be simple, fast, and has no dependencies outside of the Go standard library.

    Key features include:

    • Command Hierarchy: Support for commands and subcommands with alias and prefix matching.
    • Help System: A flexible and permissive help system.
    • Shell Completion: Dynamic completion for bash, zsh, fish, and powershell.
    • Flag Support: Input flags for simple types, slices, time.Time, time.Duration, and more. It also supports compound short flags (e.g., -abc instead of -a -b -c).
    • Input Sources: Supports looking up values from environment variables, plain text files, and structured file formats (via the urfave/cli-altsrc module).
    • Documentation: Capability to generate man pages and Markdown documentation (via the urfave/cli-docs module).
  2. Constraints when using UseShortOptionHandling

    main

    When UseShortOptionHandling is set to true, you must avoid using any flag names that start with a single leading dash (-).

    • Invalid: Using a flag named -option will cause failures because the parser will attempt to interpret it as a cluster of short options.
    • Valid: Flags with two leading dashes (e.g., --options) remain fully supported and valid.
  3. Flag value precedence order

    main

    When determining the value of a flag, urfave/cli follows this precedence (from highest to lowest):

    1. Command line flag value provided by the user
    2. Environment variable (if EnvVar is specified)
    3. Configuration file (if using altsrc or FilePath)
    4. Default value defined on the flag (Value field)
  4. Use GenericFlag for custom types

    main

    If you have a custom type that needs to be used as a CLI flag, implement the flag.Value interface (from the standard flag package) and use cli.GenericFlag.

    To implement flag.Value, your type must have:

    1. Set(value string) error
    2. String() string

    Then, register it in your Flags slice using &cli.GenericFlag{Name: "your-flag", Value: &yourType{}}.

    type genericType struct {
    	s string
    }
    
    func (g *genericType) Set(value string) error {
    	g.s = value
    	return nil
    }
    
    func (g *genericType) String() string {
    	return g.s
    }
    
    // In cli.App definition
    Flags: []cli.Flag{
    	&cli.GenericFlag{Name: "wat", Value: &genericType{}},
    }
  5. Best practices for managing binary size in urfave/cli

    main

    When building applications with urfave/cli, follow these practices to keep the binary footprint small:

    • Use -trimpath: Ensures reproducible paths.
    • Use -ldflags="-s -w": Use for release builds when debug symbols are unnecessary.
    • Isolate Integrations: Keep optional integrations in separate packages to avoid pulling in large dependencies into your main binary.
    • Minimize Reflection: Avoid adding reflection-heavy dependencies to the main command package unless they are strictly required at runtime.
    • Manage Shell Completion: Shell completion is part of the core package. If your application does not require it, ensure EnableShellCompletion is disabled and measure the size impact.
  6. Set flag defaults from a file using FilePath

    main

    The FilePath field allows you to set a default value for a flag by reading it from a specific file on disk.

    Precedence: Values loaded via FilePath take precedence over values loaded via EnvVar and the default Value defined on the flag.

    app.Flags = []cli.Flag {
      cli.StringFlag{
        Name: "password, p",
        Usage: "password for the mysql database",
        FilePath: "/etc/mysql/password",
      },
    }
  7. Set flag defaults from Environment Variables

    main

    You can configure a flag to use an environment variable as its default value using the EnvVar field.

    Cascading Environment Variables: You can provide a comma-delimited list to EnvVar. The library will use the first environment variable that is set. For example, EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG" will check those variables in order.

    Precedence: Environment variables take precedence over the Value defined on the flag, but are overridden by command line flags.

    app.Flags = []cli.Flag {
      cli.StringFlag{
        Name: "lang, l",
        Value: "english",
        Usage: "language for the greeting",
        EnvVar: "APP_LANG",
      },
    }
  8. Difference between Path() and Lineage()

    main

    Both methods allow you to inspect the command hierarchy, but they serve different purposes:

    • Path(): Returns a []string of command names starting from the root to the current command. Use this when you only need the names of the commands.
    • Lineage(): Returns a []*Command slice containing the current command and all its ancestors, starting from the child first. Use this when you need access to the actual *Command objects (e.g., to access their flags, metadata, or other properties).
  9. Precedence of flag value sources

    main

    When determining a flag's value, urfave/cli follows this order of precedence (from highest to lowest):

    1. Command line flag (provided by the user)
    2. Environment variable (if EnvVars is configured)
    3. Configuration file (if using altsrc or FilePath)
    4. Default value (defined on the flag)
  10. Implement command lifecycle hooks

    main

    Commands in urfave/cli/v3 support several lifecycle hooks that allow you to execute logic at specific stages of command execution:

    1. Before: Executed after flags are parsed but before the Action. It receives a context.Context and the *cli.Command. It can return a modified context or an error to abort execution.
    2. Action: The main logic of the command.
    3. After: Executed after the Action completes. It is used for cleanup or post-execution reporting.
    4. OnUsageError: A hook called when a usage error occurs (e.g., invalid flags or arguments). It allows for custom error formatting or handling.
    5. CommandNotFound: A global hook called when a requested command is not recognized.
  11. Implement subcommands and nested commands

    main

    Commands in urfave/cli can be nested using the Subcommands field of a *cli.Command. Each command can have its own Flags, Action, and lifecycle hooks (Before, After).

    Example hierarchy:

    • app (Root)
      • doo (Command)
        • wop (Subcommand)

    When a subcommand is executed, the Action of the parent command is typically skipped unless explicitly called via cCtx.Command.Run(cCtx).

    &cli.Command{
    	Name:        "doo",
    	Aliases:     []string{"do"},
    	Flags: []cli.Flag{
    		&cli.BoolFlag{Name: "forever", Aliases: []string{"forevvarr"}},
    	},
    	Subcommands: []*cli.Command{
    		{
    			Name:   "wop",
    			Action: wopAction,
    		},
    	},
    	Action: func(cCtx *cli.Context) error {
    		if cCtx.Bool("forever") {
    			cCtx.Command.Run(cCtx)
    		}
    		return nil
    	},
    }