{"id":35014154,"url":"https://github.com/mandelsoft/flagutils","last_synced_at":"2026-05-22T19:36:20.015Z","repository":{"id":323353532,"uuid":"1087253354","full_name":"mandelsoft/flagutils","owner":"mandelsoft","description":null,"archived":false,"fork":false,"pushed_at":"2025-11-09T16:19:24.000Z","size":101,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-11-09T18:19:34.942Z","etag":null,"topics":["cli","command-line-interface","command-line-utility","flags","golang","golang-library","library","options-api","output-formatting"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mandelsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-31T15:56:28.000Z","updated_at":"2025-11-09T16:19:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mandelsoft/flagutils","commit_stats":null,"previous_names":["mandelsoft/flagutils"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/mandelsoft/flagutils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandelsoft%2Fflagutils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandelsoft%2Fflagutils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandelsoft%2Fflagutils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandelsoft%2Fflagutils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mandelsoft","download_url":"https://codeload.github.com/mandelsoft/flagutils/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandelsoft%2Fflagutils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28072771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-27T02:00:05.897Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line-interface","command-line-utility","flags","golang","golang-library","library","options-api","output-formatting"],"created_at":"2025-12-27T05:11:05.800Z","updated_at":"2026-05-22T19:36:20.004Z","avatar_url":"https://github.com/mandelsoft.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Command Line Utility Library\n\nThis library provides three support frameworks related to commmand line options\n- Handling of Option Sets\n- Handling of list-based command output using the [streaming library](https://github.com/mandelsoft/streaming).\n- Configuring implementation variants by potentially overlapping sets \n  of command line options.\n\nUnder the folder `examples` you can find two complete examples \ndescribing how to use both library parts in combination:\n\n- [Listing of files](examples/files)\n- [Simple Graph Traversal](examples/graph)\n- [Object Configuration](examples/flagsets)\n\nAdditionally, the package [pflags](pflags) provides additional technical flag types\nto be used together with the [pflag package](https://github.com/spf13/pflag)\n\n## Option Sets\n\nAn `OptionSet` represents a set of objects implementing the `Options` interface.\nSuch an object is able to configure a [`pflag.FlagSet`](https://github.com/spf13/pflag) flag set.\n\nOptions implementing the `Options` interface are typically implemented in a dedicated \npackage providing soe standard functions like `New`and `From`. If you follow\nthis pattern, options sets can be used as follows.\n\nYou can configure sets of options like this\n\n```go\n  opts:= flagutils.DefaultOptionSet{}\n  opts.Add(otype1.New(), otype2.New(), ...)\n```\n\nTo add the options to a `pflag.FlagSet` just use\n\n```go\n  fs :=  pflag.NewFlagSet(\"test\", pflag.ContinueOnError)\n  opts.AddFlags(fs)\n```\n\nThe option set can be passed around and \nif your code wants to access configured values for a dedicated option type\nthe appropriate `Options` object can be retrieved by using\n\n```go\n  myopt := otype1.From(opts)\n  myopt.Value() // or any other method provided by your option type. \n```\n\nA third interface is the `OptionSetProvider` interface. It is used to describe access to\nan `OptionSet` for and other kind of object (for example, a command).\n\nOption sets may be cascaded, they again implement the `Options` as well as the `OptionSetProvider`\ninterface and can therefore\nbe added to another `OptionSet`.\n\nAll involved (transitively) `Options` object can be iterated using the `Options`\nmethod, which is an `iter.Seq[Options]`. An option set just provides access to options.\nIf it is extendable it should implement the `ExtendableOptionSet` interface.\n\nA default implementation for an option set provided by the type `DefaultOptionSet`.\nIt also implements the `ExtendableOptionSet`interface and supports the `Add`\nmethod to aggregate `Options`.\n\nWith `GetFrom[T]` it is possible to retrieve the option in an option set\nimplementing the interface `T`. Similarly, `Filter[T]` provides a slice\nwith all options implementing the interface `T`. `T` might be \na pointer to a concreate option type (`*otypepkg.Options`), or any interface implemented by an option type.\n\n### Option Completion and Validation\n\nAn `Options` object may optionally implement the `Validatable` interface.\nIf implemented it will be called whenever an option set is validated using\nthe `flagutils.Validate` function. The `Validate(ctx context.Context, opts OptionSet, v ValidationSet) error`\nmethods gets access to the used context, the actually validated option set and\na validation set.\n\nThe validation set can be used to recursively get access to other validated\noptions. THis might be required for different correlated options if\nthe validation of one option requires the state of another option.\nThe validation set keeps track of already validated options to assure \nthat every option is validated only once. Cyclic dependencies among\noptions should be avoided but do not lead to an error.\nThe validation set figures out whether an option is already validated or validating\nand returns the requested option without further recursive calls.\nThis way the initial order options are added to the `OptionSet`\ndetermines the order resolution for cyclic validation dependencies.\n\nThe same way works a `Finalizable` interface. It can be used to clean up\nexternal state after the processing based on an option set. Finalization\nshould be done in the opposite order than the validation.\nIf an `OptionSet` implements the `Validatable` or `Finalizable` interface,\nit gets control over the handling of the included option objects.\n\n### Predefined Option Types\n\nAdditionally, some common option types are defined.\nThey follow the standard convention for option objects. Every `Options` object \nis implemented in a separate package, always following the same layout:\n- A struct type `Options` defines the option variables for the correlated set of commandline\n  options bundled by this option object. It implements the `Options` interface.\n- A function `New()` and optionally more special functions or additional\n  parameters are provided to create a new Options object. It can then be added to\n  a `DefaultOptionSet`.\n- Every such `Options`object supports the configuration methods (if it represents\n  a single flag)\n  - `WithNames` to configure the long and short option names\n  - `WithDescription` to configure the option description. The string is\n    potentially used as format for an `Sprintf` call fed with option-type\n    specific values.\n- A function `From(OptionSetProvider) *Options` retrieving the option\n  from an option set, if it is available in this set.\n\n#### Closure Option\n\nThe package `closure` provides a closure option usable to request recursive processing a list of initial elements (value type `bool`).\n\nDefault values:\n- *Long Option*: `closure`\n- *Short Option*: `c`\n\nConfiguration:\n- `WithNames(long,short)`\n- `WithDescription(desc)`\n\nThis option supports the element processing by being able to\nprovide an `Exploder` for a processing chain.\n\nTherefore, there are two constructors taking some info for generating such\nan exploder:\n- `New(chain.Exploder)`: The exploder code to use\n- `NewByFactory(ExploderFactory)`: a factory able to create an exploder based on other options.\n\nTo support types elements for those processing chains, the \noption type is parameterized with the element type.\n\n### Sort Option\n\nThe package `sort` provides a sort option usable to request sorting of field-based output.\nIt accepts a list of sort fields names (value type `[]string`).\n\nDefault values:\n- *Long Option*: `sort`\n- *Short Option*: `s`\n\nConfiguration:\n- `WithNames(long,short)`\n- `WithDescription(desc)`\n- `WithComparator(field, cmp)`\n\nThis option supports the element processing by being able to\nprovide an `CompateFunc` for a processing chain to sort elements\noffering a field value slice. Field values are always strings.\n\nIf a field name is prefixed by `-` the sort order is reversed.\nPossible field names are taken from another option in the \nused `OptionSet` offering a field name slice for the state name\nFIELD_MODE_SORT. Such a slice is, for example, offered by the \n[output mode option](#output-mode-option) by implementing\nthe `output.FieldNameProvider` interface.\n\nIt implements the `flagutils.Validatable` interface.\n\n#### Parallel Option\n\nThe package `parallel` provides a parallel option usable to request \nparallel processing of elements with a limited degree of parallelity\n(value type `bool`).\n\nDefault values:\n- *Long Option*: `parallel`\n- *Short Option*: `p`\n\nConfiguration:\n- `WithNames(long,short)`\n- `WithDescription(desc)`\n- `WithPoolProvider(PoolProvider)`\n\nThis option works together with the `pool` package to support parallel\nprocessing with limited degree of parallelity. It again works together\nwith the streaming package used to for the [list-based processing](#list-based-output).\n\nIf enabled, the option object provides access to a processor pool\nable to handle processing requests. The used pool provider can be configured\nfor the option. By default, the `simplepool` provider is used.\n\nIt implements the `flagutils.Validatable` and `flagutils.Finalizable`interface.\n\nWhen finalized, the manged processing pool is closed again.\n\n#### Output Mode Option\n\nThe package `output` provides an output mode option usable to request\none of multiple possible output modes (like `-o wide` or `-o tree`)\n(value type `string`).\n\nDefault values:\n- *Long Option*: `mode`\n- *Short Option*: `o`\n\nConfiguration:\n- `WithNames(long,short)`\n- `WithDescription(desc)`\n\nThe `New` function takes an `output.OutputsFactory` defining the available\noutput modes (see [list-based-output](#list-based-output)).\n\nIt implements the `output.FieldNameProvider` and `flagutils.Validatable` interface.\n\n#### Table Output Options\n\nThe package `tableoutput` provides an output mode for [table-based list output](#table-output).\n\nIt also offers an `Options` object for configuring the behavior via\ncommand line options.\n\n- list of filtered output column names (value type `[]string`).\n\n  Default values:\n  - *Long Option*: `columns`\n  - *Short Option*: none\n\n  Configuration:\n  - `WithColumnsNames(long,short)`\n  - `WithColumnsDescription(desc)`\n\n- request all fields if created with optimized mode. (value type `bool`).\n\n  Default values:\n  - *Long Option*: `all-columns`\n  - *Short Option*: none\n\n  Configuration:\n  - `WithAllColumnsNames(long,short)`\n  - `WithAllColumnsDescription(desc)`\n\n### Option Type Support\n\nThere are some types supporting the creation of options.\n\n`flagutils.SimpleOption` is a standard implementation for an\n`Options` object implementing a single option. It can also be used\nto be aggregated to implement a multi-option `Options` object.\n\nIt offers a default configuration and the methods to adapt\nthe names when creating such an `Options` object (`WithNames`and `WithDescription`).\n\nThe type `flagutils.VarPFunc[T]` is the type for a function\nusable to add a flag to a `pflag.FlagSet` for the value type `T`.\nImplementations can be achieved directly from the `pflag.FlagSet`\ntype, like\n\n```go\n(*pflag.FlagSet).StringVarP\n```\n\nIt used by the simple option to implement the `AddFlags` method.\nWith `NewSimpleOption[T]` an option for the value type `T` is created,\nit uses the type `T` to implicitly determine the flag setter function.\nWith `NewSimpleOptionWithSetter[T]` the setter can explicitly be given.\n\n## Output destinations\n\nThe package `utils.out` offers a simple output redirection bound to a `context.Context`. \n\nIt can be set by `out.With(context.Context, OutputContext)` and retrieved\nby `out.Get(context.Context)` It always provides an output context. The default context is reflecting `os.Stdout` and `os.Stderr`.\n\nThis package also provides functions for printing using a context, which implicitly evaluate the configured `OutputContext`.\n\nThe [outputs](#predefined-output-modes) provided for the [list-based output](#list-based-output) use this functionality \nto support context-specific output redirection.\n\nOutput destinations are configured by an `out.OutputContext` object.\n\n## List-Based Output\n\nA common use case for some reporting command line interface \nis to provide commands taking some element specifications and listing\nattributes for those elements (see kubectl) potentially with different\noutput modes. \n\nThe steps required to fulfill this task are always similar:\n- first the input specification is mapped to some root elements.\n- this initial set is enriched by other objects, for example, following dependencies.\n- The elements are mapped out a set of attributes which should be displayed\n- And finally, the elements in the given order are formatted to be displayed on the output stream.\n\nThis part of the library provides some support for those commands, based\non the [streaming library](https://github.com/mandelsoft/streaming).\nThis library supports the execution of a processing chain consisting of multiple steps, like mapping elements and substituting elements by a set of other elements.\n\nThe basic functionality can be found in package `output`. \nThe central interface is `OutputsFactory`, It shields a set of\navailable output mode described by elements of type `OutputFactory` and\nis used to configure an `output.Options` describing the command line flags to select the desired output mode.\n\nAn `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.\n\nAdditionally, it supports the `output.FieldNameProvider` interface to support the [sort](#sort-option) option. It should at least support the `sort.FIELD_MODE_SORT` and `output.FIELD_MODE_OUTPUT` field mode.\nThe first one describes the field names and order for the sort step, and \nthe second one describes the fields available for the final output formatting.\n\nAll 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\nthe desires of the user.\n\n\n### Predefined Output Modes\n\nThe package provides some default output mode implementations. They\nare based on the streaming library used to implement the various steps\nrequired to map the initial input to the final output.\n\n- [*Manifest Outputs*](#manifest-output): Map the elements to a textual format like JSON or YAML.\n- [*Table Output*](#table-output): Show the elements as table with a particular column per value field.\n- [*Tree Output*](#tree-output): Like a table output but shows the attributes as a tree. This is applicable if selected elements feature dependencies among each other.\n\nEvery mode creates a chain of processing steps, potentially influenced by\noptions of an `OptionSet`. \n\nInput is an iterator provided by a source object. It is used to feed some\nprocessing steps, which may include\n- an *explode* step used to build the transitive closure.\n- map the elements to a slice of field values\n- sort those elements according to some sor function (provided by the `sort`option)\n- and finally, processing the provided elements to generate the desired output\n\n### Table Output\n\nThe package `tableoutput` offers an output mode displaying a sequence of elements as table, one column per attribute and one rwo per element.\n\nIt offers some [formatting options](#table-output-options).\nIt 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`](#sort-option)), if it is present in the given option set.\nIt also observes the [`closure` option](#closure-option). If required, an appropriate *explode* step is processed before the mapping. \n\nThe 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.\n\nA sample output may look like this:\n\n```\nMODE       NAME                                 SIZE ERROR\ndrwxrwxrwx output                               4096 \n-rw-rw-rw- output\\interface.go                   653 \n-rw-rw-rw- output\\options.go                    1513 \n-rw-rw-rw- output\\output.go                      347 \n-rw-rw-rw- output\\outputs.go                    1375 \n-rw-rw-rw- output\\utils.go                      1249 \ndrwxrwxrwx output\\internal                         0 \ndrwxrwxrwx output\\manifest                         0 \n-rw-rw-rw- output\\internal\\impl.go              1041 \n-rw-rw-rw- output\\internal\\interface.go         1691 \n-rw-rw-rw- output\\manifest\\factory.go           1162 \n-rw-rw-rw- output\\manifest\\manifest.go          2237 \ndrwxrwxrwx output\\tableoutput                   4096 \ndrwxrwxrwx output\\treeoutput                    4096 \n-rw-rw-rw- output\\manifest\\output.go            1167 \n-rw-rw-rw- output\\tableoutput\\factory.go        2674 \n-rw-rw-rw- output\\treeoutput\\factory.go         3397 \n-rw-rw-rw- output\\tableoutput\\options.go        1760 \n-rw-rw-rw- output\\treeoutput\\output_test.go     2131 \n-rw-rw-rw- output\\tableoutput\\output.go         3573 \n-rw-rw-rw- output\\treeoutput\\suite_test.go       201 \n-rw-rw-rw- output\\tableoutput\\utils.go          2600 \n-rw-rw-rw- output\\treeoutput\\treeoptions.go     2303 \ndrwxrwxrwx output\\treeoutput\\test                  0 \ndrwxrwxrwx output\\treeoutput\\topo               4096 \n-rw-rw-rw- output\\treeoutput\\test\\a                5 \n-rw-rw-rw- output\\treeoutput\\test\\b                3 \n-rw-rw-rw- output\\treeoutput\\topo\\sort.go       3067 \n-rw-rw-rw- output\\treeoutput\\topo\\sort_test.go  2461 \ndrwxrwxrwx output\\treeoutput\\test\\dir              0 \n-rw-rw-rw- output\\treeoutput\\topo\\suite_test.go  183 \n-rw-rw-rw- output\\treeoutput\\test\\dir\\a            5 \n-rw-rw-rw- output\\treeoutput\\topo\\topo.go       1442 \n-rw-rw-rw- output\\treeoutput\\test\\dir\\c            6 \ndrwxrwxrwx output\\treeoutput\\test\\dir\\sub          0 \n-rw-rw-rw- output\\treeoutput\\test\\dir\\sub\\d        6 \n-rw-rw-rw- output\\treeoutput\\test\\dir\\sub\\e        3 \ndrwxrwxrwx examples                                0 \ndrwxrwxrwx examples\\graph                          0 \ndrwxrwxrwx examples\\files                          0 \ndrwxrwxrwx examples\\graph\\graph                    0 \ndrwxrwxrwx examples\\files\\files                    0 \n-rw-rw-rw- examples\\graph\\graph\\closure.go      1584 \n-rw-rw-rw- examples\\files\\files\\closure.go      2465 \n-rw-rw-rw- examples\\graph\\graph\\graph.go        1087 \n-rw-rw-rw- examples\\files\\files\\options.go       465 \ndrwxrwxrwx examples\\graph\\app                      0 \n-rw-rw-rw- examples\\graph\\graph\\outputs.go      1181 \n-rw-rw-rw- examples\\graph\\graph\\source.go       2098 \n-rw-rw-rw- examples\\files\\files\\outputs.go      1806 \n-rw-rw-rw- examples\\graph\\app\\main.go           1549 \n-rw-rw-rw- examples\\files\\files\\sort.go          390 \ndrwxrwxrwx examples\\files\\app                      0 \n-rw-rw-rw- examples\\files\\files\\source.go       2335 \n-rw-rw-rw- examples\\files\\app\\main.go           1725 \nprocessed 55 files\n```\n\n### Manifest Output\n\nThe package `manifest` offers an output mode displaying a sequence of elements as textual structured data, like JSON or YAML.\nTherefore, the elements must implement the `Manifest` interface.\n\nThe elements are mapped to `Manifest` providing objects, which are then passed to a formatter for the final output.\n\nBefore this mapping, optionally the [`closure` option](#closure-option)\nis observed to enrich the chain by an appropriate *explode* step.\n\nThe package provides formatters for JSON and YAML. \n\nWith the function `AddManifestOutputs` the known modes can be added to an existing `OutputsFactory`:\n- `json` compressed JSON\n- `JSON` pretty printed JSON\n- `yaml` elements as a YAML list\n- `YAML` elements as a sequence of YAML documents.\n\n\n### Tree Output\n\nThe 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.\nIt is able to map a sequence of elements providing some tree-relevant\ninformation, like the nesting hierarchy to a sequence `tree.TreeObject`.\n\nThe inbound elements provided by the element source must implement the \n`treeoutput.Element` interface, providing some standard node information and topology information.\n\nThis sequence is handled by a [`table output`](#table-output) with some\nintermediate processing steps, doing\n- a topological sort, observing the order of elements on every level as found in the inbound sequence.\n- a mapping to elements providing visualization information\n- and a mapping to enriched field value slices \n\nThe last step is then fed into the table output.\n\nThe topological sort is defined by a compare function created\nby a `topo.ComparerFactory`.\nThe sub package `topo` provides a standard implementation by providing\na factory for creating such a comparer based on an initial sorting order\n( `topo.NewDefaultComparerFactory`).\n\nAn example how to use it can be found in [`exampled/graph`](examples/graph).\n\nAn output of a table output could look like this:\n\n```\n            NAME VALUE  ERROR\n└─ ⊗        c    charly \n   ├─ ⊗     e    eve    \n   │  └─    ...         already shown\n   ├─ ⊗     b    bob    \n   │  ├─    d    david  \n   │  └─ ⊗  c    charly \n   │     └─ ...         cycle\n   └─ ⊗     a    alice  \n      ├─ ⊗  e    eve    \n      │  └─ d    david  \n      └─    d    david  \nprocessed 11 nodes\n```\n\n## Object Configuration\n\nThe package [flagset](flagsets) offers a more flexible handling for correlated sets of options.\nIt introduces `OptionType`s, which represent a particular kind of Option with a name a description and a technical type according to the [pflag](https://github.com/spf13/pflag) flag types. Hereby, they represent a particular meaning on top of the pure technical type.\n\nSuch types can then be composed to `OptionTypeSet`s representing a set of correlated options, for example options used for a dedicated purpose. Such sets can dynamically provide an `OptionSet` consisting of `Option` object and can be added to a `pflag.FlagSet`, similar to technical options.\n\nComposing such sets can use overlapping `OptionsSet`s again, which is not possible for a `pflag.FlagSet`. It is possible, because the effectice option set is only created after the composition\nis done and shared options are deduplicated.\n\nA more high-level `TypedOptionSetConfigProvider` is introduced, which uses a separate type option to\nspecify the selection of a variant described by nested sets.\n\nAfter evaluation of concrete command line options a consistent set of options for the selected\nvariant is provided, which is mapped to a Config object describing the setting for the selected object type. Hereby, consistency checks are done, to notify about invalid option combinations.\n\nA complete example can be found in [examples/flagsets](examples/flagsets/usage.go). It uses a simple\nScheme` type to describe the variants and bundles the features of the flagsets package.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandelsoft%2Fflagutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmandelsoft%2Fflagutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandelsoft%2Fflagutils/lists"}