{"id":37169366,"url":"https://github.com/moshenahmias/funcv","last_synced_at":"2026-01-14T19:59:56.877Z","repository":{"id":57549705,"uuid":"267865311","full_name":"moshenahmias/funcv","owner":"moshenahmias","description":"Command-Line parser for Go","archived":false,"fork":false,"pushed_at":"2020-06-05T10:02:30.000Z","size":54,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-06-20T05:23:28.724Z","etag":null,"topics":["argument-parser","arguments","cli","cli-app","command-line","command-line-parser","flags","go","golang","parser","tool"],"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/moshenahmias.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":"2020-05-29T13:31:19.000Z","updated_at":"2020-06-05T10:02:33.000Z","dependencies_parsed_at":"2022-09-01T06:40:25.477Z","dependency_job_id":null,"html_url":"https://github.com/moshenahmias/funcv","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/moshenahmias/funcv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moshenahmias%2Ffuncv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moshenahmias%2Ffuncv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moshenahmias%2Ffuncv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moshenahmias%2Ffuncv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moshenahmias","download_url":"https://codeload.github.com/moshenahmias/funcv/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moshenahmias%2Ffuncv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28434076,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T18:57:19.464Z","status":"ssl_error","status_checked_at":"2026-01-14T18:52:48.501Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["argument-parser","arguments","cli","cli-app","command-line","command-line-parser","flags","go","golang","parser","tool"],"created_at":"2026-01-14T19:59:56.211Z","updated_at":"2026-01-14T19:59:56.870Z","avatar_url":"https://github.com/moshenahmias.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# funcv [![GoDoc](https://godoc.org/moshenahmias/funcv?status.svg)](https://godoc.org/github.com/moshenahmias/funcv)\n\n**funcv** helps you create CLI tools with Go.\n\n**funcv** offers a different approach for dealing with command line arguments and flags.\n\n**funcv** supplies an easy to use command builder, you use that builder to build your set of commands, each such command can be tested against a slice of string arguments, if the arguments are compatible with the command, a given action function is called, the parameters for that function are the extracted and parsed variables and flags.\n\nLet's see how it works with a simple example:\n\n```go\nfunc main() {\n\tcmd := funcv.NewCommand(\"delete a file\").\n\t\tAddConstant(\"delete\", false).\n\t\tAddVariable(\"filename\", \"file to delete\", new(funcv.StringConverter)).\n\t\tMustCompile()\n\n\tif _, err := cmd.Execute(os.Args[1:], func(name string) {\n\t\tfmt.Println(\"deleting\", name, \"...\")\n\t\t// ...\n\t}); err != nil {\n\t\tfmt.Fprintln(os.Stderr, \"invalid command:\", strings.Join(os.Args[1:], \" \"))\n\t}\n}\n```\n\n```console\n$ example delete song.mp3\ndeleting song.mp3 ...\n```\n\n\nFirst, we called the `funcv.NewCommand` function with a command description, then, we used the returned builder (`funcv.Builder`) to add our command components, a constant text (\"delete\") and a string variable (\"filename\"). The call for `MustCompile()` finished the building process and returned the new command (`failure.Command`).\n\nNext, we called the command's `Execute`  method with a slice of string arguments (`os.Args[1:]`) and an action function (`func(name string){...}`).\n\nThe `Execute` method tests the given arguments slice (`[]string{\"delete\", \"song.mp3\"}`)  and finds that it contains two arguments, the first argument equals \"delete\", therefore, the action function is called with the second argument as a parameter (`name string`).\n\n\n\n### Arguments\n\nCurrently supported list of arguments:\n\n|          | Comment                                                |\n| -------- | ------------------------------------------------------ |\n| Constant | Static word (allowed characters: 0-9, A-Z, a-z, _, -). |\n| Variable | With default value or without.                         |\n| Flag     | -x or -x..x, with parameter or without.                |\n| Variadic | Closing the list of arguments.                         |\n\nThe list of supported arguments is extendable via the `funcv.Argument` interface.\n\n\n\n### Converters\n\nArguments that translates to function parameters (ex: not constant) require a `func.Converter`.\n\nThe package includes converters for Strings, Integers, Floats and Booleans.\n\n### Groups\n\nIt is possible to group different commands together using a `funcv.Group`:\n\n```go\nfunc main() {\n\tvar grp funcv.Group\n\n\terr := funcv.NewCommand(\"delete a file\").\n\t\tAddConstant(\"example\", false).\n\t\tAddConstant(\"delete\", false).\n\t\tAddParameterlessFlag(\"r\", \"move to recycle bin\", new(funcv.BooleanConverter), false, true).\n\t\tAddVariable(\"filename\", \"file to delete\", new(funcv.StringConverter)).\n\t\tToGroup(\u0026grp, func(recycle bool, name string) {\n\t\t\t// the count, order and type of params must match the count, order\n\t\t\t// and type of flags and variables in the command (excluding constants)\t\n\t\t\tif recycle {\n\t\t\t\tfmt.Println(\"recycling\", name, \"...\")\n\t\t\t} else {\n\t\t\t\tfmt.Println(\"deleting\", name, \"...\")\n\t\t\t}\n\t\t\t// ...\n\t\t})\n\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = funcv.NewCommand(\"print this help\").\n\t\tAddConstant(\"example\", false).\n\t\tAddConstant(\"help\", false).\n\t\tToGroup(\u0026grp, func() {\n\t\t\t// groups, commands and arguments implement io.WriterTo\n\t\t\t// and will write their informative usage text into the\n\t\t\t// writer given to WriteTo(io.Writer)\n\t\t\tw := new(tabwriter.Writer)\n\t\t\tw.Init(os.Stdout, 18, 8, 0, '\\t', 0)\n\t\t\tdefer w.Flush()\n\t\t\tif _, err := grp.WriteTo(w); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t})\n\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// test against all commands in grp\n\t// returns the number of executed commands\n\tif grp.ExecuteAll(append([]string{\"example\"}, os.Args[1:]...)) == 0 {\n\t\tfmt.Fprintln(os.Stderr, \"invalid command:\", strings.Join(os.Args[1:], \" \"))\n\t}\n}\n```\n\n```console\n$ example delete song.mp3 \ndeleting song.mp3 ...\n\n$ example delete -r song.mp3 \nrecycling song.mp3 ...\n\n$ example delete -r false song.mp3 \ndeleting song.mp3 ...\n\n$ example delete -r true song.mp3 \nrecycling song.mp3 ...\n\n$ example help\ndelete a file:          \u003e example delete [-r] \u003cfilename\u003e\n\n                        -r                      move to recycle bin (default: false)\n                        filename                file to delete\n\nprint this help:        \u003e example help\n\n$ example typo\ninvalid command: typo\n```\n\n\n\n### Variadic Functions\n\nVariadic action functions support is available. Example:  \n\n```go\nfunc main() {\n\tvar grp funcv.Group\n\n   \tconverter := new(funcv.IntegerConverter)\n    \n\tif err := funcv.NewCommand(\"add two numbers\").\n\t\tAddConstant(\"calc\", false).\n\t\tAddConstant(\"add\", false).\n\t\tAddVariable(\"1st\", \"first operand\", converter).\n\t\tAddVariable(\"2nd\", \"second operand\", converter).\n\t\tToGroup(\u0026grp, func(x, y int) {\n\t\t\tfmt.Println(x, \"+\", y, \"=\", x+y, \"(I)\")\n\t\t}); err != nil {\n\t\tpanic(err)\n\t}\n\n\tif err := funcv.NewCommand(\"add two or more numbers\").\n\t\tAddConstant(\"calc\", false).\n\t\tAddConstant(\"add\", false).\n\t\tAddVariable(\"1st\", \"first operand\", converter).\n\t\tAddVariable(\"2nd\", \"second operand\", converter).\n\t\tAddVariadic(\"operands\", \"list of operands\", converter).\n\t\tToGroup(\u0026grp, func(operands ...int) {\n\t\t\tvar sb strings.Builder\n\t\t\tvar sum int\n\n\t\t\tfor i, op := range operands {\n\t\t\t\tsum += op\n\t\t\t\tsb.WriteString(fmt.Sprint(op))\n\n\t\t\t\tif i+1 \u003c len(operands) {\n\t\t\t\t\tsb.WriteString(\" + \")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsb.WriteString(fmt.Sprintf(\" = %d (II)\", sum))\n\t\t\tfmt.Println(sb.String())\n\n\t\t}); err != nil {\n\t\tpanic(err)\n\t}\n\n\tif grp.ExecuteAll(append([]string{\"calc\"}, os.Args[1:]...)) == 0 {\n\t\tfmt.Fprintln(os.Stderr, \"invalid command:\", strings.Join(os.Args[1:], \" \"))\n\t}\n}\n```\n\n```console\n$ calc add 1\ninvalid command: add 1\n\n$ calc add 1 2\n1 + 2 = 3 (I)\n1 + 2 = 3 (II)\n\n$ calc add 1 2 3\n1 + 2 + 3 = 6 (II)\n```\n\nUse `ExecuteFirst` if you want to stop executing commands after the first successful executed command, the method returns the index of the executed command within the group, [0, `len(group)`), or a negative value if no command was found: \n\n```go\nfunc main() {\n\t// ... same commands as before ...\n\n\tif grp.ExecuteFirst(append([]string{\"calc\"}, os.Args[1:]...)) \u003c 0 {\n\t\tfmt.Fprintln(os.Stderr, \"invalid command:\", strings.Join(os.Args[1:], \" \"))\n\t}\n}\n```\n\n```console\n$ calc add 1 2\n1 + 2 = 3 (I)\n```\n\n\n\n### Action Function Returned Error\n\nIf an action function returns an error (non-nil), that error will propagate through the command's `Execute` method:\n\n```go\nfunc main() {\n\tvar grp funcv.Group\n\n\tif err := funcv.NewCommand(\"...\").\n\t\tAddConstant(\"run\", false).\n\t\tAddConstant(\"me\", false).\n\t\tToGroup(\u0026grp, func() error {\n\t\t\tfmt.Println(\"1nd command\")\n\t\t\treturn errors.New(\"...\")\n\t\t}); err != nil {\n\t\tpanic(err)\n\t}\n\n\tif err := funcv.NewCommand(\"...\").\n\t\tAddConstant(\"run\", false).\n\t\tAddConstant(\"me\", false).\n\t\tToGroup(\u0026grp, func() {\n\t\t\tfmt.Println(\"2nd command\")\n\t\t}); err != nil {\n\t\tpanic(err)\n\t}\n\n\tif grp.ExecuteFirst(append([]string{\"run\"}, os.Args[1:]...)) \u003c 0 {\n\t\tfmt.Fprintln(os.Stderr, \"invalid command:\", strings.Join(os.Args[1:], \" \"))\n\t}\n}\n```\n\n```console\n$ run me\n1nd command\n2nd command\n```\n\n`ExecuteFirst` stops after the first successful command, if an action function returns an error, the execution is considered to be unsuccessful.\n\n\n\n### Download\n\n```console\n$ go get -u github.com/moshenahmias/funcv\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoshenahmias%2Ffuncv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoshenahmias%2Ffuncv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoshenahmias%2Ffuncv/lists"}