Kong Command-Line Parser for Go

repository·master·Indexed 25 days ago

https://github.com/alecthomas/kong

A command-line parser for Go that maps complex CLI structures to Go types using struct tags. It supports nested commands, positional arguments, flags, and automatic help generation. Key features include lifecycle hooks, custom help providers via the HelpProvider interface, and the ability to serve a CLI interactively over SSH.

Tokens
13.1K
Snippets
20
Records
104
Agent score
83%

What's inside kong

  1. Introduction to Kong

    master
    Kong is a command-line parser for Go that allows you to express complex command-line structures using Go types. The structure and struct tags direct how the command line is mapped onto your Go structs.
  2. Inject Values into Run() Methods

    master

    When implementing command execution via Run(...) error methods, you can inject dependencies using several patterns:

    1. Bind(value): Bind a value directly.
    2. BindTo(interface): Bind a value to an interface type.
    3. BindToProvider(func): Bind a value to a provider function.
    4. Provide<Type>() error: Implement a provider method on the command structure itself.
  3. Use Variable Interpolation in Help and Defaults

    master

    Kong supports limited variable interpolation in help strings, placeholder strings, enum lists, and default values using the syntax ${<name>} or ${<name>=<default>}.

    Variables can be provided in two ways:

    1. Via kong.Vars: Pass a map of variables to kong.Parse.
    2. Via set tag: Use the set:"K=V" tag on a struct field. These variables are available to that node and all its children.

    Special variables available during interpolation:

    • ${default}: The default value.
    • ${enum}: The list of enum values.
    • ${env}: The name of the associated environment variable. If ${env} is used in a help string, Kong will automatically append ($${env}) to the help text.
    type cli struct {
      Config string `type:"path" default:"${config_file}"`
    }
    
    func main() {
      kong.Parse(&cli, 
        kong.Vars{
          "config_file": "~/.app.conf",
        })
    }
  4. Handle commands by attaching a Run() method

    master

    A robust way to handle commands is to define a Run(... error) method on your command structs.

    1. Define leaf commands as separate structs.
    2. Attach a Run(... error) method to these structs.
    3. Call ctx.Run(bindings...) to execute the selected command.

    Kong will traverse from the selected node back to the root, calling any Run() methods it encounters in reverse order. This allows for reusable sub-trees.

    type Context struct {
      Debug bool
    }
    
    type RmCmd struct {
      Force     bool `help:"Force removal."`
      Recursive bool `help:"Recursively remove files."` 
    
      Paths []string `arg:"" name:"path" help:"Paths to remove." type:"path"`
    }
    
    func (r *RmCmd) Run(ctx *Context) error {
      fmt.Println("rm", r.Paths)
      return nil
    }
    
    type LsCmd struct {
      Paths []string `arg:"" optional:"" name:"path" help:"Paths to list." type:"path"`
    }
    
    func (l *LsCmd) Run(ctx *Context) error {
      fmt.Println("ls", l.Paths)
      return nil
    }
    
    var cli struct {
      Debug bool `help:"Enable debug mode."` 
    
      Rm RmCmd `cmd:"" help:"Remove files."`
      Ls LsCmd `cmd:"" help:"List paths."`
    }
    
    func main() {
      ctx := kong.Parse(&cli)
      // Call the Run() method of the selected parsed command.
      err := ctx.Run(&Context{Debug: cli.Debug})
      ctx.FatalIfErrorf(err)
    }
  5. Generate help documentation in Kong

    master

    Kong automatically generates --help documentation based on your struct tags (help:"").

    • Top-level help: Displays available commands and global flags.
    • Contextual help: If a command is provided (e.g., app --help <command>), Kong shows detailed help for that specific command, including its flags and arguments.
    • Custom help: Any command or argument type implementing the Help() string interface can provide additional descriptive text that augments the standard help tags.
  6. Implement custom help providers using the HelpProvider interface

    master
    You can augment the help text generated by Kong's help:"" tagged annotations by implementing the HelpProvider interface. To do this, add a Help() string method to your command structs, argument structs, or flag types. Kong will call this method to retrieve additional help information for that specific component.
  7. Configure CLI definitions using struct tags

    master

    Kong uses Go struct tags to define CLI commands, flags, and arguments. You can use the kong: tag to specify various properties like name, help, default, required, and more. If a field is marked with kong:"-", it will be ignored by Kong.

    Properties can be defined directly on the field or via a Signature interface on the type to provide defaults that can be overridden by the field itself.

  8. Embed nested data structures

    master

    Use the embed:"" tag to include nested data structures. You can combine this with prefix:"" to create prefixed flags. For example, prefix:"logging." with a field Level will result in the flag --logging.level.

    var CLI struct {
      Logging struct {
        Level string `enum:"debug,info,warn,error" default:"info"` 
        Type string `enum:"json,console" default:"console"` 
      } `embed:"" prefix:"logging."` 
    }
  9. Define a command-line structure with Kong

    master

    To use Kong, define a Go struct where fields represent flags, arguments, or sub-commands. Use struct tags like help:"..." for documentation, cmd:"" to define a command, and arg:"" for positional arguments.

    package main
    
    import "github.com/alecthomas/kong"
    
    var CLI struct {
      Rm struct {
        Force     bool `help:"Force removal."`
        Recursive bool `help:"Recursively remove files."`
    
        Paths []string `arg:"" name:"path" help:"Paths to remove." type:"path"`
      } `cmd:"" help:"Remove files."`
    
      Ls struct {
        Paths []string `arg:"" optional:"" name:"path" help:"Paths to list." type:"path"`
      } `cmd:"" help:"List paths."`
    }
    
    func main() {
      ctx := kong.Parse(&CLI)
      switch ctx.Command() {
      case "rm <path>":
      case "ls":
      default:
        panic(ctx.Command())
      }
    }
  10. Define branching positional arguments

    master

    You can configure structs as branching positional arguments by tagging an unmapped nested struct field with arg, and then including a positional argument field inside that struct with the same name as the enclosing field.

    var CLI struct {
      Rename struct {
        Name struct {
          Name string `arg` // <-- NOTE: identical name to enclosing struct field.
          To struct {
            Name struct {
              Name string `arg` 
            } `cmd` 
          } `cmd` 
        } `arg` 
      } `cmd` 
    }