{"id":16834624,"url":"https://github.com/gobwas/flagutil","last_synced_at":"2025-03-22T04:30:46.389Z","repository":{"id":50855771,"uuid":"226696589","full_name":"gobwas/flagutil","owner":"gobwas","description":"Easy flags population.","archived":false,"fork":false,"pushed_at":"2021-10-05T10:49:39.000Z","size":154,"stargazers_count":34,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-18T08:11:15.427Z","etag":null,"topics":["easy","flags","go"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gobwas.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}},"created_at":"2019-12-08T16:25:45.000Z","updated_at":"2023-12-13T08:08:02.000Z","dependencies_parsed_at":"2022-09-14T05:41:33.960Z","dependency_job_id":null,"html_url":"https://github.com/gobwas/flagutil","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gobwas%2Fflagutil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gobwas%2Fflagutil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gobwas%2Fflagutil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gobwas%2Fflagutil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gobwas","download_url":"https://codeload.github.com/gobwas/flagutil/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244907420,"owners_count":20529850,"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":["easy","flags","go"],"created_at":"2024-10-13T12:07:09.921Z","updated_at":"2025-03-22T04:30:45.759Z","avatar_url":"https://github.com/gobwas.png","language":"Go","readme":"# flagutil\n\n[![GoDoc][godoc-image]][godoc-url]\n[![CI][ci-badge]][ci-url]\n\n\u003e A library to populate [`flag.FlagSet`][flagSet] from various sources.\n\n# Features\n\n- Uses standard `flag` package\n- Structured configuration\n- Reads values from multiple sources\n- Ability to write your own parser\n\n# Why\n\nDefining your program parameters and reading their values should be as simple\nas possible. There is no reason to use some library or even monstrous framework\ninstead of standard [flag][flag] package.\n\nThere is [Configuration in Go][article] article, which describes in detail the\nreasons of creating this library.\n\n# Available parsers\n\nNote that it is very easy to implement your own [Parser][parser].\n\nAt the moment these parsers are already implemented:\n- [Flag][flag-syntax] syntax arguments parser\n- [Posix][posix] program arguments syntax parser\n- Environment variables parser\n- Prompt interactive parser\n- File parsers:\n  - json\n  - yaml\n  - toml\n\n# Custom help message\n\nIt is possible to print custom help message which may include, for example,\nnames of the environment variables used by env parser. See the\n`WithCustomUsage()` parse option.\n\nCustom usage currently looks like this:\n\n```\nUsage of test:\n  $TEST_FOO, --foo\n        bool\n        bool flag description (default false)\n\n  $TEST_BAR, --bar\n        int\n        int flag description (default 42)\n```\n\n# Usage\n\nA simple example could be like this:\n\n```go\npackage main\n\nimport (\n\t\"flag\"\n\n\t\"github.com/gobwas/flagutil\"\n\t\"github.com/gobwas/flagutil/parse/pargs\"\n\t\"github.com/gobwas/flagutil/parse/file/json\"\n)\n\nfunc main() {\n\tflags := flag.NewFlagSet(\"my-app\", flag.ExitOnError)\n\t\n\tport := flag.Int(\u0026port,\n\t\t\"port\", \"port\",\n\t\t\"port to bind to\",\n\t)\n\n\t// This flag will be required by the file.Parser below.\n\t_ = flags.String(\n\t\t\"config\", \"/etc/app/config.json\", \n\t\t\"path to configuration file\",\n\t)\n\n\tflagutil.Parse(flags,\n\t\t// Use posix options syntax instead of `flag` – just to illustrate that\n\t\t// it is possible.\n\t\tflagutil.WithParser(\u0026pargs.Parser{\n\t\t\tArgs: os.Args[1:],\n\t\t}),\t\n\n\t\t// Then lookup flag values among environment.\n\t\tflagutil.WithParser(\u0026env.Parser{\n\t\t\tPrefix: \"MY_APP_\",\n\t\t}),\n\n\t\t// Finally lookup for \"config\" flag value and try to interpret its\n\t\t// value as a path to json configuration file.\n\t\tflagutil.WithParser(\n\t\t\t\u0026file.Parser{\n\t\t\t\tLookup: file.LookupFlag(flags, \"config\"),\n\t\t\t\tSyntax: new(json.Syntax),\n\t\t\t},\n\t\t\t// Don't allow to setup \"config\" flag from file.\n\t\t\tflagutil.WithStashName(\"config\"),\n\t\t),\n\t)\n\n\t// Work with received values.\n}\n```\n\n## Subsets\n\n`flagutil` provides ability to define so called flag subsets:\n\n```go\npackage main\n\nimport (\n\t\"flag\"\n\n\t\"github.com/gobwas/flagutil\"\n\t\"github.com/gobwas/flagutil/parse/pargs\"\n\t\"github.com/gobwas/flagutil/parse/file/json\"\n)\n\nfunc main() {\n\tflags := flag.NewFlagSet(\"my-app\", flag.ExitOnError)\n\t\n\tport := flag.Int(\u0026port,\n\t\t\"port\", \"port\",\n\t\t\"port to bind to\",\n\t)\n\n\t// Define parameters for some third-party library.\n\tvar endpoint string\n\tflagutil.Subset(flags, \"database\", func(sub *flag.FlagSet) {\n\t\tsub.StringVar(\u0026endpoint,\n\t\t\t\"endpoint\", \"localhost\",\n\t\t\t\"database endpoint to connect to\"\n\t\t)\n\t})\n\t\n\tflagutil.Parse(flags,\n\t\tflagutil.WithParser(\u0026pargs.Parser{\n\t\t\tArgs: os.Args[1:],\n\t\t}),\t\n\t\tflagutil.WithParser(\n\t\t\t\u0026file.Parser{\n\t\t\t\tLookup: file.PathLookup(\"/etc/my-app/config.json\"),\n\t\t\t\tSyntax: new(json.Syntax),\n\t\t\t},\n\t\t),\n\t)\n\n\t// Work with received values.\n}\n```\n\nThe configuration file may look as follows:\n\n```json\n{\n  \"port\": 4050,\n  \n  \"database\": {\n    \"endpoint\": \"localhost:5432\",\n  }\n}\n```\n\nAnd, if you want to override, say, database endpoint, you can execute your\nprogram as follows:\n\n```bash\n$ app --database.endpoint 4055\n```\n\n## Allowing name collisions\n\nIt's rare, but still possible, when you want to receive single flag value from\nmultiple places in code. To avoid panics with \"flag redefined\" reason you can\n(if you _really_ need to) _merge_ two flag values into single by using\n`flagutil.Merge()` function:\n\n```go\nvar (\n\ts0 string\n\ts1 string\n)\nflag.StringVar(\u0026s0,\n\t\"foo\", \"default\",\n\t\"foo flag usage\",\n)\nflagutil.MergeInto(flag.CommandLine, func(safe *flag.FlagSet) {\n\tsafe.StringVar(\u0026s1,\n\t\t\"foo\", \"\",\n\t\t\"foo flag another usage\", // This usage will be joined with previous.\n\t)\n})\n\n// After parsing, s0 and s1 will be filled with single `-foo` flag value.\n// If value is not provided, both s0 and s1 will have its default values (which\n// may be _different_).\n```\n\n\n# Conventions and limitations\n\nAny structure from parsed configuration is converted into a pairs of a flat key\nand a value. Keys are flattened recursively until there is no such flag defined\nwithin `flag.FlagSet`.\n\n\u003e Keys flattening happens just as two keys concatenation with `.` as a \u003e\n\u003e delimiter.\n\nThere are three scenarios when the flag was found:\n\n1) If value is a mapping or an object, then its key-value pairs are\n   concatenated with `:` as a delimiter and are passed to the `flag.Value.Set()`\n   in appropriate number of calls.\n\n2) If value is an array, then its items are passed to the `flag.Value.Set()` in\n   appropriate number of calls. \n\n3) In other way, `flag.Value.Set()` will be called once with value as is.\n\n\u003e Note that for any type of values the `flag.Value.String()` method is never\n\u003e used to access the \"real\" value – only for defaults when printing help\n\u003e message. To provide \"real\" value implementations must satisfy `flag.Getter`\n\u003e interface.\n\nSuppose you have this json configuration:\n\n```json\n{\n  \"foo\": {\n    \"bar\": \"1\",\n    \"baz\": \"2\"\n  }\n}\n```\n\nIf you define `foo.bar` flag, you will receive `\"1\"` in a single call to its\n`flag.Value.Set()` method. No surprise here. But if you define `foo` flag, then\nits `flag.Value.Set()` will be called twice with `\"bar:1\"` and `\"baz:2\"`.\n\nThe same thing happens with slices:\n\n```json\n{\n  \"foo\": [\n    \"bar\",\n    \"baz\"\n  ]\n}\n```\n\nYour `foo`'s `flag.Value.Set()` will be called twice with `\"bar\"` and `\"baz\"`.\n\nThis still allows you to use command line arguments to override or declare\nparameter complex values:\n\n```bash\n$ app --slice 1 --slice 2 --slice 3 --map foo:bar --map bar:baz\n```\n\n# Misc\n\nCreation of this library was greatly inspired by [peterburgon/ff][ff] – and I\nwouldn't write `flagutil` if I didn't met some design disagreement with it.\n\n\n[parser]:      https://godoc.org/github.com/gobwas/flagutil#Parser\n[flag]:        https://golang.org/pkg/flag\n[flagSet]:     https://golang.org/pkg/flag#FlagSet\n[flag-syntax]: https://golang.org/pkg/flag/#hdr-Command_line_flag_syntax\n[article]:     https://gbws.io/articles/configuration-in-go\n[godoc-image]: https://godoc.org/github.com/gobwas/flagutil?status.svg\n[godoc-url]:   https://godoc.org/github.com/gobwas/flagutil\n[posix]:       https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html\n[ff]:          https://github.com/peterbourgon/ff\n[ci-badge]:    https://github.com/gobwas/flagutil/workflows/CI/badge.svg\n[ci-url]:      https://github.com/gobwas/flagutil/actions?query=workflow%3ACI\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgobwas%2Fflagutil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgobwas%2Fflagutil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgobwas%2Fflagutil/lists"}