{"id":19368437,"url":"https://github.com/anchore/fangs","last_synced_at":"2025-04-23T15:30:40.442Z","repository":{"id":156650270,"uuid":"632514780","full_name":"anchore/fangs","owner":"anchore","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-02T13:56:13.000Z","size":166,"stargazers_count":6,"open_issues_count":3,"forks_count":2,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-04-02T14:49:26.882Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/anchore.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":"2023-04-25T15:06:06.000Z","updated_at":"2025-04-02T13:56:16.000Z","dependencies_parsed_at":"2023-12-01T15:27:45.137Z","dependency_job_id":"0dd6b9be-621e-458a-a814-0634da3a903f","html_url":"https://github.com/anchore/fangs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchore%2Ffangs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchore%2Ffangs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchore%2Ffangs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anchore%2Ffangs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anchore","download_url":"https://codeload.github.com/anchore/fangs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250460235,"owners_count":21434229,"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-11-10T08:06:25.929Z","updated_at":"2025-04-23T15:30:40.126Z","avatar_url":"https://github.com/anchore.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fangs\n\nA library that makes integrating Cobra and Viper simpler and more consistent.\n\n## Background\n\nAnchore Go-based CLI tools use Cobra and Viper for building the basic CLI handling\nand configuration, respectively. The use of these tools has evolved over the years\nand some patterns have emerged that seem to work better than others and avoid some\npitfalls.\n\nThis library uses some best practices we've found for integrating these tools together\nin fairly simple ways.\n\n## Usage\n\nIn order to use this library, a consumer will need to:\n* Define configuration structs\n    * By default, use `mapstructure` struct tags (can be changed in the `Config`)\n    * For embedded structs to be inline, these must use the nonstandard `,squash` option\n    * For embedded structs, the embedded type must exported if it is embedded via a pointer\n* Define Cobra commands\n* Add flags to Cobra using the `*Var*` flag variants\n* Call `config.Load` during command invocation\n\nA number of examples can be seen in the tests, but a simple example is as follows:\n\n```go\n// define configuration structs:\ntype Options struct {\n    Output string `mapstructure:\"output\"`\n    Scanning ScanningOptions `mapstructure:\"scanning\"`\n\tEmbeddedOptions `mapstructure:\",squash\"` // need to use ,squash\n}\n\ntype ScanningOptions struct {\n    Depth int `mapstructure:\"output\"`\n}\n\ntype EmbeddedOptions struct {\n\tEmbedded string `mapstructure:\"string\"`\n}\n\n// fangs needs a configuration with a minimum of an app name\ncfg := config.NewConfig(\"my-app\")\n\n// in a cobra configuration function:\nfunc makeCommand(cfg config.Config) cobra.Command {\n    // an instance of options with defaults we use to add flags and configure\n    opts := Options{\n        Output: \"default\",\n        Scanning: ScanningOptions {\n            Depth: 1,\n        },\n    }\n\n    // make a cobra command with the options you need\n    cmd := cobra.Command{\n        RunE: func(cmd *cobra.Command, args []string) error {\n            // before using opts, call config.Load with the cmd instance,\n            // after flags have been added\n            err := config.Load(cfg, cmd, \u0026opts)\n            // ...\n        },\n    }\n\n    // add flags like normal, making sure to use the *Var* variants\n    flags := cmd.Flags()\n    flags.StringVarP(\u0026opts.Output, \"output\", \"o\", opts.Output, \"output usage\")\n    flags.IntVar(\u0026opts.Scanning.Depth, \"depth\", opts.Scanning.Depth, \"depth usage\")\n    \n    return cmd\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanchore%2Ffangs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanchore%2Ffangs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanchore%2Ffangs/lists"}