flagutils

package module
v0.0.0-...-ff948a4 Latest Latest
Warning

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

Go to latest
Published: Jan 5, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

README

Command Line Utility Library

This library provides two support frameworks

  • Handling of Option Sets
  • Handling of list-based command output using the streaming library.

Under the folder examples you can find two complete examples describing how to use both library parts in combination:

Option Sets

An OptionSet represents a set of objects implementing the Options interface. Such an object is able to configure a pflag.FlagSet flag set.

Options implementing the Options interface are typically implemented in a dedicated package providing soe standard functions like Newand From. If you follow this pattern, options sets can be used as follows.

You can configure sets of options like this

  opts:= flagutils.DefaultOptionSet{}
  opts.Add(otype1.New(), otype2.New(), ...)

To add the options to a pflag.FlagSet just use

  fs :=  pflag.NewFlagSet("test", pflag.ContinueOnError)
  opts.AddFlags(fs)

The option set can be passed around and if your code wants to access configured values for a dedicated option type the appropriate Options object can be retrieved by using

  myopt := otype1.From(opts)
  myopt.Value() // or any other method provided by your option type. 

A third interface is the OptionSetProvider interface. It is used to describe access to an OptionSet for and other kind of object (for example, a command).

Option sets may be cascaded, they again implement the Options as well as the OptionSetProvider interface and can therefore be added to another OptionSet.

All involved (transitively) Options object can be iterated using the Options method, which is an iter.Seq[Options]. An option set just provides access to options. If it is extendable it should implement the ExtendableOptionSet interface.

A default implementation for an option set provided by the type DefaultOptionSet. It also implements the ExtendableOptionSetinterface and supports the Add method to aggregate Options.

With GetFrom[T] it is possible to retrieve the option in an option set implementing the interface T. Similarly, Filter[T] provides a slice with all options implementing the interface T. T might be a pointer to a concreate option type (*otypepkg.Options), or any interface implemented by an option type.

Option Completion and Validation

An Options object may optionally implement the Validatable interface. If implemented it will be called whenever an option set is validated using the flagutils.Validate function. The Validate(ctx context.Context, opts OptionSet, v ValidationSet) error methods gets access to the used context, the actually validated option set and a validation set.

The validation set can be used to recursively get access to other validated options. THis might be required for different correlated options if the validation of one option requires the state of another option. The validation set keeps track of already validated options to assure that every option is validated only once. Cyclic dependencies among options should be avoided but do not lead to an error. The validation set figures out whether an option is already validated or validating and returns the requested option without further recursive calls. This way the initial order options are added to the OptionSet determines the order resolution for cyclic validation dependencies.

The same way works a Finalizable interface. It can be used to clean up external state after the processing based on an option set. Finalization should be done in the opposite order than the validation. If an OptionSet implements the Validatable or Finalizable interface, it gets control over the handling of the included option objects.

Predefined Option Types

Additionally, some common option types are defined. They follow the standard convention for option objects. Every Options object is implemented in a separate package, always following the same layout:

  • A struct type Options defines the option variables for the correlated set of commandline options bundled by this option object. It implements the Options interface.
  • A function New() and optionally more special functions or additional parameters are provided to create a new Options object. It can then be added to a DefaultOptionSet.
  • Every such Optionsobject supports the configuration methods (if it represents a single flag)
    • WithNames to configure the long and short option names
    • WithDescription to configure the option description. The string is potentially used as format for an Sprintf call fed with option-type specific values.
  • A function From(OptionSetProvider) *Options retrieving the option from an option set, if it is available in this set.
Closure Option

The package closure provides a closure option usable to request recursive processing a list of initial elements (value type bool).

Default values:

  • Long Option: closure
  • Short Option: c

Configuration:

  • WithNames(long,short)
  • WithDescription(desc)

This option supports the element processing by being able to provide an Exploder for a processing chain.

Therefore, there are two constructors taking some info for generating such an exploder:

  • New(chain.Exploder): The exploder code to use
  • NewByFactory(ExploderFactory): a factory able to create an exploder based on other options.

To support types elements for those processing chains, the option type is parameterized with the element type.

Sort Option

The package sort provides a sort option usable to request sorting of field-based output. It accepts a list of sort fields names (value type []string).

Default values:

  • Long Option: sort
  • Short Option: s

Configuration:

  • WithNames(long,short)
  • WithDescription(desc)
  • WithComparator(field, cmp)

This option supports the element processing by being able to provide an CompateFunc for a processing chain to sort elements offering a field value slice. Field values are always strings.

If a field name is prefixed by - the sort order is reversed. Possible field names are taken from another option in the used OptionSet offering a field name slice for the state name FIELD_MODE_SORT. Such a slice is, for example, offered by the output mode option by implementing the output.FieldNameProvider interface.

It implements the flagutils.Validatable interface.

Parallel Option

The package parallel provides a parallel option usable to request parallel processing of elements with a limited degree of parallelity (value type bool).

Default values:

  • Long Option: parallel
  • Short Option: p

Configuration:

  • WithNames(long,short)
  • WithDescription(desc)
  • WithPoolProvider(PoolProvider)

This option works together with the pool package to support parallel processing with limited degree of parallelity. It again works together with the streaming package used to for the list-based processing.

If enabled, the option object provides access to a processor pool able to handle processing requests. The used pool provider can be configured for the option. By default, the simplepool provider is used.

It implements the flagutils.Validatable and flagutils.Finalizableinterface.

When finalized, the manged processing pool is closed again.

Output Mode Option

The package output provides an output mode option usable to request one of multiple possible output modes (like -o wide or -o tree) (value type string).

Default values:

  • Long Option: mode
  • Short Option: o

Configuration:

  • WithNames(long,short)
  • WithDescription(desc)

The New function takes an output.OutputsFactory defining the available output modes (see list-based-output).

It implements the output.FieldNameProvider and flagutils.Validatable interface.

Table Output Options

The package tableoutput provides an output mode for table-based list output.

It also offers an Options object for configuring the behavior via command line options.

  • list of filtered output column names (value type []string).

    Default values:

    • Long Option: columns
    • Short Option: none

    Configuration:

    • WithColumnsNames(long,short)
    • WithColumnsDescription(desc)
  • request all fields if created with optimized mode. (value type bool).

    Default values:

    • Long Option: all-columns
    • Short Option: none

    Configuration:

    • WithAllColumnsNames(long,short)
    • WithAllColumnsDescription(desc)
Option Type Support

There are some types supporting the creation of options.

flagutils.SimpleOption is a standard implementation for an Options object implementing a single option. It can also be used to be aggregated to implement a multi-option Options object.

It offers a default configuration and the methods to adapt the names when creating such an Options object (WithNamesand WithDescription).

The type flagutils.VarPFunc[T] is the type for a function usable to add a flag to a pflag.FlagSet for the value type T. Implementations can be achieved directly from the pflag.FlagSet type, like

(*pflag.FlagSet).StringVarP

It used by the simple option to implement the AddFlags method. With NewSimpleOption[T] an option for the value type T is created, it uses the type T to implicitly determine the flag setter function. With NewSimpleOptionWithSetter[T] the setter can explicitly be given.

Output destinations

The package utils.out offers a simple output redirection bound to a context.Context.

It can be set by out.With(context.Context, OutputContext) and retrieved by out.Get(context.Context) It always provides an output context. The default context is reflecting os.Stdout and os.Stderr.

This package also provides functions for printing using a context, which implicitly evaluate the configured OutputContext.

The outputs provided for the list-based output use this functionality to support context-specific output redirection.

Output destinations are configured by an out.OutputContext object.

List-Based Output

A common use case for some reporting command line interface is to provide commands taking some element specifications and listing attributes for those elements (see kubectl) potentially with different output modes.

The steps required to fulfill this task are always similar:

  • first the input specification is mapped to some root elements.
  • this initial set is enriched by other objects, for example, following dependencies.
  • The elements are mapped out a set of attributes which should be displayed
  • And finally, the elements in the given order are formatted to be displayed on the output stream.

This part of the library provides some support for those commands, based on the streaming library. This library supports the execution of a processing chain consisting of multiple steps, like mapping elements and substituting elements by a set of other elements.

The basic functionality can be found in package output. The central interface is OutputsFactory, It shields a set of available output mode described by elements of type OutputFactory and is used to configure an output.Options describing the command line flags to select the desired output mode.

An OutputFactory is able to create an object implementing the output.Output interface. It can be used to process a slice of input elements and provide the desired output.

Additionally, it supports the output.FieldNameProvider interface to support the sort option. It should at least support the sort.FIELD_MODE_SORT and output.FIELD_MODE_OUTPUT field mode. The first one describes the field names and order for the sort step, and the second one describes the fields available for the final output formatting.

All those factories get access to the option set used to configure the output on the command line. This way, they can adapt their processing to the desires of the user.

Predefined Output Modes

The package provides some default output mode implementations. They are based on the streaming library used to implement the various steps required to map the initial input to the final output.

  • Manifest Outputs: Map the elements to a textual format like JSON or YAML.
  • Table Output: Show the elements as table with a particular column per value field.
  • Tree Output: Like a table output but shows the attributes as a tree. This is applicable if selected elements feature dependencies among each other.

Every mode creates a chain of processing steps, potentially influenced by options of an OptionSet.

Input is an iterator provided by a source object. It is used to feed some processing steps, which may include

  • an explode step used to build the transitive closure.
  • map the elements to a slice of field values
  • sort those elements according to some sor function (provided by the sortoption)
  • and finally, processing the provided elements to generate the desired output
Table Output

The package tableoutput offers an output mode displaying a sequence of elements as table, one column per attribute and one rwo per element.

It offers some formatting options. It is defined by a mapping function able to map elements to a slice of attribute fields. Those elements can then be fed into a sort step (which can be configured by the sort), if it is present in the given option set. It also observes the closure option. If required, an appropriate explode step is processed before the mapping.

The mapping can either be defined by directly giving a mapper, or an output.MappingProvider, which is able to provide a mapper based on an OptionSet. For example, is a transitive output the path should be added to a name field value, but not for non-transitive processing.

A sample output may look like this:

MODE       NAME                                 SIZE ERROR
drwxrwxrwx output                               4096 
-rw-rw-rw- output\interface.go                   653 
-rw-rw-rw- output\options.go                    1513 
-rw-rw-rw- output\output.go                      347 
-rw-rw-rw- output\outputs.go                    1375 
-rw-rw-rw- output\utils.go                      1249 
drwxrwxrwx output\internal                         0 
drwxrwxrwx output\manifest                         0 
-rw-rw-rw- output\internal\impl.go              1041 
-rw-rw-rw- output\internal\interface.go         1691 
-rw-rw-rw- output\manifest\factory.go           1162 
-rw-rw-rw- output\manifest\manifest.go          2237 
drwxrwxrwx output\tableoutput                   4096 
drwxrwxrwx output\treeoutput                    4096 
-rw-rw-rw- output\manifest\output.go            1167 
-rw-rw-rw- output\tableoutput\factory.go        2674 
-rw-rw-rw- output\treeoutput\factory.go         3397 
-rw-rw-rw- output\tableoutput\options.go        1760 
-rw-rw-rw- output\treeoutput\output_test.go     2131 
-rw-rw-rw- output\tableoutput\output.go         3573 
-rw-rw-rw- output\treeoutput\suite_test.go       201 
-rw-rw-rw- output\tableoutput\utils.go          2600 
-rw-rw-rw- output\treeoutput\treeoptions.go     2303 
drwxrwxrwx output\treeoutput\test                  0 
drwxrwxrwx output\treeoutput\topo               4096 
-rw-rw-rw- output\treeoutput\test\a                5 
-rw-rw-rw- output\treeoutput\test\b                3 
-rw-rw-rw- output\treeoutput\topo\sort.go       3067 
-rw-rw-rw- output\treeoutput\topo\sort_test.go  2461 
drwxrwxrwx output\treeoutput\test\dir              0 
-rw-rw-rw- output\treeoutput\topo\suite_test.go  183 
-rw-rw-rw- output\treeoutput\test\dir\a            5 
-rw-rw-rw- output\treeoutput\topo\topo.go       1442 
-rw-rw-rw- output\treeoutput\test\dir\c            6 
drwxrwxrwx output\treeoutput\test\dir\sub          0 
-rw-rw-rw- output\treeoutput\test\dir\sub\d        6 
-rw-rw-rw- output\treeoutput\test\dir\sub\e        3 
drwxrwxrwx examples                                0 
drwxrwxrwx examples\graph                          0 
drwxrwxrwx examples\files                          0 
drwxrwxrwx examples\graph\graph                    0 
drwxrwxrwx examples\files\files                    0 
-rw-rw-rw- examples\graph\graph\closure.go      1584 
-rw-rw-rw- examples\files\files\closure.go      2465 
-rw-rw-rw- examples\graph\graph\graph.go        1087 
-rw-rw-rw- examples\files\files\options.go       465 
drwxrwxrwx examples\graph\app                      0 
-rw-rw-rw- examples\graph\graph\outputs.go      1181 
-rw-rw-rw- examples\graph\graph\source.go       2098 
-rw-rw-rw- examples\files\files\outputs.go      1806 
-rw-rw-rw- examples\graph\app\main.go           1549 
-rw-rw-rw- examples\files\files\sort.go          390 
drwxrwxrwx examples\files\app                      0 
-rw-rw-rw- examples\files\files\source.go       2335 
-rw-rw-rw- examples\files\app\main.go           1725 
processed 55 files
Manifest Output

The package manifest offers an output mode displaying a sequence of elements as textual structured data, like JSON or YAML. Therefore, the elements must implement the Manifest interface.

The elements are mapped to Manifest providing objects, which are then passed to a formatter for the final output.

Before this mapping, optionally the closure option is observed to enrich the chain by an appropriate explode step.

The package provides formatters for JSON and YAML.

With the function AddManifestOutputs the known modes can be added to an existing OutputsFactory:

  • json compressed JSON
  • JSON pretty printed JSON
  • yaml elements as a YAML list
  • YAML elements as a sequence of YAML documents.
Tree Output

The package manifest offers an output mode displaying a sequence of elements as a table of attributes preceeded with a column visualizing a tree structure. This visualization if generated using the tree package. It is able to map a sequence of elements providing some tree-relevant information, like the nesting hierarchy to a sequence tree.TreeObject.

The inbound elements provided by the element source must implement the treeoutput.Element interface, providing some standard node information and topology information.

This sequence is handled by a table output with some intermediate processing steps, doing

  • a topological sort, observing the order of elements on every level as found in the inbound sequence.
  • a mapping to elements providing visualization information
  • and a mapping to enriched field value slices

The last step is then fed into the table output.

The topological sort is defined by a compare function created by a topo.ComparerFactory. The sub package topo provides a standard implementation by providing a factory for creating such a comparer based on an initial sorting order ( topo.NewDefaultComparerFactory).

An example how to use it can be found in exampled/graph.

An output of a table output could look like this:

            NAME VALUE  ERROR
└─ ⊗        c    charly 
   ├─ ⊗     e    eve    
   │  └─    ...         already shown
   ├─ ⊗     b    bob    
   │  ├─    d    david  
   │  └─ ⊗  c    charly 
   │     └─ ...         cycle
   └─ ⊗     a    alice  
      ├─ ⊗  e    eve    
      │  └─ d    david  
      └─    d    david  
processed 11 nodes

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddOptionally

func AddOptionally[T any](set ExtendableOptionSet, opts ...T)

func Filter

func Filter[T any](set OptionSetProvider) []T

Filter extracts elements of type T from the provided OptionSetProvider and returns them as a slice of T.

func Finalize

func Finalize(ctx context.Context, set OptionSetProvider, val FinalizationSet) error

Finalize checks whether the provided OptionSetProvider or its nested options implement the Finalizable interface and finalizes them. It returns an error if any finalization fails or nil if all finalizations succeed.

func GetFrom

func GetFrom[T any](set OptionSetProvider) T

GetFrom retrieves an option of type T from the provided OptionSetProvider and returns it. T is typically a pointer to an option struct of type Options. If an interface type is used the first found implementation is returned. To get all options implementing an interface use Filter.

func Implements

func Implements[T any](o Options) bool

func RetrieveFrom

func RetrieveFrom(set OptionSetProvider, proto interface{}) bool

RetrieveFrom extracts the option for a given target. This might be a

  • pointer to a struct implementing the Options interface which will fill the struct with a copy of the options OR
  • a pointer to such a pointer which will be filled with the pointer to the actual member of the OptionSet.

func SelectByInterface

func SelectByInterface[T any](set OptionSet, sel ...OptionSelector) []T

func Validate

func Validate(ctx context.Context, set OptionSetProvider, val ValidationSet) error

Validate checks whether the provided OptionSetProvider or its nested options implement the Validatable interface and validates them. It returns an error if any validation fails or nil if all validations succeed.

func ValidatedFilteredOptions

func ValidatedFilteredOptions[O any](ctx context.Context, opts OptionSet, s ValidationSet) ([]O, error)

ValidatedFilteredOptions filters an OptionSet for elements of type O and validates each element against a ValidationSet. Returns the filtered and validated list of elements or an error if validation fails. It is typically used with an interface type to get all Options objects implementing this interface.

func ValidatedOptions

func ValidatedOptions[O any](ctx context.Context, opts OptionSet, s ValidationSet) (O, error)

ValidatedOptions provides a validated Options object of the given type. The type is typically a pointer type to the Options struct.

Types

type DefaultOptionSet

type DefaultOptionSet []Options

DefaultOptionSet defines a slice of Options, representing a basic implementation of an OptionSet.

func Select

func Select(set OptionSet, sel OptionSelector) DefaultOptionSet

func (*DefaultOptionSet) Add

func (DefaultOptionSet) AddFlags

func (s DefaultOptionSet) AddFlags(fs *pflag.FlagSet)

func (DefaultOptionSet) AsOptionSet

func (s DefaultOptionSet) AsOptionSet() OptionSet

func (DefaultOptionSet) Options

func (s DefaultOptionSet) Options(yield func(Options) bool)

func (DefaultOptionSet) Usage

func (s DefaultOptionSet) Usage() string

type ExtendableOptionSet

type ExtendableOptionSet interface {
	OptionSet
	Add(o ...Options) ExtendableOptionSet
}

type Finalizable

type Finalizable interface {
	Finalize(ctx context.Context, opts OptionSet, v FinalizationSet) error
}

Finalizable represents a type that can perform a finalization operation with a context and a set of options. Options keeping external state should implement this interface.

type FinalizationSet

type FinalizationSet set.Set[Finalizable]

FinalizationSet is a set of finalization elements that ensures each element is finalized only once within a context. It keeps a set of already finalized objects. If there are cyclic finalizations, only the first call finalizes the object. The order therefore depends on the order of the executed initial finalizations, No error is provided for such cyclic scenarios.

func (FinalizationSet) Finalize

func (s FinalizationSet) Finalize(ctx context.Context, opts OptionSet, o any) error

func (FinalizationSet) FinalizeSet

func (s FinalizationSet) FinalizeSet(ctx context.Context, opts OptionSet, set OptionSetProvider) error

FinalizeSet finalizes the OptionSet given by the OptionSetProvider against a more general OptionSet using the provided FinalizationSet. It iterates over the options in the set and applies validation using the provided context and the general OptionSet. If validation fails for any option, the function returns the respective error. This function is intended to be used by Validation method in some Options object requiring to forward Validation to a nested OptionSet. Note: If an object implements a Finalize method, it is also responsible to handle nested options.

type NoOptions

type NoOptions struct{}

func (NoOptions) AddFlags

func (NoOptions) AddFlags(fs *pflag.FlagSet)

type OptionSelector

type OptionSelector func(Options) bool

func Always

func Always() OptionSelector

func And

func Never

func Never() OptionSelector

func Not

func Or

type OptionSet

type OptionSet interface {
	Options
	OptionSetProvider
	Options(yield func(Options) bool)
}

OptionSet is an interface representing a set of Options. It acts as Options and OptionSetProvider and provides a method to iterate over nested Options.

type OptionSetProvider

type OptionSetProvider interface {
	AsOptionSet() OptionSet
}

OptionSetProvider defines an interface for types capable of providing an OptionSet by implementing the AsOptionSet method.

type Options

type Options interface {
	AddFlags(fs *pflag.FlagSet)
}

Options provides an interface for adding flags to a given pflag.FlagSet using the AddFlags method.

type SetBasedOptions

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

func (*SetBasedOptions) Add

func (s *SetBasedOptions) Add(o ...Options) OptionSet

func (*SetBasedOptions) AddFlags

func (s *SetBasedOptions) AddFlags(fs *pflag.FlagSet)

func (*SetBasedOptions) AsOptionSet

func (s *SetBasedOptions) AsOptionSet() OptionSet

type SimpleOption

type SimpleOption[V any, T Options] struct {
	// contains filtered or unexported fields
}

func NewSimpleOption

func NewSimpleOption[V any, T Options](self T, def V, long, short, desc string) SimpleOption[V, T]

func NewSimpleOptionWithSetter

func NewSimpleOptionWithSetter[V any, T Options](self T, setter VarPFunc[V], def V, long, short, desc string) SimpleOption[V, T]

func (*SimpleOption[V, T]) AddFlags

func (o *SimpleOption[V, T]) AddFlags(fs *pflag.FlagSet)

func (*SimpleOption[V, T]) Set

func (o *SimpleOption[V, T]) Set(v V) T

func (*SimpleOption[V, T]) Value

func (o *SimpleOption[V, T]) Value() V

func (*SimpleOption[V, T]) WithDescription

func (o *SimpleOption[V, T]) WithDescription(s string) T

func (*SimpleOption[V, T]) WithNames

func (o *SimpleOption[V, T]) WithNames(l, s string) T

type Usage

type Usage interface {
	Usage() string
}

Usage is an interface representing an entity capable of producing a usage string via the Usage method. This info is a length description of the purpose of the option, which can be used in the command description.

type Validatable

type Validatable interface {
	Validate(ctx context.Context, opts OptionSet, v ValidationSet) error
}

Validatable defines an interface for objects that can be validated based on an OptionSet within a given context. Optionally, the given context as well as the other options in the OptionSet can also be used to complete the option state. If nested elements are used, they must be validated using the given ValidationSet to assert they are already validated before used.

type ValidationSet

type ValidationSet set.Set[Validatable]

ValidationSet is a set of Validatable elements that ensures each element is validated only once within a context. It keeps a set of already validated objects. If there are cyclic evaluations, only the first call evaluates the object. The order therefore depends on the order of the executed initial validations, No error is provided for such cyclic scenarios.

func (ValidationSet) Validate

func (s ValidationSet) Validate(ctx context.Context, opts OptionSet, o any) error

func (ValidationSet) ValidateSet

func (s ValidationSet) ValidateSet(ctx context.Context, opts OptionSet, set OptionSetProvider) error

ValidateSet validates the OptionSet givey an OptionSetProvider against a more general OptionSet using the provided ValidationSet. It iterates over the options in the set and applies validation using the provided context and the general OptionSet. If validation fails for any option, the function returns the respective error. This function is intended to be used by Validation method in some Options object requiring to forward Validation to a nested OptionSet. Note: If an object implements a Validation method, it is also responsible to handle nested options.

type VarPFunc

type VarPFunc[V any] = func(fs *pflag.FlagSet, p *V, name, shorthand string, value V, usage string)

func VarPFuncFor

func VarPFuncFor[T any]() VarPFunc[T]

Directories

Path Synopsis
examples
files/app command
graph/app command
utils
out

Jump to

Keyboard shortcuts

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