fcli

package module
v0.0.0-...-9c6ac59 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2022 License: MIT Imports: 16 Imported by: 0

README

fcli

Package fcli provides utilities for function-based command-line tools.

Usage

package main

import (
	"fmt"

	"github.com/berquerant/fcli"
)

func greet(name string) {
	fmt.Println("Hello,", name)
}

// bye prints Bye!
func bye() {
	fmt.Println("Bye!")
}

func main() {
	cli := fcli.NewCLI("do")
	_ = cli.Add(greet)
	_ = cli.Add(bye)
	_ = cli.Start()
}
❯ ./do
Error: not enough arguments
Usage: do {bye,greet}

❯ ./do greet -h
Usage of greet:
  -name string

❯ ./do greet -name world
Hello, world

❯ ./do bye -h
bye prints Bye!

❯ ./do bye
Bye!

Examples

examples

Documentation

Overview

Package fcli provides utilities for function-based command-line tools.

Index

Examples

Constants

View Source
const (
	Cusage = 1 << iota // print usage
	Cerror             // return error
)

Variables

View Source
var (
	ErrCLINotEnoughArguments = errors.New("not enough arguments")
	ErrCLICommandNotFound    = errors.New("command not found")

	// NilUsage is noop.
	// Disable Usage of CLI by CLI.Usage(NilUsage).
	NilUsage = func() {}
	// DefaultOnError prints the error, usage and returns the error.
	DefaultOnError = func(err error) int {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		return Cusage | Cerror
	}
)
View Source
var (
	// ErrInvalidCustomFlag is the error returned if failed to parse the value of the custom flag.
	ErrCannotUnmarshalCustomFlag = errors.New("cannot unmarshal custom flag")
	// ErrInvalidCustomFlag is the error returned if the type of the flag is not proper.
	ErrInvalidCustomFlag = errors.New("invalid custom flag")
)
View Source
var (
	ErrNotFunction       = errors.New("not function")
	ErrCannotCutFuncDecl = errors.New("cannot cut func decl")
	ErrInvalidFuncInfo   = errors.New("invalid func info")
)
View Source
var (
	ErrBadTargetFunction = errors.New("bad target function")
	ErrCallFailure       = errors.New("call failure")
)
View Source
var (
	ErrBuildFuncInfo = errors.New("failed to build func info")
)
View Source
var (
	// ErrValueOutOfRange is the error returned if the parsed value from the command-line arguments
	// is the out of the range.
	ErrValueOutOfRange = errors.New("value out of range")
)

Functions

func SetVerboseLevel

func SetVerboseLevel(level int)

Types

type BoolFlag

type BoolFlag struct {
	// contains filtered or unexported fields
}

BoolFlag is the flag for bool.

func (*BoolFlag) AddFlag

func (s *BoolFlag) AddFlag(flagSet *flag.FlagSet)

func (BoolFlag) Name

func (s BoolFlag) Name() string

func (*BoolFlag) ReflectValue

func (s *BoolFlag) ReflectValue() (reflect.Value, error)

func (*BoolFlag) Unwrap

func (s *BoolFlag) Unwrap() (any, error)

func (*BoolFlag) Value

func (s *BoolFlag) Value() (bool, error)

type CLI

type CLI interface {
	// Start parses arguments and calls proper function.
	// if arguments is nil, reads os.Args.
	Start(arguments ...string) error
	StartWithContext(ctx context.Context, arguments ...string) error
	// Add adds a subcommand.
	// See NewTargetFunction.
	Add(f any, opt ...Option) error
	// Usage sets a function to print usage.
	Usage(func())
	// OnError sets a function called when command function returned an error.
	// If onError return Cusage then print usage.
	// If onError return Cerror then return the error.
	OnError(onError func(error) int)
}

CLI is the function-based subcommands set.

func NewCLI

func NewCLI(name string, opt ...Option) CLI

type Config

type Config struct {
	ErrorHandling *ConfigItem[flag.ErrorHandling]
	CommandName   *ConfigItem[string]
}

func (*Config) Apply

func (s *Config) Apply(opt ...Option)

type ConfigBuilder

type ConfigBuilder struct {
	// contains filtered or unexported fields
}

func NewConfigBuilder

func NewConfigBuilder() *ConfigBuilder

func (*ConfigBuilder) Build

func (s *ConfigBuilder) Build() *Config

func (*ConfigBuilder) CommandName

func (s *ConfigBuilder) CommandName(v string) *ConfigBuilder

func (*ConfigBuilder) ErrorHandling

func (s *ConfigBuilder) ErrorHandling(v flag.ErrorHandling) *ConfigBuilder

type ConfigItem

type ConfigItem[T any] struct {
	// contains filtered or unexported fields
}

func NewConfigItem

func NewConfigItem[T any](defaultValue T) *ConfigItem[T]

func (*ConfigItem[T]) Default

func (s *ConfigItem[T]) Default() T

func (*ConfigItem[T]) Get

func (s *ConfigItem[T]) Get() T

func (*ConfigItem[T]) IsModified

func (s *ConfigItem[T]) IsModified() bool

func (*ConfigItem[T]) Set

func (s *ConfigItem[T]) Set(value T)

type CustomFlag

type CustomFlag struct {
	// contains filtered or unexported fields
}

CustomFlag is the flag for types that implement CustomFlagUnmarshaller.

func (*CustomFlag) AddFlag

func (s *CustomFlag) AddFlag(flagSet *flag.FlagSet)

func (CustomFlag) Name

func (s CustomFlag) Name() string

func (*CustomFlag) ReflectValue

func (s *CustomFlag) ReflectValue() (reflect.Value, error)

func (*CustomFlag) Unwrap

func (s *CustomFlag) Unwrap() (any, error)

type CustomFlagUnmarshaller

type CustomFlagUnmarshaller interface {
	// UnmarshalFlag converts string into the value.
	// The value must be the implementing type.
	UnmarshalFlag(string) (CustomFlagUnmarshaller, error)
}

CustomFlagUnmarshaller should be implemented by the type for CustomFlag.

type CustomFlagZeroer

type CustomFlagZeroer interface {
	FlagZero() CustomFlagUnmarshaller
}

CustomFlagZeroer provides zero value.

type FileLines

type FileLines interface {
	Filename() string
	Line(lineNumber int) (string, bool)
}

FileLines is the set of the lines of the file.

func NewFileLines

func NewFileLines(file string) (FileLines, error)

type Flag

type Flag interface {
	// Name is the flag name.
	Name() string
	// AddFlag defines the flag in the flag set.
	AddFlag(flagSet *flag.FlagSet)
	// Unwrap returns the flag value.
	// Default value is the zero value.
	Unwrap() (any, error)
	// ReflectValue returns the flag value for reflection.
	// Default value is the zero value.
	ReflectValue() (reflect.Value, error)
}

Flag is a command-line flag.

func NewBoolFlag

func NewBoolFlag(name string) Flag

func NewCustomFlag

func NewCustomFlag(name string, typ reflect.Type) (Flag, error)

NewCustomFlag returns the new CustomFlag. typ is the type that implements CustomFlagUnmarshaller. struct should be passed as pointer. If typ implements CustomFlagZeroer, use it as the default value of the flag.

func NewFloat32Flag

func NewFloat32Flag(name string) Flag

func NewFloat64Flag

func NewFloat64Flag(name string) Flag

func NewInt16Flag

func NewInt16Flag(name string) Flag

func NewInt32Flag

func NewInt32Flag(name string) Flag

func NewInt64Flag

func NewInt64Flag(name string) Flag

func NewInt8Flag

func NewInt8Flag(name string) Flag

func NewIntFlag

func NewIntFlag(name string) Flag

func NewStringFlag

func NewStringFlag(name string) Flag

func NewUint16Flag

func NewUint16Flag(name string) Flag

func NewUint32Flag

func NewUint32Flag(name string) Flag

func NewUint64Flag

func NewUint64Flag(name string) Flag

func NewUint8Flag

func NewUint8Flag(name string) Flag

func NewUintFlag

func NewUintFlag(name string) Flag

type FlagFactory

type FlagFactory func(name string) Flag

func NewFlagFactory

func NewFlagFactory(v any) (FlagFactory, bool)

NewFlagFactory returns the proper flag for the v.

Example (BasicTypes)
package main

import (
	"flag"
	"fmt"

	"github.com/berquerant/fcli"
)

func main() {
	var (
		boolFlagF, _   = fcli.NewFlagFactory(false)
		stringFlagF, _ = fcli.NewFlagFactory("")

		boolFlag   = boolFlagF("b")
		stringFlag = stringFlagF("s")

		flagSet = flag.NewFlagSet("ff", flag.ContinueOnError)
	)

	boolFlag.AddFlag(flagSet)
	stringFlag.AddFlag(flagSet)

	if err := flagSet.Parse([]string{"-b", "-s", "basic"}); err != nil {
		panic(err)
	}
	b, _ := boolFlag.Unwrap()
	s, _ := stringFlag.Unwrap()
	fmt.Println(b)
	fmt.Println(s)
}
Output:

true
basic
Example (CustomFlag)
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"strings"

	"github.com/berquerant/fcli"
)

type customJSONStruct struct {
	World  string `json:"world"`
	Number int    `json:"number"`
}

func (*customJSONStruct) UnmarshalFlag(v string) (fcli.CustomFlagUnmarshaller, error) {
	var x customJSONStruct
	if err := json.Unmarshal([]byte(v), &x); err != nil {
		return nil, err
	}
	return &x, nil
}

type customStringSlice []string

func (customStringSlice) UnmarshalFlag(v string) (fcli.CustomFlagUnmarshaller, error) {
	return customStringSlice(strings.Split(v, ",")), nil
}

type customStringZero string

func (customStringZero) UnmarshalFlag(v string) (fcli.CustomFlagUnmarshaller, error) {
	return customStringZero(v), nil
}

func (customStringZero) FlagZero() fcli.CustomFlagUnmarshaller {
	return customStringZero("ZERO")
}

func main() {
	var (
		jsonFlagF, _  = fcli.NewFlagFactory(new(customJSONStruct))
		sliceFlagF, _ = fcli.NewFlagFactory(customStringSlice(nil))
		zeroFlagF, _  = fcli.NewFlagFactory(customStringZero(""))

		jsonFlag  = jsonFlagF("j")
		sliceFlag = sliceFlagF("s")
		zeroFlag  = zeroFlagF("z")

		flagSet = flag.NewFlagSet("ff", flag.ContinueOnError)
	)

	jsonFlag.AddFlag(flagSet)
	sliceFlag.AddFlag(flagSet)
	zeroFlag.AddFlag(flagSet)

	if err := flagSet.Parse([]string{"-j", `{"world":"fog","number":1}`, "-s", "sig,light,back"}); err != nil {
		panic(err)
	}
	j, _ := jsonFlag.Unwrap()
	s, _ := sliceFlag.Unwrap()
	z, _ := zeroFlag.Unwrap()
	fmt.Println(j.(*customJSONStruct).World)
	fmt.Println(j.(*customJSONStruct).Number)
	for _, x := range s.(customStringSlice) {
		fmt.Println(x)
	}
	fmt.Println(z)
}
Output:

fog
1
sig
light
back
ZERO

type Float32Flag

type Float32Flag struct {
	*Float64Flag
}

Float32Flag is the flag for float32.

func (Float32Flag) Name

func (s Float32Flag) Name() string

func (*Float32Flag) ReflectValue

func (s *Float32Flag) ReflectValue() (reflect.Value, error)

func (*Float32Flag) Unwrap

func (s *Float32Flag) Unwrap() (any, error)

func (*Float32Flag) Value

func (s *Float32Flag) Value() (float32, error)

type Float64Flag

type Float64Flag struct {
	// contains filtered or unexported fields
}

Float64Flag is the flag for float64.

func (*Float64Flag) AddFlag

func (s *Float64Flag) AddFlag(flagSet *flag.FlagSet)

func (Float64Flag) Name

func (s Float64Flag) Name() string

func (*Float64Flag) ReflectValue

func (s *Float64Flag) ReflectValue() (reflect.Value, error)

func (*Float64Flag) Unwrap

func (s *Float64Flag) Unwrap() (any, error)

func (*Float64Flag) Value

func (s *Float64Flag) Value() (float64, error)

type FuncDeclCutter

type FuncDeclCutter interface {
	// CutFuncDecl cuts out a func decl.
	// Include doc but comment marker // only.
	CutFuncDecl() (string, error)
}

func NewFuncDeclCutter

func NewFuncDeclCutter(file FileLines, funcHeadLineNumber int) FuncDeclCutter

type FuncInfo

type FuncInfo interface {
	// Name returns the name of the function.
	Name() string
	// Doc returns the comments of the function.
	Doc() string
	NumIn() int
	In(int) FuncParam
}

func BuildFuncInfo

func BuildFuncInfo(filename string, lineNumber int) (FuncInfo, error)

func NewFuncInfo

func NewFuncInfo(src string) (FuncInfo, error)

NewFuncInfo parses src and generate FuncInfo. src is func decl, like:

func targetFunc() int { return 0 }

Returns ErrInvalidFuncInfo if parse failed.

Example
package main

import (
	"fmt"

	"github.com/berquerant/fcli"
)

func main() {
	const src = `// Hello greets you.
func Hello(name string) {
  println("Hello!", name)
}`
	info, err := fcli.NewFuncInfo(src)
	if err != nil {
		panic(err)
	}
	fmt.Println(info.Name())
	fmt.Println(info.NumIn())
	fmt.Println(info.In(0).Name())
	fmt.Println(info.Doc())
}
Output:

Hello
1
name
Hello greets you.

type FuncName

type FuncName struct {
	// contains filtered or unexported fields
}

FuncName represents the function name and the location.

func GetFuncName

func GetFuncName(f any) (*FuncName, error)

GetFuncName returns the function name. Returns ErrNotFunction if f is not a function. Note: this is not for method, literal.

Example
package main

import (
	"fmt"

	"github.com/berquerant/fcli"
)

func main() {
	v, err := fcli.GetFuncName(fmt.Println)
	if err != nil {
		panic(err)
	}
	fmt.Println(v)
}
Output:

Println

func (*FuncName) File

func (s *FuncName) File() string

func (*FuncName) FullName

func (s *FuncName) FullName() string

func (*FuncName) Line

func (s *FuncName) Line() int

func (*FuncName) String

func (s *FuncName) String() string

type FuncParam

type FuncParam interface {
	// Name returns the name of the parameter.
	Name() string
}

FuncParam is an input parameter of the function.

type Int16Flag

type Int16Flag struct {
	// contains filtered or unexported fields
}

Int16Flag is the flag for int16.

func (*Int16Flag) ReflectValue

func (s *Int16Flag) ReflectValue() (reflect.Value, error)

func (*Int16Flag) Unwrap

func (s *Int16Flag) Unwrap() (any, error)

func (*Int16Flag) Value

func (s *Int16Flag) Value() (int16, error)

type Int32Flag

type Int32Flag struct {
	// contains filtered or unexported fields
}

Int32Flag is the flag for int32.

func (*Int32Flag) ReflectValue

func (s *Int32Flag) ReflectValue() (reflect.Value, error)

func (*Int32Flag) Unwrap

func (s *Int32Flag) Unwrap() (any, error)

func (*Int32Flag) Value

func (s *Int32Flag) Value() (int32, error)

type Int64Flag

type Int64Flag struct {
	// contains filtered or unexported fields
}

Int64Flag is the flag for int64.

func (*Int64Flag) AddFlag

func (s *Int64Flag) AddFlag(flagSet *flag.FlagSet)

func (Int64Flag) Name

func (s Int64Flag) Name() string

func (*Int64Flag) ReflectValue

func (s *Int64Flag) ReflectValue() (reflect.Value, error)

func (*Int64Flag) Unwrap

func (s *Int64Flag) Unwrap() (any, error)

func (*Int64Flag) Value

func (s *Int64Flag) Value() (int64, error)

type Int8Flag

type Int8Flag struct {
	// contains filtered or unexported fields
}

Int8Flag is the flag for int8.

func (*Int8Flag) ReflectValue

func (s *Int8Flag) ReflectValue() (reflect.Value, error)

func (*Int8Flag) Unwrap

func (s *Int8Flag) Unwrap() (any, error)

func (*Int8Flag) Value

func (s *Int8Flag) Value() (int8, error)

type IntFlag

type IntFlag struct {
	// contains filtered or unexported fields
}

IntFlag is a flag for int.

func (*IntFlag) AddFlag

func (s *IntFlag) AddFlag(flagSet *flag.FlagSet)

func (IntFlag) Name

func (s IntFlag) Name() string

func (*IntFlag) ReflectValue

func (s *IntFlag) ReflectValue() (reflect.Value, error)

func (*IntFlag) Unwrap

func (s *IntFlag) Unwrap() (any, error)

func (*IntFlag) Value

func (s *IntFlag) Value() (int, error)

type Option

type Option func(*Config)

func WithCommandName

func WithCommandName(v string) Option

func WithErrorHandling

func WithErrorHandling(v flag.ErrorHandling) Option

type StringFlag

type StringFlag struct {
	// contains filtered or unexported fields
}

StringFlag is the flag for string.

func (*StringFlag) AddFlag

func (s *StringFlag) AddFlag(flagSet *flag.FlagSet)

func (StringFlag) Name

func (s StringFlag) Name() string

func (*StringFlag) ReflectValue

func (s *StringFlag) ReflectValue() (reflect.Value, error)

func (*StringFlag) Unwrap

func (s *StringFlag) Unwrap() (any, error)

func (*StringFlag) Value

func (s *StringFlag) Value() (string, error)

type TargetFunction

type TargetFunction interface {
	// Name returns the name of the function.
	Name() string
	// Unwrap returns raw function.
	Unwrap() any
	// Call calls the function by flag arguments.
	// Returns ErrCallFailure if failed to call the function.
	Call(arguments []string) error
	CallWithContext(ctx context.Context, arguments []string) error
}

TargetFunction specifies a function for CLI subcommand.

Example
package main

import (
	"flag"
	"fmt"
	"strings"

	"github.com/berquerant/fcli"
)

type targetArg struct {
	category string
	location string
}

func (*targetArg) UnmarshalFlag(v string) (fcli.CustomFlagUnmarshaller, error) {
	xs := strings.Split(v, ".")
	if len(xs) != 2 {
		return nil, fmt.Errorf("invalid format")
	}
	return &targetArg{
		category: xs[0],
		location: xs[1],
	}, nil
}

func queryCLI(key string, target *targetArg) {
	fmt.Println(key)
	fmt.Println(target.category)
	fmt.Println(target.location)
}

func main() {
	f, err := fcli.NewTargetFunction(queryCLI, fcli.WithErrorHandling(flag.ContinueOnError))
	if err != nil {
		panic(err)
	}
	fmt.Println(f.Name())
	if err := f.Call([]string{"-key", "fall", "-target", "human.mars"}); err != nil {
		panic(err)
	}
}
Output:

queryCLI
fall
human
mars

func NewTargetFunction

func NewTargetFunction(f any, opt ...Option) (TargetFunction, error)

NewTargetFunction makes a function able to be invoked by string slice arguments. F can be the function which is not variadic, no output parameters or an error, not literal, not method and can have input parameters below:

int, int8, int16, int32, int64
uint, uint8, uint16, uint32, uint64
bool, string, float32, float64

and the type which implements CustomFlagUnmarshaller. First input argument can be context.Context. Default value is available if the type implements CustomFlagZeroer. Note: if pass the struct, pass as a pointer.

type Uint16Flag

type Uint16Flag struct {
	// contains filtered or unexported fields
}

Uint16Flag is the flag for uint16.

func (*Uint16Flag) ReflectValue

func (s *Uint16Flag) ReflectValue() (reflect.Value, error)

func (*Uint16Flag) Unwrap

func (s *Uint16Flag) Unwrap() (any, error)

func (*Uint16Flag) Value

func (s *Uint16Flag) Value() (uint16, error)

type Uint32Flag

type Uint32Flag struct {
	// contains filtered or unexported fields
}

Uint32Flag is the flag for uint32.

func (*Uint32Flag) ReflectValue

func (s *Uint32Flag) ReflectValue() (reflect.Value, error)

func (*Uint32Flag) Unwrap

func (s *Uint32Flag) Unwrap() (any, error)

func (*Uint32Flag) Value

func (s *Uint32Flag) Value() (uint32, error)

type Uint64Flag

type Uint64Flag struct {
	// contains filtered or unexported fields
}

Uint64Flag is the flag for uint64.

func (*Uint64Flag) AddFlag

func (s *Uint64Flag) AddFlag(flagSet *flag.FlagSet)

func (Uint64Flag) Name

func (s Uint64Flag) Name() string

func (*Uint64Flag) ReflectValue

func (s *Uint64Flag) ReflectValue() (reflect.Value, error)

func (*Uint64Flag) Unwrap

func (s *Uint64Flag) Unwrap() (any, error)

func (*Uint64Flag) Value

func (s *Uint64Flag) Value() (uint64, error)

type Uint8Flag

type Uint8Flag struct {
	// contains filtered or unexported fields
}

Uint8Flag is the flag for uint8.

func (*Uint8Flag) ReflectValue

func (s *Uint8Flag) ReflectValue() (reflect.Value, error)

func (*Uint8Flag) Unwrap

func (s *Uint8Flag) Unwrap() (any, error)

func (*Uint8Flag) Value

func (s *Uint8Flag) Value() (uint8, error)

type UintFlag

type UintFlag struct {
	// contains filtered or unexported fields
}

UintFlag is the flag for uint.

func (*UintFlag) AddFlag

func (s *UintFlag) AddFlag(flagSet *flag.FlagSet)

func (UintFlag) Name

func (s UintFlag) Name() string

func (*UintFlag) ReflectValue

func (s *UintFlag) ReflectValue() (reflect.Value, error)

func (*UintFlag) Unwrap

func (s *UintFlag) Unwrap() (any, error)

func (*UintFlag) Value

func (s *UintFlag) Value() (uint, error)

type UsageFunc

type UsageFunc = func()

Directories

Path Synopsis
examples
ctx
internal

Jump to

Keyboard shortcuts

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