{"id":16754633,"url":"https://github.com/audriusbutkevicius/recli","last_synced_at":"2025-03-21T22:32:17.819Z","repository":{"id":57479847,"uuid":"167607302","full_name":"AudriusButkevicius/recli","owner":"AudriusButkevicius","description":"Reflection based CLI (command line interface) generator for Golang","archived":false,"fork":false,"pushed_at":"2024-08-04T21:19:50.000Z","size":25,"stargazers_count":5,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-18T05:51:18.343Z","etag":null,"topics":["cli","command-line","generator","go","golang","reflection"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AudriusButkevicius.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}},"created_at":"2019-01-25T20:11:59.000Z","updated_at":"2022-09-11T12:19:36.000Z","dependencies_parsed_at":"2024-10-28T11:39:04.300Z","dependency_job_id":"7a74b951-6bf3-49b7-8e57-4afad3a34154","html_url":"https://github.com/AudriusButkevicius/recli","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AudriusButkevicius%2Frecli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AudriusButkevicius%2Frecli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AudriusButkevicius%2Frecli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AudriusButkevicius%2Frecli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AudriusButkevicius","download_url":"https://codeload.github.com/AudriusButkevicius/recli/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244880448,"owners_count":20525507,"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":["cli","command-line","generator","go","golang","reflection"],"created_at":"2024-10-13T03:05:28.077Z","updated_at":"2025-03-21T22:32:17.381Z","avatar_url":"https://github.com/AudriusButkevicius.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"recli - Reflection based CLI (command line interface) generator for Golang\r\n--------------------------------------------------------------------------\r\n\r\n[![GoDoc](https://godoc.org/github.com/AudriusButkevicius/recli?status.svg)](https://godoc.org/github.com/AudriusButkevicius/recli)\r\n\r\nFor a given struct, builds a set of [urfave/cli](https://github.com/urfave/cli) commands which allows you\r\nto modify it from the command line.\r\n\r\nUseful for generating command line clients for your application configuration that is stored in a Go struct.\r\n\r\n## Features\r\n\r\n* Nested struct support\r\n* Enum/Custom complex type support via MarshalText/UnmarshalText\r\n* Slice support, including complex types\r\n* Slice indexing by struct field\r\n* Map support\r\n* Default primitive value support when adding items to slices\r\n\r\n## Known limitations\r\n\r\n* Adding new struct to a slice only allows setting primitive fields (use add-json as a work-around)\r\n* Only primitive types supported for map keys and values\r\n* No defaults for maps\r\n\r\n\r\n## Examples\r\n\r\nExample config\r\n\r\n```go\r\ntype Config struct {\r\n\tAddress          string `usage:\"Address on which to listen\"` // Description printed in -help\r\n\tAuthMode         AuthMode                                    // Enum support\r\n\tThreadingOptions ThreadingOptions                            // Nested struct support\r\n\tBackends         []Backend                                   // Slice support\r\n\tEnvVars          map[string]string                           // Map support\r\n}\r\n\r\ntype Backend struct {\r\n\tHostname         string `recli:\"id\"`         // Constructs commands for indexing into the array based on the value of this field\r\n\tPort             int    `default:\"2019\"`     // Default support\r\n\tBackoffIntervals []int  `default:\"10,20\"`    // Slice default support\r\n\tIPAddressCached  net.IP `recli:\"-\" json:\"-\"` // Skips the field\r\n}\r\n\r\ntype ThreadingOptions struct {\r\n\tMaxThreads int\r\n}\r\n```\r\n\r\nSample input data\r\n```json\r\n{\r\n   \"Address\":\"http://website.com\",\r\n   \"AuthMode\":\"static\",\r\n   \"ThreadingOptions\":{\r\n      \"MaxThreads\":10\r\n   },\r\n   \"Backends\":[\r\n      {\r\n         \"Hostname\":\"backend1.com\",\r\n         \"Port\":1010\r\n      },\r\n      {\r\n         \"Hostname\":\"backend2.com\",\r\n         \"Port\":2020\r\n      }\r\n   ],\r\n   \"EnvVars\":{\r\n      \"CC\":\"/usr/bin/gcc\"\r\n   }\r\n}\r\n```\r\n\r\n\u003cdetails\u003e\r\n \u003csummary\u003eFull example code\u003c/summary\u003e\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"encoding/json\"\r\n\t\"fmt\"\r\n\t\"net\"\r\n\t\"os\"\r\n\r\n\t\"github.com/AudriusButkevicius/recli\"\r\n\t\"github.com/urfave/cli\"\r\n)\r\n\r\ntype Config struct {\r\n\tAddress          string `usage:\"Address on which to listen\"` // Description printed in -help\r\n\tAuthMode         AuthMode                                    // Enum support\r\n\tThreadingOptions ThreadingOptions                            // Nested struct support\r\n\tBackends         []Backend                                   // Slice support\r\n\tEnvVars          map[string]string                           // Map support\r\n}\r\n\r\ntype Backend struct {\r\n\tHostname         string `recli:\"id\"`         // Constructs commands for indexing into the array based on the value of this field\r\n\tPort             int    `default:\"2019\"`     // Default support\r\n\tBackoffIntervals []int  `default:\"10,20\"`    // Slice default support\r\n\tIPAddressCached  net.IP `recli:\"-\" json:\"-\"` // Skips the field\r\n}\r\n\r\ntype ThreadingOptions struct {\r\n\tMaxThreads int\r\n}\r\n\r\ntype AuthMode int\r\n\r\nconst (\r\n\tAuthModeStatic AuthMode = iota // default is static\r\n\tAuthModeLDAP\r\n)\r\n\r\nfunc (t AuthMode) MarshalText() ([]byte, error) {\r\n\tswitch t {\r\n\tcase AuthModeStatic:\r\n\t\treturn []byte(\"static\"), nil\r\n\tcase AuthModeLDAP:\r\n\t\treturn []byte(\"ldap\"), nil\r\n\t}\r\n\treturn nil, fmt.Errorf(\"unknown value: %s\", t)\r\n}\r\n\r\nfunc (t *AuthMode) UnmarshalText(bs []byte) error {\r\n\tswitch string(bs) {\r\n\tcase \"ldap\":\r\n\t\t*t = AuthModeLDAP\r\n\tcase \"static\":\r\n\t\t*t = AuthModeStatic\r\n\tdefault:\r\n\t\treturn fmt.Errorf(\"unknown value: %s\", string(bs))\r\n\t}\r\n\treturn nil\r\n}\r\n\r\nconst (\r\n\tsampleData = `\r\n{\r\n   \"Address\":\"http://website.com\",\r\n   \"AuthMode\":\"static\",\r\n   \"ThreadingOptions\":{\r\n      \"MaxThreads\":10\r\n   },\r\n   \"Backends\":[\r\n      {\r\n         \"Hostname\":\"backend1.com\",\r\n         \"Port\":1010\r\n      },\r\n      {\r\n         \"Hostname\":\"backend2.com\",\r\n         \"Port\":2020\r\n      }\r\n   ],\r\n   \"EnvVars\":{\r\n      \"CC\":\"/usr/bin/gcc\"\r\n   }\r\n}`\r\n)\r\n\r\nfunc main() {\r\n\tcfg := \u0026Config{}\r\n\r\n\tif err := json.Unmarshal([]byte(sampleData), cfg); err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n\r\n\tcmds, err := recli.Default.Construct(cfg)\r\n\tif err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n\r\n\tdump := false\r\n\r\n\tapp := cli.NewApp()\r\n\tapp.Commands = cmds\r\n\tapp.Flags = []cli.Flag{\r\n\t\tcli.BoolFlag{\r\n\t\t\tName:        \"dump\",\r\n\t\t\tDestination: \u0026dump,\r\n\t\t},\r\n\t}\r\n\r\n\tif err := app.Run(os.Args); err != nil {\r\n\t\tpanic(err)\r\n\t}\r\n\r\n\tif dump {\r\n\t\tbs, err := json.MarshalIndent(\u0026cfg, \"\", \"    \")\r\n\t\tif err != nil {\r\n\t\t\tpanic(err)\r\n\t\t}\r\n\r\n\t\tfmt.Print(string(bs))\r\n\t}\r\n}\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n \u003csummary\u003eGet a field\u003c/summary\u003e\r\n\r\n```bash\r\n$ go run main.go address get\r\nhttp://website.com\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n \u003csummary\u003eSet a field\u003c/summary\u003e\r\n\r\n```bash\r\n$ go run main.go -dump address set foo\r\n{\r\n    \"Address\": \"foo\",\r\n    \"AuthMode\": \"static\",\r\n    \"ThreadingOptions\": {\r\n        \"MaxThreads\": 10\r\n    },\r\n    \"Backends\": [\r\n        {\r\n            \"Hostname\": \"backend1.com\",\r\n            \"Port\": 1010,\r\n            \"BackoffIntervals\": null\r\n        },\r\n        {\r\n            \"Hostname\": \"backend2.com\",\r\n            \"Port\": 2020,\r\n            \"BackoffIntervals\": null\r\n        }\r\n    ],\r\n    \"EnvVars\": {\r\n        \"CC\": \"/usr/bin/gcc\"\r\n    }\r\n}\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n \u003csummary\u003eSet a nested field\u003c/summary\u003e\r\n\r\n```bash\r\n$ go run main.go -dump threading-options max-threads set 9000\r\n{\r\n    \"Address\": \"http://website.com\",\r\n    \"AuthMode\": \"static\",\r\n    \"ThreadingOptions\": {\r\n        \"MaxThreads\": 9000\r\n    },\r\n    \"Backends\": [\r\n        {\r\n            \"Hostname\": \"backend1.com\",\r\n            \"Port\": 1010,\r\n            \"BackoffIntervals\": null\r\n        },\r\n        {\r\n            \"Hostname\": \"backend2.com\",\r\n            \"Port\": 2020,\r\n            \"BackoffIntervals\": null\r\n        }\r\n    ],\r\n    \"EnvVars\": {\r\n        \"CC\": \"/usr/bin/gcc\"\r\n    }\r\n}\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n \u003csummary\u003eListing available slice items (with a custom slice index key)\u003c/summary\u003e\r\n\r\n```bash\r\n$ go run main.go backends\r\nNAME:\r\n   main.exe backends -\r\n\r\nUSAGE:\r\n   main.exe backends command [command options] [arguments...]\r\n\r\nCOMMANDS:\r\n  ACTIONS:\r\n     add           Add a new item to collection\r\n     add-json      Add a new item to collection deserialised from JSON\r\n\r\n  ITEMS:\r\n     backend1.com\r\n     backend2.com\r\n     \r\nOPTIONS:\r\n   --help, -h  show help\r\n\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n \u003csummary\u003eDeleting a slice item\u003c/summary\u003e\r\n\r\n```bash\r\n$ go run main.go -dump backends backend1.com delete\r\n{\r\n    \"Address\": \"http://website.com\",\r\n    \"AuthMode\": \"static\",\r\n    \"ThreadingOptions\": {\r\n        \"MaxThreads\": 10\r\n    },\r\n    \"Backends\": [\r\n        {\r\n            \"Hostname\": \"backend2.com\",\r\n            \"Port\": 2020,\r\n            \"BackoffIntervals\": null\r\n        }\r\n    ],\r\n    \"EnvVars\": {\r\n        \"CC\": \"/usr/bin/gcc\"\r\n    }\r\n}\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n \u003csummary\u003eAdding a slice item (with defaults)\u003c/summary\u003e\r\n\r\n```bash\r\n$ go run main.go -dump backends add -hostname=\"testback.end\"\r\n{\r\n    \"Address\": \"http://website.com\",\r\n    \"AuthMode\": \"static\",\r\n    \"ThreadingOptions\": {\r\n        \"MaxThreads\": 10\r\n    },\r\n    \"Backends\": [\r\n        {\r\n            \"Hostname\": \"backend1.com\",\r\n            \"Port\": 1010,\r\n            \"BackoffIntervals\": null\r\n        },\r\n        {\r\n            \"Hostname\": \"backend2.com\",\r\n            \"Port\": 2020,\r\n            \"BackoffIntervals\": null\r\n        },\r\n        {\r\n            \"Hostname\": \"testback.end\",\r\n            \"Port\": 2019,\r\n            \"BackoffIntervals\": [\r\n                10,\r\n                20\r\n            ]\r\n        }\r\n    ],\r\n    \"EnvVars\": {\r\n        \"CC\": \"/usr/bin/gcc\"\r\n    }\r\n}\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n \u003csummary\u003eSetting map keys\u003c/summary\u003e\r\n\r\n```bash\r\n$ go run main.go -dump env-vars set GCC /usr/bin/true\r\n{\r\n    \"Address\": \"http://website.com\",\r\n    \"AuthMode\": \"static\",\r\n    \"ThreadingOptions\": {\r\n        \"MaxThreads\": 10\r\n    },\r\n    \"Backends\": [\r\n        {\r\n            \"Hostname\": \"backend1.com\",\r\n            \"Port\": 1010,\r\n            \"BackoffIntervals\": null\r\n        },\r\n        {\r\n            \"Hostname\": \"backend2.com\",\r\n            \"Port\": 2020,\r\n            \"BackoffIntervals\": null\r\n        }\r\n    ],\r\n    \"EnvVars\": {\r\n        \"CC\": \"/usr/bin/gcc\",\r\n        \"GCC\": \"/usr/bin/true\"\r\n    }\r\n}\r\n```\r\n\u003c/details\u003e\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faudriusbutkevicius%2Frecli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faudriusbutkevicius%2Frecli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faudriusbutkevicius%2Frecli/lists"}