{"id":13411004,"url":"https://github.com/Jagerente/gocfg","last_synced_at":"2025-03-14T16:33:30.744Z","repository":{"id":207917353,"uuid":"720268121","full_name":"Jagerente/gocfg","owner":"Jagerente","description":"⚙️ Golang config manager. Control your configurations using tags, unmarshal to structs, implement and inject your own value providers and parsers.","archived":false,"fork":false,"pushed_at":"2024-07-02T08:32:59.000Z","size":34,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-07-31T20:44:36.203Z","etag":null,"topics":["config","configuration","configuration-management","dotenv","env","environment-variables","go","golang"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/Jagerente/gocfg","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/Jagerente.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-11-18T00:58:41.000Z","updated_at":"2024-07-12T20:38:48.000Z","dependencies_parsed_at":"2024-04-10T18:53:17.034Z","dependency_job_id":null,"html_url":"https://github.com/Jagerente/gocfg","commit_stats":null,"previous_names":["jagerente/gocfg"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jagerente%2Fgocfg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jagerente%2Fgocfg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jagerente%2Fgocfg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jagerente%2Fgocfg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jagerente","download_url":"https://codeload.github.com/Jagerente/gocfg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221486919,"owners_count":16830966,"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":["config","configuration","configuration-management","dotenv","env","environment-variables","go","golang"],"created_at":"2024-07-30T20:01:10.783Z","updated_at":"2025-03-14T16:33:30.703Z","avatar_url":"https://github.com/Jagerente.png","language":"Go","funding_links":[],"categories":["Configuration","配置"],"sub_categories":["Standard CLI","标准CLI"],"readme":"[![CI](https://github.com/Jagerente/gocfg/actions/workflows/ci.yml/badge.svg)](https://github.com/Jagerente/gocfg/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/Jagerente/gocfg/workflows/CodeQL/badge.svg)](https://github.com/Jagerente/gocfg/actions?query=workflow%3ACodeQL)\n[![Go Report Card](https://goreportcard.com/badge/github.com/Jagerente/gocfg)](https://goreportcard.com/report/github.com/Jagerente/gocfg)\n[![codecov](https://codecov.io/gh/Jagerente/gocfg/graph/badge.svg?token=7M88UL4ZG4)](https://codecov.io/gh/Jagerente/gocfg)\n[![Go Reference](https://pkg.go.dev/badge/github.com/Jagerente/gocfg.svg)](https://pkg.go.dev/github.com/Jagerente/gocfg)\n\n## GoCfg\n\n## Key Features\n\n- Unmarshal from **Environment Variables**, **.env** and any other sources right to your structs.\n- Set default values for each field using tags.\n- Easy to inject as much custom parsers as you need.\n- Easy to inject your own values providers as much as you need and use them all at once with priority.\n- Automatic documentation generator.\n\n## Quick start\n\n### Install package:\n\n```bash\ngo get -u github.com/Jagerente/gocfg\n```\n\n### Basic usage:\n\nIt will use environment variables and default values defined in tags.\n\n```go\npackage main\n\nimport (\n\t\"github.com/Jagerente/gocfg\"\n\t\"github.com/Jagerente/gocfg/pkg/parsers\"\n\t\"github.com/Jagerente/gocfg/pkg/values\"\n\t\"time\"\n)\n\ntype LoggerConfig struct {\n\tLogLevel string `env:\"LOG_LEVEL\" default:\"debug\"`\n}\n\ntype RedisConfig struct {\n\tRedisHost     string `env:\"REDIS_HOST\" default:\"localhost\"`\n\tRedisPort     uint16 `env:\"REDIS_PORT\" default:\"6379\"`\n\tRedisUser     string `env:\"REDIS_USER,omitempty\"`\n\tRedisPassword string `env:\"REDIS_PASS\"`\n\tRedisDatabase string `env:\"REDIS_DATABASE\"`\n}\n\ntype AppConfig struct {\n\t// Supported Tags:\n\t// - env: Specifies the environment variable name.\n\t// - default: Specifies the default value for the field.\n\t// - omitempty: Allows empty fields. \n\t//              If both the parsed value and the default value are empty, \n\t//              the field will be set to the zero value for its type in Go.\n\n\tLogLevel          LoggerConfig\n\tRedisConfig       RedisConfig\n\tBoolField         bool          `env:\"BOOL_FIELD\"`\n\tStringField       string        `env:\"STRING_FIELD\"`\n\tIntField          int           `env:\"INT_FIELD\"`\n\tInt8Field         int8          `env:\"INT8_FIELD\"`\n\tInt16Field        int16         `env:\"INT16_FIELD\"`\n\tInt32Field        int32         `env:\"INT32_FIELD\"`\n\tInt64Field        int64         `env:\"INT64_FIELD\"`\n\tUintField         uint          `env:\"UINT_FIELD\"`\n\tUint8Field        uint8         `env:\"UINT8_FIELD\"`\n\tUint16Field       uint16        `env:\"UINT16_FIELD\"`\n\tUint32Field       uint32        `env:\"UINT32_FIELD\"`\n\tUint64Field       uint64        `env:\"UINT64_FIELD\"`\n\tFloat32Field      float32       `env:\"FLOAT32_FIELD\"`\n\tFloat64Field      float64       `env:\"FLOAT64_FIELD\"`\n\tTimeDurationField time.Duration `env:\"TIME_DURATION_FIELD\"`\n\tByteSliceField    []byte        `env:\"BYTE_SLICE_FIELD\"`\n\tStringSliceField  []string      `env:\"STRING_SLICE_FIELD\" default:\"string1,string2,string3\"`\n\tIntSliceField     []int         `env:\"INT_SLICE_FIELD\" default:\"3,2,1,0,-1,-2,-3\"`\n\tEmptyField        string        `env:\"EMPTY_FIELD,omitempty\"`\n\tWithDefaultField  string        `env:\"WITH_DEFAULT_FIELD\" default:\"ave\"`\n}\n\nfunc main() {\n\tcfg := gocfg.NewDefault()\n\n\t// Equals to\n\tcfg = gocfg.NewEmpty().\n\t\tUseDefaults().\n\t\tAddParserProviders(parsers.NewDefaultParserProvider()).\n\t\tAddValueProviders(values.NewEnvProvider())\n\n\tappConfig := new(AppConfig)\n\tif err := cfg.Unmarshal(appConfig); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n```\n\n### Default Type Parsers\n\n\u003e The following types are supported by default parsers:\n\n- time.Duration\n- bool\n- string\n- int, int8, int16, int32, int64\n- uint, uint8, uint16, uint32, uint64\n- float32, float64\n- slices: bytes, strings, ints\n\n### .env file\n\n```go\npackage main\n\nimport (\n\t\"github.com/Jagerente/gocfg\"\n\t\"github.com/Jagerente/gocfg/pkg/parsers\"\n\t\"github.com/Jagerente/gocfg/pkg/values\"\n)\n\ntype AppConfig struct {\n\tBoolField   bool   `env:\"BOOL_FIELD\"`\n\tStringField string `env:\"STRING_FIELD\"`\n\tIntField    int    `env:\"INT_FIELD\"`\n}\n\nfunc main() {\n\t// With default '.env' file\n\tdotEnvProvider, _ := values.NewDotEnvProvider()\n\n\t// With custom env file path \n\tdotEnvProvider, _ = values.NewDotEnvProvider(\"local.env\")\n\n\t// With multiple env files\n\tdotEnvProvider, _ = values.NewDotEnvProvider(\"local.env\", \"dev.env\")\n\n\tcfg := gocfg.NewDefault().\n\t\tAddValueProviders(dotEnvProvider)\n\n\t// Equals to\n\tcfg = gocfg.NewEmpty().\n\t\tUseDefaults().\n\t\tAddParserProviders(parsers.NewDefaultParserProvider()).\n\t\tAddValueProviders(\n\t\t\tvalues.NewEnvProvider(),\n\t\t\tdotEnvProvider,\n\t\t)\n\n\tappConfig := new(AppConfig)\n\tif err := cfg.Unmarshal(appConfig); err != nil {\n\t\tpanic(err)\n\t}\n}\n```\n\n### Custom key tag\n\n```go\npackage main\n\nimport (\n\t\"github.com/Jagerente/gocfg\"\n)\n\ntype AppConfig struct {\n\tBoolField   bool   `mapstructure:\"BOOL_FIELD\"`\n\tStringField string `mapstructure:\"STRING_FIELD\"`\n\tIntField    int    `mapstructure:\"INT_FIELD\"`\n}\n\nfunc main() {\n\tcfg := gocfg.NewDefault().\n\t\tUseCustomKeyTag(\"mapstructure\")\n\n\tappConfig := new(AppConfig)\n\tif err := cfg.Unmarshal(appConfig); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n```\n\n### Custom parser provider\n\n```go \npackage main\n\nimport (\n\t\"github.com/Jagerente/gocfg\"\n\t\"reflect\"\n\t\"time\"\n)\n\ntype CustomParserProvider struct {\n}\n\nfunc NewCustomParserProvider() *CustomParserProvider {\n\treturn \u0026CustomParserProvider{}\n}\n\nfunc (p *CustomParserProvider) Get(field reflect.Value) (func(v string) (any, error), bool) {\n\tswitch field.Type() {\n\tcase reflect.TypeOf(time.Duration(83)):\n\t\treturn func(v string) (any, error) {\n\t\t\treturn time.ParseDuration(v)\n\t\t}, true\n\tdefault:\n\t\treturn nil, false\n\t}\n}\n\ntype AppConfig struct {\n\tBoolField   bool   `env:\"BOOL_FIELD\"`\n\tStringField string `env:\"STRING_FIELD\"`\n\tIntField    int    `env:\"INT_FIELD\"`\n}\n\nfunc main() {\n\tcustomParserProvider := NewCustomParserProvider()\n\n\tcfg := gocfg.NewDefault().\n\t\tAddParserProviders(customParserProvider)\n\n\tappConfig := new(AppConfig)\n\tif err := cfg.Unmarshal(appConfig); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n```\n\n### Custom value provider\n\n```go \npackage main\n\nimport (\n\t\"github.com/Jagerente/gocfg\"\n\t\"os\"\n)\n\ntype CustomValueProvider struct {\n}\n\nfunc NewCustomValueProvider() *CustomValueProvider {\n\treturn \u0026CustomValueProvider{}\n}\n\nfunc (p *CustomValueProvider) Get(key string) string {\n\treturn os.Getenv(\"CUSTOM_\" + key)\n}\n\ntype AppConfig struct {\n\tBoolField   bool   `env:\"BOOL_FIELD\"`\n\tStringField string `env:\"STRING_FIELD\"`\n\tIntField    int    `env:\"INT_FIELD\"`\n}\n\nfunc main() {\n\tcustomValueProvider := NewCustomValueProvider()\n\n\tcfg := gocfg.NewDefault().\n\t\tAddValueProviders(customValueProvider)\n\n\tappConfig := new(AppConfig)\n\tif err := cfg.Unmarshal(appConfig); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n```\n\n### Documentation generation\n\n1. Let's say you have such config file `/internal/config/config.go`:\n\n```go\npackage config\n\nimport (\n\t\"github.com/Jagerente/gocfg\"\n\t\"github.com/Jagerente/gocfg/pkg/values\"\n\t\"time\"\n\tcache_factory \"your_cool_app/internal/router/cache\"\n)\n\ntype LoggerConfig struct {\n\tLogLevel     int  `env:\"LOG_LEVEL\" default:\"6\" description:\"https://pkg.go.dev/github.com/sirupsen/logrus@v1.9.3#Level\"`\n\tReportCaller bool `env:\"REPORT_CALLER\" default:\"true\"`\n\tLogFormatter int  `env:\"LOG_FORMATTER\" default:\"0\"`\n}\n\ntype CassandraConfig struct {\n\tCassandraHosts    string `env:\"CASSANDRA_HOSTS\" default:\"127.0.0.1\"`\n\tCassandraKeyspace string `env:\"CASSANDRA_KEYSPACE\" default:\"user_data_service\"`\n}\n\ntype RouterConfig struct {\n\tServerPort               uint16        `env:\"SERVER_PORT\" default:\"8080\"`\n\tDebug                    bool          `env:\"ROUTER_DEBUG\" default:\"true\"`\n\tCacheAdapter             string        `env:\"CACHE_ADAPTER,omitempty\" description:\"Leave blank to not use.\\nPossible values:\\n- redis\\n- memcache\"`\n\tCacheAdapterTTL          time.Duration `env:\"CACHE_ADAPTER_TTL,omitempty\" default:\"1m\"`\n\tCacheAdapterNoCacheParam string        `env:\"CACHE_ADAPTER_NOCACHE_PARAM,omitempty\" default:\"no-cache\"`\n}\n\ntype RedisCacheAdapterConfig struct {\n\tRedisAddr     string `env:\"CACHE_ADAPTER_REDIS_ADDR,omitempty\" default:\":6379\"`\n\tRedisDB       int    `env:\"CACHE_ADAPTER_REDIS_DB,omitempty\" default:\"0\"`\n\tRedisUsername string `env:\"CACHE_ADAPTER_REDIS_USERNAME,omitempty\"`\n\tRedisPassword string `env:\"CACHE_ADAPTER_REDIS_PASSWORD,omitempty\"`\n}\n\ntype MemcacheCacheAdapterConfig struct {\n\tCapacity         int                     `env:\"CACHE_ADAPTER_MEMCACHE_CAPACITY,omitempty\" default:\"10000000\"`\n\tCachingAlgorithm cache_factory.Algorithm `env:\"CACHE_ADAPTER_MEMCACHE_CACHING_ALGORITHM,omitempty\" default:\"LRU\"`\n}\ntype Config struct {\n\tLoggerConfig               `title:\"Logger configuration\"`\n\tRouterConfig               `title:\"Router configuration\"`\n\tRedisCacheAdapterConfig    `title:\"Redis Cache Adapter configuration\"`\n\tMemcacheCacheAdapterConfig `title:\"Memcache Cache Adapter configuration\"`\n\tCassandraConfig            `title:\"Cassandra configuration\"`\n}\n\nfunc New() (*Config, error) {\n\tvar cfg = new(Config)\n\n\tcfgManager := gocfg.NewDefault()\n\tif dotEnvProvider, err := values.NewDotEnvProvider(); err == nil {\n\t\tcfgManager = cfgManager.AddValueProviders(dotEnvProvider)\n\t}\n\n\tif err := cfgManager.Unmarshal(cfg); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn cfg, nil\n}\n\n```\n\n2. Create new app, for example `/cmd/docs/main.go`:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/Jagerente/gocfg\"\n\t\"github.com/Jagerente/gocfg/pkg/docgens\"\n\t\"os\"\n\t\"your_cool_app/internal/config\"\n)\n\nconst outputFile = \".env.dist.generated\"\n\nfunc main() {\n\tcfg := new(config.Config)\n\n\tfile, err := os.Create(outputFile)\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"error creating %s file: %v\", outputFile, err))\n\t}\n\n\tcfgManager := gocfg.NewDefault()\n\tif err := cfgManager.GenerateDocumentation(cfg, docgens.NewEnvDocGenerator(file)); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n```\n\n3. Run it by executing `go run cmd/docs/main.go`; it will generate the following file `.env.dist.generated`:\n\n```go\n# Auto-generated config\n\n#############################\n# Logger configuration\n#############################\n\n# Description:\n#  https://pkg.go.dev/github.com/sirupsen/logrus@v1.9.3#Level\nLOG_LEVEL=6\n\nREPORT_CALLER=true\n\nLOG_FORMATTER=0\n\n#############################\n# Router configuration\n#############################\n\nSERVER_PORT=8080\n\nROUTER_DEBUG=true\n\n# Allowed to be empty\n# Description:\n#  Leave blank to not use.\n#  Possible values:\n#  - redis\n#  - memcache\nCACHE_ADAPTER=\n\n# Allowed to be empty\nCACHE_ADAPTER_TTL=1m\n\n# Allowed to be empty\nCACHE_ADAPTER_NOCACHE_PARAM=no-cache\n\n#############################\n# Redis Cache Adapter configuration\n#############################\n\n# Allowed to be empty\nCACHE_ADAPTER_REDIS_ADDR=:6379\n\n# Allowed to be empty\nCACHE_ADAPTER_REDIS_DB=0\n\n# Allowed to be empty\nCACHE_ADAPTER_REDIS_USERNAME=\n\n# Allowed to be empty\nCACHE_ADAPTER_REDIS_PASSWORD=\n\n#############################\n# Memcache Cache Adapter configuration\n#############################\n\n# Allowed to be empty\nCACHE_ADAPTER_MEMCACHE_CAPACITY=10000000\n\n# Allowed to be empty\nCACHE_ADAPTER_MEMCACHE_CACHING_ALGORITHM=LRU\n\n#############################\n# Cassandra configuration\n#############################\n\nCASSANDRA_HOSTS=127.0.0.1\n\nCASSANDRA_KEYSPACE=user_data_service\n\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJagerente%2Fgocfg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJagerente%2Fgocfg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJagerente%2Fgocfg/lists"}