clapper

package module
v1.0.10 Latest Latest
Warning

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

Go to latest
Published: Apr 9, 2020 License: MIT Imports: 2 Imported by: 4

README

clapper

A simple but powerful Go package to parse command-line arguments getopt(3) style. Designed especially for making CLI based libraries with ease. It has built-in support for sub-commands, long and short flag name combination (for example --version <==> -v), --flag=<value> syntax, inverted flag (for example --no-clean), variadic arguments, etc.

Commando CLI application builder library uses this package to parse command-line arguments.

go-version   Build

logo

Documentation

pkg.go.dev

Installation

$ go get "github.com/thatisuday/clapper"

Usage

// cmd.go
package main

import (
	"fmt"
	"os"

	"github.com/thatisuday/clapper"
)

func main() {

	// create a new registry
	registry := clapper.NewRegistry()

	// register the root command
	if _, ok := os.LookupEnv("NO_ROOT"); !ok {
		rootCommand, _ := registry.Register("")             // root command
		rootCommand.AddArg("output", "")                    //
		rootCommand.AddFlag("force", "f", true, "")         // --force, -f | default value: "false"
		rootCommand.AddFlag("verbose", "v", true, "")       // --verbose, -v | default value: "false"
		rootCommand.AddFlag("version", "V", false, "")      // --version, -V <value>
		rootCommand.AddFlag("dir", "", false, "/var/users") // --dir <value> | default value: "/var/users"
	}

	// register the `info` sub-command
	infoCommand, _ := registry.Register("info")         // sub-command
	infoCommand.AddArg("category", "manager")           // default value: manager
	infoCommand.AddArg("username", "")                  //
	infoCommand.AddArg("subjects...", "")               // variadic argument
	infoCommand.AddFlag("verbose", "v", true, "")       // --verbose, -v | default value: "false"
	infoCommand.AddFlag("version", "V", false, "1.0.1") // --version, -V <value> | default value: "1.0.1"
	infoCommand.AddFlag("output", "o", false, "./")     // --output, -o <value> | default value: "./"
	infoCommand.AddFlag("no-clean", "", true, "")       // --no-clean | default value: "true"

	// register the `ghost` sub-command
	registry.Register("ghost")

	/*----------------*/

	// parse command-line arguments
	command, err := registry.Parse(os.Args[1:])

	/*----------------*/

	// check for error
	if err != nil {
		fmt.Printf("error => %#v\n", err)
		return
	}

	// get executed sub-command name
	fmt.Printf("sub-command => %#v\n", command.Name)

	// get argument values
	for argName, argValue := range command.Args {
		fmt.Printf("argument(%s) => %#v\n", argName, argValue)
	}

	// get flag values
	for flagName, flagValue := range command.Flags {
		fmt.Printf("flag(%s) => %#v\n", flagName, flagValue)
	}
}

In the above example, we have registred a root command and an info command. The registry can parse arguments passed to the command that executed this program.

Example 1

When the root command is executed with no command-line arguments.

$ go run cmd.go

sub-command => ""
argument(output) => &clapper.Arg{Name:"output", IsVariadic:false, DefaultValue:"", Value:""}
flag(dir) => &clapper.Flag{Name:"dir", ShortName:"", IsBoolean:false, IsInverted:false, DefaultValue:"/var/users", Value:""}
flag(force) => &clapper.Flag{Name:"force", ShortName:"f", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:""}
flag(verbose) => &clapper.Flag{Name:"verbose", ShortName:"v", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:""}
flag(version) => &clapper.Flag{Name:"version", ShortName:"V", IsBoolean:false, IsInverted:false, DefaultValue:"", Value:""}
Example 2

When the root command is executed but not registered.

$ NO_ROOT=TRUE go run cmd.go

error => clapper.ErrorUnknownCommand{Name:""}
Example 3

When the root command is executed with short/long flag names as well as by changing the positions of the arguments.

$ go run cmd.go userinfo -V 1.0.1 -v --force --dir ./sub/dir
$ go run cmd.go -V 1.0.1 --verbose --force userinfo --dir ./sub/dir
$ go run cmd.go -V 1.0.1 -v --force --dir ./sub/dir userinfo
$ go run cmd.go --version 1.0.1 --verbose --force --dir ./sub/dir userinfo

sub-command => ""
argument(output) => &clapper.Arg{Name:"output", IsVariadic:false, DefaultValue:"", Value:"userinfo"}
flag(verbose) => &clapper.Flag{Name:"verbose", ShortName:"v", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:"true"}
flag(version) => &clapper.Flag{Name:"version", ShortName:"V", IsBoolean:false, IsInverted:false, DefaultValue:"", Value:"1.0.1"}
flag(dir) => &clapper.Flag{Name:"dir", ShortName:"", IsBoolean:false, IsInverted:false, DefaultValue:"/var/users", Value:"./sub/dir"}
flag(force) => &clapper.Flag{Name:"force", ShortName:"f", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:"true"}
Example 4

When an unregistered flag is provided in the command-line arguments.

$ go run cmd.go userinfo -V 1.0.1 -v --force -d ./sub/dir
error => clapper.ErrorUnknownFlag{Name:"-d"}

$ go run cmd.go userinfo -V 1.0.1 -v --force --d ./sub/dir
error => clapper.ErrorUnknownFlag{Name:"--d"}

$ go run cmd.go userinfo -V 1.0.1 -v --force --directory ./sub/dir
error => clapper.ErrorUnknownFlag{Name:"--directory"}

$ go run cmd.go info student --dump
error => clapper.ErrorUnknownFlag{Name:"--dump"}

$ go run cmd.go info student --clean
error => clapper.ErrorUnknownFlag{Name:"--clean"}
Example 5

When information was intended to be a sub-command but not registered and the root command accepts arguments.

$ go run cmd.go information --force

sub-command => ""
argument(output) => &clapper.Arg{Name:"output", IsVariadic:false, DefaultValue:"", Value:"information"}
flag(version) => &clapper.Flag{Name:"version", ShortName:"V", IsBoolean:false, IsInverted:false, DefaultValue:"", Value:""}
flag(dir) => &clapper.Flag{Name:"dir", ShortName:"", IsBoolean:false, IsInverted:false, DefaultValue:"/var/users", Value:""}
flag(force) => &clapper.Flag{Name:"force", ShortName:"f", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:"true"}
flag(verbose) => &clapper.Flag{Name:"verbose", ShortName:"v", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:""}
Example 6

When a sub-command is executed.

$ go run cmd.go info student -V -v --output ./opt/dir

sub-command => "info"
argument(category) => &clapper.Arg{Name:"category", IsVariadic:false, DefaultValue:"manager", Value:"student"}
argument(username) => &clapper.Arg{Name:"username", IsVariadic:false, DefaultValue:"", Value:""}
argument(subjects) => &clapper.Arg{Name:"subjects", IsVariadic:true, DefaultValue:"", Value:""}
flag(verbose) => &clapper.Flag{Name:"verbose", ShortName:"v", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:"true"}
flag(version) => &clapper.Flag{Name:"version", ShortName:"V", IsBoolean:false, IsInverted:false, DefaultValue:"1.0.1", Value:""}
flag(output) => &clapper.Flag{Name:"output", ShortName:"o", IsBoolean:false, IsInverted:false, DefaultValue:"./", Value:"./opt/dir"}
flag(clean) => &clapper.Flag{Name:"clean", ShortName:"", IsBoolean:true, IsInverted:true, DefaultValue:"true", Value:""}
Example 7

When a command is executed with an inverted flag (flag that starts with --no- prefix).

$ go run cmd.go info student -V -v --output ./opt/dir --no-clean

sub-command => "info"
argument(username) => &clapper.Arg{Name:"username", IsVariadic:false, DefaultValue:"", Value:""}
argument(subjects) => &clapper.Arg{Name:"subjects", IsVariadic:true, DefaultValue:"", Value:""}
argument(category) => &clapper.Arg{Name:"category", IsVariadic:false, DefaultValue:"manager", Value:"student"}
flag(verbose) => &clapper.Flag{Name:"verbose", ShortName:"v", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:"true"}
flag(version) => &clapper.Flag{Name:"version", ShortName:"V", IsBoolean:false, IsInverted:false, DefaultValue:"1.0.1", Value:""}
flag(output) => &clapper.Flag{Name:"output", ShortName:"o", IsBoolean:false, IsInverted:false, DefaultValue:"./", Value:"./opt
Example 8

When the position of argument values are changed and variadic arguments are provided.

$ go run cmd.go info -v student -V 2.0.0 thatisuday math science physics
$ go run cmd.go info student -v --version=2.0.0 thatisuday math science physics
$ go run cmd.go info student thatisuday math science -v physics -V=2.0.0

sub-command => "info"
argument(category) => &clapper.Arg{Name:"category", IsVariadic:false, DefaultValue:"manager", Value:"student"}
argument(username) => &clapper.Arg{Name:"username", IsVariadic:false, DefaultValue:"", Value:"thatisuday"}
argument(subjects) => &clapper.Arg{Name:"subjects", IsVariadic:true, DefaultValue:"", Value:"math,science,physics"}
flag(output) => &clapper.Flag{Name:"output", ShortName:"o", IsBoolean:false, IsInverted:false, DefaultValue:"./", Value:""}
flag(clean) => &clapper.Flag{Name:"clean", ShortName:"", IsBoolean:true, IsInverted:true, DefaultValue:"true", Value:""}
flag(verbose) => &clapper.Flag{Name:"verbose", ShortName:"v", IsBoolean:true, IsInverted:false, DefaultValue:"false", Value:"true"}
flag(version) => &clapper.Flag{Name:"version", ShortName:"V", IsBoolean:false, IsInverted:false, DefaultValue:"1.0.1", Value:"2.0.0"}
Example 9

When a sub-command is registered without any flags.

$ go run cmd.go ghost -v thatisuday -V 2.0.0 teachers

error => clapper.ErrorUnknownFlag{Name:"-v"}
Example 10

When a sub-command is registered without any arguments.

$ go run cmd.go ghost
$ go run cmd.go ghost thatisuday extra

sub-command => "ghost
Example 11

When the root command is not registered or the root command is registered with no arguments.

$ NO_ROOT=TRUE go run cmd.go information
error => clapper.ErrorUnknownCommand{Name:"information"}

$ go run cmd.go ghost
sub-command => "ghost"
Example 12

When unsupported flag format is provided.

$ go run cmd.go ---version 
error => clapper.ErrorUnsupportedFlag{Name:"---version"}

$ go run cmd.go ---v=1.0.0 
error => clapper.ErrorUnsupportedFlag{Name:"---v"}

$ go run cmd.go -version 
error => clapper.ErrorUnsupportedFlag{Name:"-version"}

Contribution

A lot of improvements can be made to this library, one of which is the support for combined short flags, like -abc. If you are willing to contribute, create a pull request and mention your bug fixes or enhancements in the comment.

Documentation

Overview

Package clapper processes the command-line arguments of getopt(3) syntax. This package provides the ability to process the root command, sub commands, command-line arguments and command-line flags.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Arg

type Arg struct {
	// name of the argument
	Name string

	// variadic argument can take multiple values
	IsVariadic bool

	// default value of the argument
	DefaultValue string

	// value of the argument (provided by the user)
	Value string
}

Arg type holds the structured information about an argument.

type CommandConfig added in v1.0.8

type CommandConfig struct {

	// name of the sub-command ("" for the root command)
	Name string

	// command-line flags
	Flags map[string]*Flag

	// registered command argument values
	Args map[string]*Arg

	// list of the argument names (for ordered iteration)
	ArgNames []string
	// contains filtered or unexported fields
}

CommandConfig type holds the structure and values of the command-line arguments of command.

func (*CommandConfig) AddArg added in v1.0.8

func (commandConfig *CommandConfig) AddArg(name string, defaultValue string) (*Arg, bool)

AddArg registers an argument configuration with the command. The `name` argument represents the name of the argument. If value of the `name` argument ends with `...` suffix, then it is a variadic argument. Variadic argument can accept multiple argument values and it should be the last registered argument. Values of a variadic argument will be concatenated using comma (,). The `defaultValue` argument represents the default value of the argument. All arguments without a default value must be registered first. If an argument with given `name` is already registered, then argument registration is skipped and registered `*Arg` object returned. If the argument is already registered, second return value will be `true`.

func (*CommandConfig) AddFlag added in v1.0.8

func (commandConfig *CommandConfig) AddFlag(name string, shortName string, isBool bool, defaultValue string) (*Flag, bool)

AddFlag method registers a command-line flag with the command. The `name` argument is the long-name of the flag and it should not start with `--` prefix. The `shortName` argument is the short-name of the flag and it should not start with `-` prefix. The `isBool` argument indicates whether the flag holds a boolean value. A boolean flag doesn't accept an input value such as `--flag=<value>` and its default value is "true". The `defaultValue` argument represents the default value of the flag. In case of a boolean flag, the `defaultValue` is redundant. If the `name` value starts with `no-` prefix, then it is considered as an inverted flag. An inverted flag is registered with the name `<flag>` produced by removing `no-` prefix from `no-<flag>` and its defaut value is "true". When command-line arguments contain `--no-<flag>`, the value of the `<flag>` becomes "false". If a flag with given `name` is already registered, then flag registration is skipped and registered `*Flag` object returned. If the flag is already registered, second return value will be `true`.

type ErrorUnknownCommand

type ErrorUnknownCommand struct {
	Name string
}

ErrorUnknownCommand represents an error when command-line arguments contain an unregistered command.

func (ErrorUnknownCommand) Error

func (e ErrorUnknownCommand) Error() string

type ErrorUnknownFlag

type ErrorUnknownFlag struct {
	Name string
}

ErrorUnknownFlag represents an error when command-line arguments contain an unregistered flag.

func (ErrorUnknownFlag) Error

func (e ErrorUnknownFlag) Error() string

type ErrorUnsupportedFlag added in v1.0.3

type ErrorUnsupportedFlag struct {
	Name string
}

ErrorUnsupportedFlag represents an error when command-line arguments contain an unsupported flag.

func (ErrorUnsupportedFlag) Error added in v1.0.3

func (e ErrorUnsupportedFlag) Error() string

type Flag

type Flag struct {

	// long name of the flag
	Name string

	// short name of the flag
	ShortName string

	// if the flag holds boolean value
	IsBoolean bool

	// if the flag is an inverted flag (with `--no-` prefix)
	IsInverted bool

	// default value of the flag
	DefaultValue string

	// value of the flag (provided by the user)
	Value string
}

Flag type holds the structured information about a flag.

type Registry

type Registry map[string]*CommandConfig

Registry holds the configuration of the registered commands.

func NewRegistry

func NewRegistry() Registry

NewRegistry returns new instance of the "Registry"

func (Registry) Parse

func (registry Registry) Parse(values []string) (*CommandConfig, error)

Parse method parses command-line arguments and returns an appropriate "*CommandConfig" object registered in the registry. If command is not registered, it return `ErrorUnknownCommand` error. If there is an error parsing a flag, it can return an `ErrorUnknownFlag` or `ErrorUnsupportedFlag` error.

func (Registry) Register

func (registry Registry) Register(name string) (*CommandConfig, bool)

Register method registers a command. The "name" argument should be a simple string. If "name" is an empty string, it is considered as a root command. If a command is already registered, the registered `*CommandConfig` object is returned. If the command is already registered, second return value will be `true`.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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