cli

package
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

README

CLI

cli is a simple package for building Cobra commands with common patterns.

Example

Simple Command (No Flags)
package main

import (
    "fmt"

    "github.com/spf13/cobra"
    "github.com/zoumo/golib/cli"
)

var _ cli.Command = &GreetCommand{}

// GreetCommand is the simplest command - no flags, just positional args.
type GreetCommand struct{}

func (c *GreetCommand) Name() string {
    return "greet"
}

func (c *GreetCommand) Run(_ *cobra.Command, args []string) error {
    if len(args) == 0 {
        fmt.Println("Hello, World!")
        return nil
    }
    fmt.Printf("Hello, %s!\n", args[0])
    return nil
}

func main() {
    root := &cobra.Command{Use: "myapp"}
    root.AddCommand(cli.NewCobraCommand(&GreetCommand{}))
    root.Execute()
}
Command with Options (BindFlags)
package main

import (
    "fmt"

    "github.com/spf13/cobra"
    "github.com/spf13/pflag"
    "github.com/zoumo/golib/cli"
)

var (
    _ cli.Command = &EchoCommand{}
    _ cli.Options = &EchoCommand{}
)

// EchoCommand demonstrates a command with flags.
type EchoCommand struct {
    count int
}

func (c *EchoCommand) Name() string {
    return "echo"
}

func (c *EchoCommand) BindFlags(fs *pflag.FlagSet) {
    fs.IntVar(&c.count, "count", 1, "Number of times to echo")
}

func (c *EchoCommand) Run(_ *cobra.Command, args []string) error {
    if len(args) == 0 {
        return fmt.Errorf("usage: echo <text>")
    }
    for i := 0; i < c.count; i++ {
        fmt.Println(args[0])
    }
    return nil
}

func main() {
    root := &cobra.Command{Use: "myapp"}
    root.AddCommand(cli.NewCobraCommand(&EchoCommand{}))
    root.Execute()
}
Complex Command (With CommonOptions, Complete, Validate)
package main

import (
    "errors"
    "fmt"

    "github.com/spf13/cobra"
    "github.com/spf13/pflag"
    "github.com/zoumo/golib/cli"
)

var _ cli.ComplexOptions = &QueryOptions{}

// QueryOptions implements Options and ComplexOptions interfaces.
// By embedding CommonOptions, it inherits Workspace and Logger fields.
type QueryOptions struct {
    cli.CommonOptions

    Resource string
    Limit    int
}

// BindFlags implements Options interface.
func (o *QueryOptions) BindFlags(fs *pflag.FlagSet) {
    fs.StringVar(&o.Resource, "resource", "", "Resource to query (required)")
    fs.IntVar(&o.Limit, "limit", 10, "Maximum results")
}

// Complete implements ComplexOptions interface.
// MUST call embedded CommonOptions.Complete to initialize Logger.
func (o *QueryOptions) Complete(cmd *cobra.Command, args []string) error {
    return o.CommonOptions.Complete(cmd, args)
}

// Validate implements ComplexOptions interface.
// MUST call embedded CommonOptions.Validate first, then add custom validation.
func (o *QueryOptions) Validate() error {
    // Call parent first
    if err := o.CommonOptions.Validate(); err != nil {
        return err
    }
    // Custom validation
    if o.Resource == "" {
        return errors.New("--resource is required")
    }
    if o.Limit < 0 {
        return errors.New("--limit must be non-negative")
    }
    return nil
}

var (
    _ cli.Command        = &QueryCommand{}
    _ cli.ComplexOptions = &QueryCommand{}
)

// QueryCommand implements Command interface.
// Through pointer embedding of *QueryOptions, it also satisfies Options and ComplexOptions.
type QueryCommand struct {
    *QueryOptions
}

// Name implements Command interface.
func (c *QueryCommand) Name() string {
    return "query"
}

// Run implements Command interface.
func (c *QueryCommand) Run(_ *cobra.Command, args []string) error {
    // Access fields directly through pointer embedding
    c.Logger.Info("Querying", "resource", c.Resource, "limit", c.Limit)
    fmt.Printf("Querying: %s (limit: %d)\n", c.Resource, c.Limit)
    return nil
}

func main() {
    root := &cobra.Command{Use: "myapp"}
    root.AddCommand(cli.NewCobraCommand(&QueryCommand{
        QueryOptions: &QueryOptions{},
    }))
    root.Execute()
}

Key Points:

  • QueryOptions implements both Options (via BindFlags) and ComplexOptions (via Complete, Validate)
  • QueryOptions embeds CommonOptions to inherit Workspace and Logger fields
  • QueryOptions.Complete() and QueryOptions.Validate() MUST call the embedded CommonOptions methods to avoid shadowing
  • QueryCommand implements Command interface and embeds *QueryOptions pointer
  • Through pointer embedding, QueryCommand gets promoted methods and fields from QueryOptions, satisfying all type assertions

Compile-time interface assertions (the var _ declarations):

  • Go's idiomatic way to verify a type implements an interface at compile time
  • Provides immediate feedback if interface requirements change
  • No runtime overhead - declarations are optimized away
  • Example: var _ cli.Command = &MyCommand{}

API

Interfaces
type Command interface {
    Name() string
    Run(cmd *cobra.Command, args []string) error
}

type Options interface {
    BindFlags(fs *pflag.FlagSet)
}

type ComplexOptions interface {
    Options
    Complete(cmd *cobra.Command, args []string) error
    Validate() error
}
Functions
func NewCobraCommand(c Command) *cobra.Command

Creates a *cobra.Command from a Command. Automatically:

  • Binds flags if the command implements Options
  • Calls Complete() before Run() if command implements ComplexOptions
  • Calls Validate() before Run() if command implements ComplexOptions
CommonOptions
type CommonOptions struct {
    Workspace string
    Logger    log.Logger
}

func (c *CommonOptions) BindFlags(fs *pflag.FlagSet)
func (c *CommonOptions) Complete(cmd *cobra.Command, args []string) error
func (c *CommonOptions) Validate() error

Provides workspace directory and logger for your command.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewCobraCommand

func NewCobraCommand(c Command) *cobra.Command

NewCobraCommand creates a cobra.Command from a Command implementation.

This function automatically handles the full command lifecycle:

  1. Sets the command name from c.Name()
  2. Binds flags if the command implements Options interface
  3. Calls Complete() before Run() if command implements ComplexOptions
  4. Calls Validate() before Run() if command implements ComplexOptions
  5. Calls Run() to execute the command

Note: The type assertions work on the concrete type, not the Command interface. This means if you return a concrete type that embeds *QueryOptions pointer, the promoted methods will be found through method promotion.

Types

type Command

type Command interface {
	// Name returns the command's name used for CLI invocation.
	Name() string

	// Run executes the command logic with the parsed cobra.Command and arguments.
	// Called after flags are bound and validated (if implemented).
	Run(cmd *cobra.Command, args []string) error
}

Command represents a CLI command that can be executed.

A command implements at least Name() and Run() methods. Commands that also implement Options or ComplexOptions interfaces get additional functionality like flag binding and validation.

Example:

var _ cli.Command = &MyCommand{}

type MyCommand struct{}

func (c *MyCommand) Name() string { return "mycommand" }
func (c *MyCommand) Run(cmd *cobra.Command, args []string) error { ... }

type CommonOptions

type CommonOptions struct {
	// Workspace is the working directory for the command.
	// Defaults to current working directory if not set.
	Workspace string

	// Logger is a structured logger for the command.
	// Initialized in Complete() with the command name.
	Logger log.Logger
}

CommonOptions provides common functionality for CLI commands.

It implements the ComplexOptions interface and provides:

  • Workspace: The working directory for the command
  • Logger: A structured logger with the command name

Commands can embed this struct to reuse these common features.

Example:

type MyCommand struct {
    cli.CommonOptions
    MyField string
}

func (c *MyCommand) Complete(cmd *cobra.Command, args []string) error {
    // Always call parent first to initialize Logger and Workspace
    return c.CommonOptions.Complete(cmd, args)
}

func (*CommonOptions) BindFlags

func (c *CommonOptions) BindFlags(fs *pflag.FlagSet)

BindFlags implements ComplexOptions interface.

This is a no-op for CommonOptions, allowing derived types to add their own flags.

func (*CommonOptions) Complete

func (c *CommonOptions) Complete(cmd *cobra.Command, args []string) error

Complete implements ComplexOptions interface.

Initializes the Logger with the command name and sets Workspace to the current working directory if not already set.

IMPORTANT: Derived types MUST call this method first in their own Complete() implementation to ensure proper initialization.

func (*CommonOptions) Validate

func (c *CommonOptions) Validate() error

Validate implements ComplexOptions interface.

Performs base validation. Derived types should call this method first in their own Validate() implementation before adding custom validation logic.

type ComplexOptions

type ComplexOptions interface {
	Options

	// Complete initializes the command's options after flags have been parsed.
	// This is the right place to:
	//   - Initialize resources (loggers, clients, etc.)
	//   - Load configuration from files
	//   - Parse and validate arguments
	//   - Set up derived state
	Complete(cmd *cobra.Command, args []string) error

	// Validate validates the command's options after completion.
	// Return an error if the configuration is invalid.
	// Called automatically by NewCobraCommand before Run().
	Validate() error
}

ComplexOptions extends Options with lifecycle methods for initialization and validation.

This interface is for commands that require additional setup after flag parsing and validation before execution. The lifecycle is:

  1. BindFlags() - from Options (if implemented)
  2. Complete() - initialize resources, parse args, set up logger, etc.
  3. Validate() - validate the configuration

type Options

type Options interface {
	// BindFlags binds the command's flags to the pflag.FlagSet.
	// This allows each subcommand to define its own command line flags.
	BindFlags(fs *pflag.FlagSet)
}

Options provides flag binding capability for commands.

Implementing this interface allows NewCobraCommand to automatically call BindFlags during command construction.

Directories

Path Synopsis
Package example provides a root command with simple and complex subcommands.
Package example provides a root command with simple and complex subcommands.
complex
Package complex demonstrates advanced usage with CommonOptions.
Package complex demonstrates advanced usage with CommonOptions.
simple
Package simple demonstrates basic usage of the cli package.
Package simple demonstrates basic usage of the cli package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL