Documentation
¶
Overview ¶
Package lieut provides mechanisms to standardize command line app execution.
Lieut, short for lieutenant, or "second-in-command" to a commander.
An opinionated, feature-limited, no external dependency, "micro-framework" for building command line applications in Go.
Example (ErrWithHelpRequested) ¶
package main
import (
"context"
"errors"
"flag"
"fmt"
"os"
"github.com/Rican7/lieut"
)
func main() {
do := func(ctx context.Context, arguments []string) error {
if len(arguments) == 0 {
return lieut.ErrWithHelpRequested(errors.New("at least one argument is required"))
}
_, err := fmt.Println(arguments)
return err
}
app := lieut.NewSingleCommandApp(
lieut.AppInfo{Name: "example"},
do,
flag.CommandLine,
os.Stdout,
os.Stderr,
)
exitCode := app.Run(context.Background(), os.Args[1:])
os.Exit(exitCode)
}
Output:
Example (ErrWithHelpRequestedAndStatusCode) ¶
package main
import (
"context"
"errors"
"flag"
"fmt"
"os"
"github.com/Rican7/lieut"
)
func main() {
do := func(ctx context.Context, arguments []string) error {
if len(arguments) == 0 {
return lieut.ErrWithStatusCode(
lieut.ErrWithHelpRequested(errors.New("at least one argument is required")),
2,
)
}
_, err := fmt.Println(arguments)
return err
}
app := lieut.NewSingleCommandApp(
lieut.AppInfo{Name: "example"},
do,
flag.CommandLine,
os.Stdout,
os.Stderr,
)
exitCode := app.Run(context.Background(), os.Args[1:])
os.Exit(exitCode)
}
Output:
Example (ErrWithStatusCode) ¶
package main
import (
"context"
"errors"
"flag"
"fmt"
"os"
"github.com/Rican7/lieut"
)
func main() {
do := func(ctx context.Context, arguments []string) error {
if len(arguments) == 0 {
return lieut.ErrWithStatusCode(errors.New("at least one argument is required"), 2)
}
_, err := fmt.Println(arguments)
return err
}
app := lieut.NewSingleCommandApp(
lieut.AppInfo{Name: "example"},
do,
flag.CommandLine,
os.Stdout,
os.Stderr,
)
exitCode := app.Run(context.Background(), os.Args[1:])
os.Exit(exitCode)
}
Output:
Example (Minimal) ¶
package main
import (
"context"
"flag"
"fmt"
"os"
"github.com/Rican7/lieut"
)
func main() {
do := func(ctx context.Context, arguments []string) error {
_, err := fmt.Println(arguments)
return err
}
app := lieut.NewSingleCommandApp(
lieut.AppInfo{Name: "example"},
do,
flag.CommandLine,
os.Stdout,
os.Stderr,
)
exitCode := app.Run(context.Background(), os.Args[1:])
os.Exit(exitCode)
}
Output:
Example (MultiCommand) ¶
package main
import (
"context"
"flag"
"fmt"
"os"
"time"
"github.com/Rican7/lieut"
)
var multiAppInfo = lieut.AppInfo{
Name: "now",
Summary: "An example CLI app to report the date and time",
Usage: "<command>... [options]...",
Version: "v1.0.4",
}
var (
timeZone = "UTC"
includeSeconds = false
includeYear = false
)
var location *time.Location
func main() {
globalFlags := flag.NewFlagSet(multiAppInfo.Name, flag.ExitOnError)
globalFlags.StringVar(&timeZone, "timezone", timeZone, "the timezone to report in")
app := lieut.NewMultiCommandApp(
multiAppInfo,
globalFlags,
os.Stdout,
os.Stderr,
)
timeFlags := flag.NewFlagSet("time", flag.ExitOnError)
timeFlags.BoolVar(&includeSeconds, "seconds", includeSeconds, "to include seconds")
dateFlags := flag.NewFlagSet("date", flag.ExitOnError)
dateFlags.BoolVar(&includeYear, "year", includeYear, "to include year")
app.SetCommand(lieut.CommandInfo{Name: "time", Summary: "Show the time", Usage: "[options]"}, printTime, timeFlags)
app.SetCommand(lieut.CommandInfo{Name: "date", Summary: "Show the date", Usage: "[options]"}, printDate, dateFlags)
app.OnInit(validateGlobals)
exitCode := app.Run(context.Background(), os.Args[1:])
os.Exit(exitCode)
}
func validateGlobals() error {
var err error
location, err = time.LoadLocation(timeZone)
return err
}
func printTime(ctx context.Context, arguments []string) error {
format := "15:04"
if includeSeconds {
format += ":05"
}
_, err := fmt.Println(time.Now().Format(format))
return err
}
func printDate(ctx context.Context, arguments []string) error {
format := "01-02"
if includeYear {
format += "-2006"
}
_, err := fmt.Println(time.Now().Format(format))
return err
}
Output:
Example (SingleCommand) ¶
package main
import (
"context"
"flag"
"fmt"
"os"
"strings"
"github.com/Rican7/lieut"
)
var singleAppInfo = lieut.AppInfo{
Name: "sayhello",
Summary: "An example CLI app to say hello to the given names",
Usage: "[option]... [names]...",
Version: "v0.1-alpha",
}
func main() {
flagSet := flag.NewFlagSet(singleAppInfo.Name, flag.ExitOnError)
app := lieut.NewSingleCommandApp(
singleAppInfo,
sayHello,
flagSet,
os.Stdout,
os.Stderr,
)
exitCode := app.Run(context.Background(), os.Args[1:])
os.Exit(exitCode)
}
func sayHello(ctx context.Context, arguments []string) error {
names := strings.Join(arguments, ", ")
hello := fmt.Sprintf("Hello %s!", names)
_, err := fmt.Println(hello)
return err
}
Output:
Index ¶
- Constants
- func ErrWithHelpRequested(err error) error
- type AppInfo
- type CommandInfo
- type Executor
- type Flags
- type MultiCommandApp
- func (a *MultiCommandApp) CommandNames() []string
- func (a *MultiCommandApp) OnInit(init func() error)
- func (a *MultiCommandApp) PrintHelp(commandName string)
- func (a *MultiCommandApp) PrintUsage(commandName string)
- func (a *MultiCommandApp) PrintUsageError(commandName string, err error)
- func (a *MultiCommandApp) PrintVersion()
- func (a *MultiCommandApp) Run(ctx context.Context, arguments []string) int
- func (a *MultiCommandApp) SetCommand(info CommandInfo, exec Executor, flags Flags) error
- type SingleCommandApp
- func (a *SingleCommandApp) OnInit(init func() error)
- func (a *SingleCommandApp) PrintHelp()
- func (a *SingleCommandApp) PrintUsage()
- func (a *SingleCommandApp) PrintUsageError(err error)
- func (a *SingleCommandApp) PrintVersion()
- func (a *SingleCommandApp) Run(ctx context.Context, arguments []string) int
- type StatusCodeError
Examples ¶
Constants ¶
const ( // DefaultCommandUsage defines the default usage string for commands. DefaultCommandUsage = "[arguments ...]" // DefaultParentCommandUsage defines the default usage string for commands // that have sub-commands. DefaultParentCommandUsage = "<command> [arguments ...]" )
const ( // ExitCodeSuccess is the exit code returned when an app runs successfully. ExitCodeSuccess = 0 // ExitCodeError is the exit code returned when an app encounters an error. ExitCodeError = 1 // ExitCodeUsageError is the exit code returned when an app encounters a // usage error, such as invalid flags or missing required arguments. ExitCodeUsageError = 2 )
Exit codes.
const ErrHelpRequested constError = "help requested"
ErrHelpRequested is a sentinel error that, when returned from an Executor or init function, signals that help should be displayed to the user.
To wrap your own error alongside ErrHelpRequested, use ErrWithHelpRequested.
Variables ¶
This section is empty.
Functions ¶
func ErrWithHelpRequested ¶ added in v0.4.0
ErrWithHelpRequested wraps an error alongside ErrHelpRequested, returning an error that satisfies errors.Is for both ErrHelpRequested and the wrapped error. When returned from an Executor or init function, the help message will be displayed to the user.
Wrapping an error with an empty Error() string will suppress the error output but still display help.
Types ¶
type CommandInfo ¶
CommandInfo describes information about a command.
type Executor ¶
Executor is a functional interface that defines an executable command.
It takes a context and arguments, and returns an error (if any occurred).
type Flags ¶
type Flags interface {
Parse(arguments []string) error
Args() []string
PrintDefaults()
Output() io.Writer
SetOutput(output io.Writer)
}
Flags defines an interface for command flags.
type MultiCommandApp ¶
type MultiCommandApp struct {
// contains filtered or unexported fields
}
MultiCommandApp is a runnable application that has many commands.
func NewMultiCommandApp ¶
func NewMultiCommandApp(info AppInfo, flags Flags, out io.Writer, errOut io.Writer) *MultiCommandApp
NewMultiCommandApp returns an initialized MultiCommandApp.
The provided flags are global/shared among the app's commands.
The provided flags should have ContinueOnError ErrorHandling, or else flag parsing errors won't properly be displayed/handled.
func (*MultiCommandApp) CommandNames ¶
func (a *MultiCommandApp) CommandNames() []string
CommandNames returns the names of the set commands.
func (*MultiCommandApp) OnInit ¶
func (a *MultiCommandApp) OnInit(init func() error)
OnInit takes an init function that is then called after initialization and before execution of a command.
func (*MultiCommandApp) PrintHelp ¶
func (a *MultiCommandApp) PrintHelp(commandName string)
PrintHelp prints the help info to the app's error output.
It's exposed so it can be called or assigned to a flag set's usage function.
func (*MultiCommandApp) PrintUsage ¶
func (a *MultiCommandApp) PrintUsage(commandName string)
PrintUsage prints the usage to the app's error output.
func (*MultiCommandApp) PrintUsageError ¶
func (a *MultiCommandApp) PrintUsageError(commandName string, err error)
PrintUsageError prints a standardized usage error to the app's error output.
func (*MultiCommandApp) PrintVersion ¶
func (a *MultiCommandApp) PrintVersion()
PrintVersion prints the version to the app's standard output.
func (*MultiCommandApp) Run ¶
func (a *MultiCommandApp) Run(ctx context.Context, arguments []string) int
Run takes a context and arguments, runs the expected command, and returns an exit code.
If the init function or command Executor returns ErrHelpRequested, the help message will be displayed and the returned exit code will be ExitCodeUsageError.
If the init function or command Executor returns a StatusCodeError, then the returned exit code will match that of the value returned by StatusCodeError.StatusCode().
func (*MultiCommandApp) SetCommand ¶
func (a *MultiCommandApp) SetCommand(info CommandInfo, exec Executor, flags Flags) error
SetCommand sets a command for the given info, executor, and flags.
It returns an error if the provided flags have already been used for another command (or for the globals).
The provided flags should have ContinueOnError ErrorHandling, or else flag parsing errors won't properly be displayed/handled.
type SingleCommandApp ¶
type SingleCommandApp struct {
// contains filtered or unexported fields
}
SingleCommandApp is a runnable application that only has one command.
func NewSingleCommandApp ¶
func NewSingleCommandApp(info AppInfo, exec Executor, flags Flags, out io.Writer, errOut io.Writer) *SingleCommandApp
NewSingleCommandApp returns an initialized SingleCommandApp.
The provided flags should have ContinueOnError ErrorHandling, or else flag parsing errors won't properly be displayed/handled.
func (*SingleCommandApp) OnInit ¶
func (a *SingleCommandApp) OnInit(init func() error)
OnInit takes an init function that is then called after initialization and before execution of a command.
func (*SingleCommandApp) PrintHelp ¶
func (a *SingleCommandApp) PrintHelp()
PrintHelp prints the help info to the app's error output.
It's exposed so it can be called or assigned to a flag set's usage function.
func (*SingleCommandApp) PrintUsage ¶
func (a *SingleCommandApp) PrintUsage()
PrintUsage prints the usage to the app's error output.
func (*SingleCommandApp) PrintUsageError ¶
func (a *SingleCommandApp) PrintUsageError(err error)
PrintUsageError prints a standardized usage error to the app's error output.
func (*SingleCommandApp) PrintVersion ¶
func (a *SingleCommandApp) PrintVersion()
PrintVersion prints the version to the app's standard output.
func (*SingleCommandApp) Run ¶
func (a *SingleCommandApp) Run(ctx context.Context, arguments []string) int
Run takes a context and arguments, runs the expected command, and returns an exit code.
If the init function or command Executor returns ErrHelpRequested, the help message will be displayed and the returned exit code will be ExitCodeUsageError.
If the init function or command Executor returns a StatusCodeError, then the returned exit code will match that of the value returned by StatusCodeError.StatusCode().
type StatusCodeError ¶
type StatusCodeError interface {
error
// StatusCode returns the status code of the error, which can be used by an
// app's execution error to know which status code to return.
StatusCode() int
}
StatusCodeError represents an error that reports an associated status code.
func ErrWithStatusCode ¶
func ErrWithStatusCode(err error, statusCode int) StatusCodeError
ErrWithStatusCode takes an error and a status code and returns a type that satisfies StatusCodeError.