fangs

package module
v0.0.0-...-20e4ec8 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2023 License: Apache-2.0 Imports: 18 Imported by: 0

README

fangs

A library that makes integrating Cobra and Viper simpler and more consistent.

Background

Anchore Go-based CLI tools use Cobra and Viper for building the basic CLI handling and configuration, respectively. The use of these tools has evolved over the years and some patterns have emerged that seem to work better than others and avoid some pitfalls.

This library uses some best practices we've found for integrating these tools together in fairly simple ways.

Usage

In order to use this library, a consumer will need to:

  • Define configuration structs
    • By default, use mapstructure struct tags (can be changed in the Config)
    • For embedded structs to be inline, these must use the nonstandard ,squash option
  • Define Cobra commands
  • Add flags to Cobra using the *Var* flag variants
  • Call config.Load during command invocation

A number of examples can be seen in the tests, but a simple example is as follows:

// define configuration structs:
type Options struct {
    Output string `mapstructure:"output"`
    Scanning ScanningOptions `mapstructure:"scanning"`
	EmbeddedOptions `mapstructure:",squash"` // need to use ,squash
}

type ScanningOptions struct {
    Depth int `mapstructure:"output"`
}

type EmbeddedOptions struct {
	Embedded string `mapstructure:"string"`
}

// fangs needs a configuration with a minimum of an app name
cfg := config.NewConfig("my-app")

// in a cobra configuration function:
func makeCommand(cfg config.Config) cobra.Command {
    // an instance of options with defaults we use to add flags and configure
    opts := Options{
        Output: "default",
        Scanning: ScanningOptions {
            Depth: 1,
        },
    }

    // make a cobra command with the options you need
    cmd := cobra.Command{
        RunE: func(cmd *cobra.Command, args []string) error {
            // before using opts, call config.Load with the cmd instance,
            // after flags have been added
            err := config.Load(cfg, cmd, &opts)
            // ...
        },
    }

    // add flags like normal, making sure to use the *Var* variants
    flags := cmd.Flags()
    flags.StringVarP(&opts.Output, "output", "o", opts.Output, "output usage")
    flags.IntVar(&opts.Scanning.Depth, "depth", opts.Scanning.Depth, "depth usage")
    
    return cmd
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddFlags

func AddFlags(log logger.Logger, flags *pflag.FlagSet, structs ...any)

AddFlags traverses the object graphs from the structs provided and calls all AddFlags methods implemented on them

func BoolPtrVarP

func BoolPtrVarP(flags *pflag.FlagSet, ptr **bool, name string, short string, usage string)

BoolPtrVarP adds a boolean pointer flag with no default

func FindConfigYamlInCwd

func FindConfigYamlInCwd(_ Config) []string

FindConfigYamlInCwd looks for ./config.yaml -- NOTE: this is not part of the default behavior

func FindDirect

func FindDirect(cfg Config) []string

FindDirect attempts to find a directly configured cfg.File

func FindInAppNameSubdir

func FindInAppNameSubdir(cfg Config) []string

FindInAppNameSubdir looks for ./.<appname>/config.<ext>

func FindInCwd

func FindInCwd(cfg Config) []string

FindInCwd looks for ./.<appname>.<ext>

func FindInHomeDir

func FindInHomeDir(cfg Config) []string

FindInHomeDir looks for ~/.<appname>.<ext>

func FindInXDG

func FindInXDG(cfg Config) (out []string)

FindInXDG looks for <appname>/config.yaml in xdg locations, starting with xdg home config dir then moving upwards

func IntPtrVarP

func IntPtrVarP(flags *pflag.FlagSet, ptr **int, name string, short string, usage string)

IntPtrVarP adds an int pointer flag with no default

func Load

func Load(cfg Config, cmd *cobra.Command, configurations ...any) error

func LoadAt

func LoadAt(cfg Config, cmd *cobra.Command, path string, configuration any) error

func StringPtrVarP

func StringPtrVarP(flags *pflag.FlagSet, ptr **string, name string, short string, usage string)

StringPtrVarP adds a string pointer flag with no default

func Summarize

func Summarize(cfg Config, descriptions DescriptionProvider, values ...any) string

func SummarizeCommand

func SummarizeCommand(cfg Config, cmd *cobra.Command, values ...any) string

func SummarizeLocations

func SummarizeLocations(cfg Config) (out []string)

Types

type Config

type Config struct {
	Logger  logger.Logger `yaml:"-" json:"-" mapstructure:"-"`
	AppName string        `yaml:"-" json:"-" mapstructure:"-"`
	TagName string        `yaml:"-" json:"-" mapstructure:"-"`
	File    string        `yaml:"-" json:"-" mapstructure:"-"`
	Finders []Finder      `yaml:"-" json:"-" mapstructure:"-"`
}

func NewConfig

func NewConfig(appName string) Config

func (*Config) AddFlags

func (c *Config) AddFlags(flags FlagSet)

type DescriptionProvider

type DescriptionProvider interface {
	GetDescription(value reflect.Value, field reflect.StructField) string
}

func DescriptionProviders

func DescriptionProviders(providers ...DescriptionProvider) DescriptionProvider

func NewCommandFlagDescriptionProvider

func NewCommandFlagDescriptionProvider(tagName string, cmd *cobra.Command) DescriptionProvider

func NewFieldDescriber

func NewFieldDescriber(cfgs ...any) DescriptionProvider

func NewStructDescriptionTagProvider

func NewStructDescriptionTagProvider() DescriptionProvider

NewStructDescriptionTagProvider returns a DescriptionProvider that returns "description" field tag values

type FieldDescriber

type FieldDescriber interface {
	DescribeFields(descriptions FieldDescriptionSet)
}

FieldDescriber a struct implementing this interface will have DescribeFields called when Summarize is called

type FieldDescriptionSet

type FieldDescriptionSet interface {
	Add(ptr any, description string)
}

FieldDescriptionSet accepts field descriptions

type FieldDescriptionSetProvider

type FieldDescriptionSetProvider interface {
	DescriptionProvider
	FieldDescriptionSet
}

FieldDescriptionSetProvider implements both DescriptionProvider and FieldDescriptionSet

func NewDirectDescriber

func NewDirectDescriber() FieldDescriptionSetProvider

type Finder

type Finder func(cfg Config) []string

type FlagAdder

type FlagAdder interface {
	AddFlags(flags FlagSet)
}

FlagAdder interface can be implemented by structs in order to add flags when AddFlags is called

type FlagSet

type FlagSet interface {
	BoolVarP(p *bool, name, shorthand, usage string)
	BoolPtrVarP(p **bool, name, shorthand, usage string)
	CountVarP(p *int, name, shorthand, usage string)
	IntVarP(p *int, name, shorthand, usage string)
	StringVarP(p *string, name, shorthand, usage string)
	StringArrayVarP(p *[]string, name, shorthand, usage string)
}

FlagSet defines effectively a subset of the methods exposed by pflag.FieldSet, as fangs requires all flag add calls to use field references in order to match reading configuration and summarization information. The methods do not take default values, however, which should be set on the struct directly. There is one additional method: BoolPtrVarP, which allows for adding flags for bool pointers, needed by some multi-level configurations.

func NewPFlagSet

func NewPFlagSet(log logger.Logger, flags *pflag.FlagSet) FlagSet

type PostLoader

type PostLoader interface {
	PostLoad() error
}

PostLoader is the interface used to do any sort of processing after `config.Load` has been called. This runs after the entire struct has been populated from the configuration files and environment variables

Jump to

Keyboard shortcuts

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