{"id":13532632,"url":"https://github.com/status-im/nim-confutils","last_synced_at":"2025-06-17T03:35:08.420Z","repository":{"id":33509641,"uuid":"158551734","full_name":"status-im/nim-confutils","owner":"status-im","description":"Simplified handling of command line options and config files","archived":false,"fork":false,"pushed_at":"2025-01-13T07:44:54.000Z","size":207,"stargazers_count":64,"open_issues_count":27,"forks_count":16,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-06-09T14:59:36.955Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Nim","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/status-im.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHEv2","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}},"created_at":"2018-11-21T13:25:25.000Z","updated_at":"2025-01-13T07:44:57.000Z","dependencies_parsed_at":"2023-02-14T15:46:50.136Z","dependency_job_id":"dabef50f-767e-4f0e-a6d6-81642d484901","html_url":"https://github.com/status-im/nim-confutils","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/status-im/nim-confutils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/status-im%2Fnim-confutils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/status-im%2Fnim-confutils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/status-im%2Fnim-confutils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/status-im%2Fnim-confutils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/status-im","download_url":"https://codeload.github.com/status-im/nim-confutils/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/status-im%2Fnim-confutils/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260286298,"owners_count":22986552,"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","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":[],"created_at":"2024-08-01T07:01:12.457Z","updated_at":"2025-06-17T03:35:08.399Z","avatar_url":"https://github.com/status-im.png","language":"Nim","funding_links":[],"categories":["Development Tools","[Nim](https://nim-lang.org/)","Nim"],"sub_categories":["Command-Line Interface Automation","Useful awesome list for Go cli"],"readme":"nim-confutils\n=============\n\n[![License: Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![Github action](https://github.com/status-im/nim-confutils/workflows/CI/badge.svg)\n\n## Introduction\n\nConfutils is a library that aims to solve the configuration problem\nwith a holistic approach. The run-time configuration of a program\nis described as a plain Nim object type from which the library\nautomatically derives the code for handling command-line options,\nconfiguration files and other platform-specific sources such as the\nWindows registry.\n\nThe library focuses on providing a lot of compile-time configurability\nand extensibility with a strong adherence to the DRY principle.\n\nLet's illustrate the API with a highly annotated example. Our configuration\nmight be described in a separate module looking like this:\n\n```nim\n# config.nim\nimport\n  confutils/defs\n\ntype\n  NimbusConf* = object\n    #\n    # This is our configuration type.\n    #\n    # Each field will be considered a configuration option that may appear\n    # on the command-line, whitin an environment variable or a configuration\n    # file, or elsewhere. Custom pragmas are used to annotate the fields with\n    # additional metadata that is used to augment the behavior of the library.\n    #\n    logLevel* {.\n      defaultValue: LogLevel.INFO\n      desc: \"Sets the log level\" }: LogLevel\n\n    #\n    # This program uses a CLI interface with sub-commands (similar to git).\n    #\n    # The `StartUpCommand` enum provides the list of available sub-commands,\n    # but since we are specifying a default value of `noCommand`, the user\n    # can also launch the program without entering any particular command.\n    # The default command will also be omitted from help messages.\n    #\n    # Please note that the `logLevel` option above will be shared by all\n    # sub-commands. The rest of the nested options will be relevant only\n    # when the designated sub-command is being invoked.\n    #\n    case cmd* {.\n      command\n      defaultValue: noCommand }: StartUpCommand\n\n    of noCommand:\n      dataDir* {.\n        defaultValue: getConfigDir() / \"nimbus\"\n        desc: \"The directory where nimbus will store all blockchain data.\"\n        abbr: \"d\" }: DirPath\n\n      bootstrapNodes* {.\n        desc: \"Specifies one or more bootstrap nodes to use when connecting to the network.\"\n        abbr: \"b\"\n        name: \"bootstrap-node\" }: seq[string]\n\n      bootstrapNodesFile* {.\n        defaultValue: \"\"\n        desc: \"Specifies a line-delimited file of bootsrap Ethereum network addresses\"\n        abbr: \"f\" }: InputFile\n\n      tcpPort* {.\n        desc: \"TCP listening port\" }: int\n\n      udpPort* {.\n        desc: \"UDP listening port\" }: int\n\n      validators* {.\n        required\n        desc: \"A path to a pair of public and private keys for a validator. \" \u0026\n              \"Nimbus will automatically add the extensions .privkey and .pubkey.\"\n        abbr: \"v\"\n        name: \"validator\" }: seq[PrivateValidatorData]\n\n      stateSnapshot* {.\n        desc: \"Json file specifying a recent state snapshot\"\n        abbr: \"s\" }: Option[BeaconState]\n\n    of createChain:\n      chainStartupData* {.\n        desc: \"\"\n        abbr: \"c\" }: ChainStartupData\n\n      outputStateFile* {.\n        desc: \"Output file where to write the initial state snapshot\"\n        name: \"out\"\n        abbr: \"o\" }: OutFilePath\n\n  StartUpCommand* = enum\n    noCommand\n    createChain\n\n  #\n  # The configuration can use user-defined types that feature custom\n  # command-line parsing and serialization routines.\n  #\n  PrivateValidatorData* = object\n    privKey*: ValidatorPrivKey\n    randao*: Randao\n\n```\n\nThen from our main module, we just need to call `confutils.load` which must be\ngiven our configuration type as a parameter:\n\n```nim\n# main.nim\nimport\n  confutils, config\n\nwhen isMainModule:\n  let conf = NimbusConf.load()\n  initDatabase conf.dataDir\n```\n\nAnd that's it - calling `load` with default parameters will first process any\n[command-line options](#handling-of-command-line-options) and then it will\ntry to load any missing options from the most appropriate\n[configuration location](#handling-of-environment-variables-and-config-files)\nfor the platform. Diagnostic messages will be provided for many simple\nconfiguration errors and the following help message will be produced\nautomatically when calling the program with `program --help`:\n\n```\nUsage: beacon_node [OPTIONS] \u003ccommand\u003e\n\nThe following options are supported:\n\n  --logLevel=LogLevel                        : Sets the log level\n  --dataDir=DirPath                          : The directory where nimbus will store all blockchain data.\n  --bootstrapNode=seq[string]                : Specifies one or more bootstrap nodes to use when connecting to the network.\n  --bootstrapNodesFile=FilePath              : Specifies a line-delimited file of bootsrap Ethereum network addresses\n  --tcpPort=int                              : TCP listening port\n  --udpPort=int                              : UDP listening port\n  --validator=seq[PrivateValidatorData]      : A path to a pair of public and private keys for a validator. Nimbus will automatically add the extensions .privkey and .pubkey.\n  --stateSnapshot=Option[BeaconState]        : Json file specifying a recent state snapshot\n\nAvailable sub-commands:\n\n  beacon_node createChain\n\n  --out=OutFilePath                          : Output file where to write the initial state snapshot\n\n```\n\nFor simpler CLI utilities, Confutils also provides the following convenience APIs:\n\n```nim\nimport\n  confutils\n\ncli do (validators {.\n          desc: \"number of validators\"\n          abbr: \"v\" }: int,\n\n        outputDir {.\n          desc: \"output dir to store the generated files\"\n          abbr: \"o\" }: OutPath,\n\n        startupDelay {.\n          desc: \"delay in seconds before starting the simulation\" } = 0):\n\n  if validators \u003c 64:\n    echo \"The number of validators must be greater than EPOCH_LENGTH (64)\"\n    quit(1)\n```\n\n```nim\nimport\n  confutils\n\nproc main(foo: string, bar: int) =\n  ...\n\ndispatch(main)\n```\n\nUnder the hood, using these APIs will result in calling `load` on an anonymous\nconfiguration type having the same fields as the supplied proc params.\nAny additional arguments given as `cli(args) do ...` and `dispatch(fn, args)`\nwill be passed to `load` without modification. Please note that this requires\nall parameters types to be concrete (non-generic).\n\nThis covers the basic usage of the library and the rest of the documentation\nwill describe the various ways the default behavior can be tweaked or extended.\n\n\n## Configuration field pragmas\n\nA number of pragmas defined in `confutils/defs` can be attached to the\nconfiguration fields to control the behavior of the library.\n\n```nim\ntemplate desc*(v: string) {.pragma.}\n```\n\nA description of the configuration option that will appear in the produced\nhelp messages.\n\n```nim\ntemplate longDesc*(v: string) {.pragma.}\n```\n\nA long description text that will appear below regular desc. You can use\none of {'\\n', '\\r'} to break it into multiple lines. But you can't use\n'\\p' as line break.\n\n```text\n -x, --name   regular description [=defVal].\n              longdesc line one.\n              longdesc line two.\n              longdesc line three.\n```\n-----------------\n\n```nim\ntemplate name*(v: string) {.pragma.}\n```\n\nA long name of the option.\nTypically, it will have to be be specified as `--longOptionName value`.\nSee [Handling of command-line options](#handling-of-command-line-options)\nfor more details.\n\n-----------------\n\n```nim\ntemplate abbr*(v: string) {.pragma.}\n\n```\n\nA short name of the option.\nTypically, it will be required to be specified as `-x value`.\nSee [Handling of command-line options](#handling-of-command-line-options)\nfor more details.\n\n-----------------\n\n```nim\ntemplate defaultValue*(v: untyped) {.pragma.}\n```\n\nThe default value of the option if no value was supplied by the user.\n\n-----------------\n\n```nim\ntemplate required* {.pragma.}\n```\n\nBy default, all options without default values are considered required.\nAn exception to this rule are all `seq[T]` or `Option[T]` options for\nwhich the \"empty\" value can be considered a reasonable default. You can\nalso extend this behavior to other user-defined types by providing the\nfollowing overloads:\n\n```nim\ntemplate hasDefault*(T: type Foo): bool = true\ntemplate default*(T: type Foo): Foo = Foo(...)\n```\n\nThe `required` pragma can be applied to fields having such defaultable\ntypes to make them required.\n\n-----------------\n\n```nim\ntemplate command* {.pragma.}\n```\n\nThis must be applied to an enum field that represents a possible sub-command.\nSee the section on [sub-commands](#Using-sub-commands) for more details.\n\n-----------------\n\n```nim\ntemplate argument* {.pragma.}\n```\n\nThis field represents an argument to the program. If the program expects\nmultiple arguments, this pragma can be applied to multiple fields or to\na single `seq[T]` field depending on the desired behavior.\n\n-----------------\n\n```nim\ntemplate separator(v: string)* {.pragma.}\n```\n\nUsing this pragma, a customizable separator text will be displayed just before\nthis field. E.g.:\n\n```text\nNetwork Options:     # this is a separator\n  -a, --opt1 desc\n  -b, --opt2 desc\n\n----------------     # this is a separator too\n  -c, --opt3 desc\n```\n\n## Configuration field types\n\nThe `confutils/defs` module provides a number of types frequently used\nfor configuration purposes:\n\n#### `InputFile`, `InputDir`\n\nConfutils will validate that the file/directory exists and that it can\nbe read by the current user.\n\n#### `ConfigFilePath[Format]`\n\nA file system path pointing to a configuration file in the specific format.\nThe actual configuration can be loaded by calling `load(path, ConfigType)`.\nWhen the format is `WindowsRegistry` the path should indicate a registry key.\n\n#### `OutPath`\n\nA valid path must be given.\n\n--------------\n\nFurthermore, you can extend the behavior of the library by providing\noverloads such as:\n\n```nim\nproc parseCmdArg*(T: type Foo, p: string): T =\n  ## This provides parsing and validation for fields having the `Foo` type.\n  ## You should raise `ConfigurationError` in case of detected problems.\n  ...\n\nproc humaneTypeName*[T](_: type MyList[T]): string =\n  ## The returned string will be used in the help messages produced by the\n  ## library to describe the expected type of the configuration option.\n  mixin humaneTypeName\n  return \"list of \" \u0026 humaneTypeName(T)\n```\n\nFor config files, Confutils can work with any format supported by the\n[nim-serialization](https://github.com/status-im/nim-serialization/) library\nand it will use the standard serialization routines defined for the field\ntypes in this format. Fields marked with the `command` or `argument` pragmas\nwill be ignored.\n\n## Handling of command-line options\n\nConfutils includes parsers that can mimic several traditional styles of\ncommand line interfaces. You can select the parser being used by specifying\nthe `CmdParser` option when calling the configuration loading APIs.\n\nThe default parser of Confutils is called `MixedCmdParser`. It tries to follow\nthe [robustness principle](https://en.wikipedia.org/wiki/Robustness_principle)\nby recognizing as many styles of passing command-line switches as possible.\nA prefix of `--` is used to indicate a long option name, while the `-` prefix\nuses the short option name. Multiple short options such as `-a`, `-b` and\n`-c` can be combined into a single `-abc` string. Both the long and the short\nforms can also be prefixed with `/` in the style of Windows utilities. The\noption names are matched in case-insensitive fashion and certain characters\nsuch as `_` and `-` will be ignored. The values can be separated from the\noption names with a space, colon or an equal sign. `bool` flags default to\n`false` and merely including them in the command line sets them to `true`.\n\nOther provided choices are `UnixCmdParser`, `WindowsCmdParser` and `NimCmdParser`\nwhich are based on more strict grammars following the most established\ntradition of the respective platforms. All of the discussed parsers are\ndefined in terms of the lower-level parametric type `CustomCmdParser` that\ncan be tweaked further for a more custom behavior.\n\nPlease note that the choice of `CmdParser` will also affect the formatting\nof the help messages. Please see the definition of the standard [Windows][WIN_CMD]\nor [Posix][POSIX_CMD] command-line help syntax for mode details.\n\n[WIN_CMD]: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/command-line-syntax-key\n[POSIX_CMD]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html\n\n### Using sub-commands\n\nAs seen in the [introduction example](#introduction), Confutils makes it\neasy to create command-line interfaces featuring sub-commands in the style\nof `git` or `nimble`. The structure of the sub-command tree is encoded as\na Nim case object where the sub-command name is represented by an `enum`\nfield having the `command` pragma. Any nested fields will be considered\noptions of the particular sub-command. The top-level fields will be shared\nbetween all sub-commands.\n\nFor each available choice of command and options, Confutils will automatically\nprovide a `help` command and the following additional switches:\n\n* `-h` will print a short syntax reminder for the command\n* `--help` will print a full help message (just like the `help` command)\n\n## Handling of environment variables and config files\n\nAfter parsing the command line options, the default behavior of Confutils is\nto try to fill any missing options by examining the contents of the environment\nvariables plus two per-user and system-wide configuration locations derived from\nthe program name. If you want to use Confutils only as a command-line processor\nor a config file parser for example, you can supply an empty/nil value to the\n`cmdLine`, `envTable` or `configFileEnumerator` parameters of the `load` call.\n\nMore specifically, the `load` call supports the following parameters:\n\n#### `cmdLine`, `envTable`\n\nThe command-line parameters and the environment table of the program.\nBy default, these will be obtained through Nim's `os` module.\n\n#### `EnvValuesFormat`, `envVarsPrefix`\n\nA nim-serialization format used to deserialize the values of environment\nvariables. The default format is called `CmdLineFormat` and it uses the\nsame `parseCmdArg` calls responsible for parsing the command-line.\n\nThe names of the environment variables are prefixed by the name of the\nprogram by default and joined with the name of command line option, which is \nuppercased and characters `-` and spaces are replaced with underscore:\n\n```nim\nlet env_variable_name = \u0026\"{prefix}_{key}\".toUpperAscii.multiReplace((\"-\", \"_\"), (\" \", \"_\"))\n```\n\n#### `configFileEnumerator`\n\nA function responsible for returning a sequence of `ConfigFilePath` objects.\nTo support heterogenous config file types, you can also return a tuple of\nsequences. The default behavior of Windows is to obtain the configuration\nfrom the Windows registry by looking at the following keys:\n\n```\nHKEY_CURRENT_USER/SOFTWARE/{appVendor}/{appName}/\nHKEY_LOCAL_MACHINE/SOFTWARE/{appVendor}/{appName}/\n```\n\nOn Posix systems, the default behavior is attempt to load the configuration\nfrom the following files:\n\n```\n/$HOME/.config/{appName}.{ConfigFileFormat.extension}\n/etc/{appName}.{ConfigFileForamt.extension}\n```\n\n#### `ConfigFileFormat`\n\nA [nim-serialization](https://github.com/status-im/nim-serialization) format\nthat will be used by default by Confutils.\n\n## Customization of the help messages\n\nThe `load` call offers few more optional parameters for modifying the\nproduced help messages:\n\n#### `bannerBeforeHelp`\n\nA copyright banner or a similar message that will appear before the\nautomatically generated help messages.\n\n#### `bannerAfterHelp`\n\nA copyright banner or a similar message that will appear after the\nautomatically generated help messages.\n\n#### `version`\n\nIf you provide this parameter, Confutils will automatically respond\nto the standard `--version` switch. If sub-commands are used, an\nadditional `version` top-level command will be inserted as well.\n\n## Compile-time options\n\n#### `confutils_colors`\n\nThis option controls the use of colors appearing in the help messages\nproduced by Confutils. Possible values are:\n\n- `NativeColors` (used by default)\n\n  In this mode, Windows builds will produce output suitable for the console\n  application in older versions of Windows. On Unix-like systems, this is\n  equivalent to specifying `AnsiColors`.\n\n- `AnsiColors`\n\n  Output suitable for terminals supporting the standard ANSI escape codes:\n  https://en.wikipedia.org/wiki/ANSI_escape_code\n\n  This includes most terminal emulators on modern Unix-like systems,\n  Windows console replacements such as ConEmu, and the native Console\n  and PowerShell applications on Windows 10.\n\n- `None` or `NoColors`\n\n  All output will be colorless.\n\n## Contributing\n\nThe development of Confutils is sponsored by [Status.im](https://status.im/)\nthrough the use of [GitCoin](https://gitcoin.co/). Please take a look at our\ntracker for any issues having the [bounty][BOUNTIES] tag.\n\nWhen submitting pull requests, please add test cases for any new features\nor fixes and make sure `nimble test` is still able to execute the entire\ntest suite successfully.\n\n[BOUNTIES]: https://github.com/status-im/nim-confutils/issues?q=is%3Aissue+is%3Aopen+label%3Abounty\n\n## License\n\nLicensed and distributed under either of\n\n* MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT\n\nor\n\n* Apache License, Version 2.0, ([LICENSE-APACHEv2](LICENSE-APACHEv2) or http://www.apache.org/licenses/LICENSE-2.0)\n\nat your option. This file may not be copied, modified, or distributed except according to those terms.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstatus-im%2Fnim-confutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstatus-im%2Fnim-confutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstatus-im%2Fnim-confutils/lists"}