cli

package module
v0.0.0-...-6345f32 Latest Latest
Warning

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

Go to latest
Published: Feb 9, 2021 License: MIT Imports: 14 Imported by: 4

README

cli

PkgGoDev

Package cli is a tiny and minimalistic CLI library for Go.

Why make another one?

This package aims to reach out these goals:

  1. To be simple as possible.
  2. To be flexible until you not violate (1).

There are few libraries to build CLI for sure, but sometimes you don't want to spend much time on learning their philosophy. To be honest it's almost always much easier to write your own map[string]func(). This library allows you to save the time spent on writing that.

Concepts

There is a cli.Command interface which has single Run() method. You can group commands by using cli.Commands map type. Additional behaviour can be added by implementing few optional interfaces such as cli.FlagDefiner.

Limitations

There is no "persistent" or "global" flags. That is, flags are parsed exactly for command they appear after.

Implementing this is not a big deal, but it complicates library API enough. However, it's possible to "mixin" global flags into each command's flag set manually (optionally resolving cases when global flag was set twice on the path or was rewritten by env value if custom flags parsing used).

Usage

package main

import (
	"context"
	"flag"
	"time"

	"github.com/gobwas/cli"
)

func main() {
	cli.Main(cli.Commands{
		"sleep": new(sleepCommand),
	})
}

type sleepCommand struct {
	duration time.Duration
}

func (s *sleepCommand) DefineFlags(fs *flag.FlagSet) {
	fs.DurationVar(&s.duration,
		"d", s.duration,
		"how long to sleep",
	)
}

func (s *sleepCommand) Run(ctx context.Context, _ []string) error {
	select {
	case <-ctx.Done(): // SIGINT, SIGTERM or SIGQUIT received.
		return ctx.Err()
	case <-time.After(s.duration):
		return nil
	}
}

Note that context.Context instance passed to the Run() method will be cancelled by default if process receives SIGTERM, SIGINT or SIGQUIT signals. See cli.Runner and cli.DefaultRunner docs for more info.

Without help message customization, help request will output this:

$ go run ./example sleep -h
Usage:

  example sleep

Options:

  -d duration
        how long to sleep (default 1s)

However, you can implement optional cli.NameProvider and, say, cli.SynopsisProvider to make help message more specific:

func (s *sleepCommand) Name() string {
	return "Suspends execution for a given amount of time."
}

func (s *sleepCommand) Synopsis() string {
	return "[-d duration]"
}

Now the output will look like this:

$ go run ./examples/simple help sleep
Suspends execution for a given amount of time.

Usage:

  example sleep [-d duration]

Options:

  -d duration
        how long to sleep (default 1s)

Help for whole binary will look like this:

$ go run ./example help
Usage:

  example [help] <command>

Commands:
  sleep  Suspends execution for a given amount of time.

To customize the cli.Commands help output you can use cli.Container wrapper.

See the example folder for more info.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultRunner = Runner{
	TermSignals: []os.Signal{
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT,
	},
}

DefaultRunner is an instance of Runner used by Main().

Functions

func Exitf

func Exitf(code int, f string, args ...interface{}) error

Exitf creates an error which reception cause Runner.Main() to exit with given code preceded by formatted message.

func Main

func Main(cmd Command)

Main runs given command using DefaultRunner.

func WithCommandInfo

func WithCommandInfo(ctx context.Context, info CommandInfo) context.Context

WithCommandInfo returns a new context with given command info added to the execution path.

WithCommandInfo is called internally during command chain execution. It might be called from third parties only for testing purposes.

Types

type Command

type Command interface {
	Run(ctx context.Context, args []string) error
}

Command is the interface that holds command execution logic.

type CommandFunc

type CommandFunc func(ctx context.Context, args []string) error

CommandFunc is an adapter to allow the use of ordinary functions as Commands.

func (CommandFunc) Run

func (f CommandFunc) Run(ctx context.Context, args []string) error

Run implements Command interface.

type CommandInfo

type CommandInfo struct {
	Name    string
	Command Command
	FlagSet *flag.FlagSet
}

func ContextCommandsInfo

func ContextCommandsInfo(ctx context.Context) []CommandInfo

ContextCommandsInfo returns commands execution path associated with context. Last element of the slice is the Command which Run() method is currently running.

Callers must not mutate returned slice.

type Commands

type Commands map[string]Command

Commands holds a mapping of sub command name to its implementation.

func (Commands) Description

func (c Commands) Description() string

Description implements DescriptionProvider interface.

func (Commands) Run

func (c Commands) Run(ctx context.Context, args []string) error

Run implements Command interface.

func (Commands) Synopsis

func (c Commands) Synopsis() string

Synopsis implements SynopsisProvider interface.

type Container

type Container struct {
	Command Command

	// DoRun allows to override Command behaviour.
	DoRun func(context.Context, []string) error
	// DoName allows to override NameProvider behaviour.
	DoName func() string
	// DoSynopsis allows to override SynopsisProvider behaviour.
	DoSynopsis func() string
	// DoDescription allows to override DescriptionProvider behaviour.
	DoDescription func() string
	// DoDefineFlags allows to override FlagDefiner behaviour.
	DoDefineFlags func(*flag.FlagSet)
}

Container is a Command wrapper which allows to modify behaviour of the Command it wraps.

func (*Container) DefineFlags

func (c *Container) DefineFlags(fs *flag.FlagSet)

DefineFlags implements FlagDefiner interface.

func (*Container) Description

func (c *Container) Description() string

Description implements DescriptionProvider interface.

func (*Container) Name

func (c *Container) Name() string

Name implements NameProvider interface.

func (*Container) Run

func (c *Container) Run(ctx context.Context, args []string) error

Run implements Command interface. / NOTE: we are explicit here (and are not embedding Command) to not allow the use of non-pointer Container type as a Command. Otherwise Container would not implement helper interfaces but still be a valid Command.

func (*Container) Synopsis

func (c *Container) Synopsis() string

Synopsis implements SynopsisProvider interface.

type DescriptionProvider

type DescriptionProvider interface {
	Description() string
}

type FlagDefiner

type FlagDefiner interface {
	DefineFlags(*flag.FlagSet)
}

type NameProvider

type NameProvider interface {
	Name() string
}

type Runner

type Runner struct {
	// TermSignals specifies termination OS signals which must be used to
	// cancel context passed to Command's Run() method.
	TermSignals []os.Signal

	// ForceTerm specifies whether reception of same signal specified in
	// TermSignals this amount of times should result into os.Exit() call.
	ForceTerm int

	// DoParseFlags allows to override standard way of flags parsing.
	// It should return remaining arguments (same as flag.Args() does) or
	// error.
	DoParseFlags func(context.Context, *flag.FlagSet, []string) ([]string, error)

	// DoPrintFlags allows to override standard way of flags printing.
	// It should write all output into given io.Writer.
	DoPrintFlags func(context.Context, io.Writer, *flag.FlagSet) error
}

Runner holds options for running commands.

func (*Runner) Main

func (r *Runner) Main(cmd Command)

Main runs given command. It does some i/o, such that printing help messages or errors returned from cmd.Error().

type SynopsisProvider

type SynopsisProvider interface {
	Synopsis() string
}

Directories

Path Synopsis
examples
complex Module

Jump to

Keyboard shortcuts

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