{"id":21352410,"url":"https://github.com/sandwich-go/xconf","last_synced_at":"2025-10-09T12:43:40.562Z","repository":{"id":43634963,"uuid":"444300290","full_name":"sandwich-go/xconf","owner":"sandwich-go","description":"Dead simple yet complete and powerful configuration manager for Go.","archived":false,"fork":false,"pushed_at":"2025-06-18T02:43:53.000Z","size":532,"stargazers_count":24,"open_issues_count":5,"forks_count":2,"subscribers_count":2,"default_branch":"0.3/release","last_synced_at":"2025-07-12T21:36:25.002Z","etag":null,"topics":["cmdline","config","environment-variables","etcdv3","flags","flagset","go","goconf","hot-reload","json","merge","toml","yaml"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sandwich-go.png","metadata":{"files":{"readme":"README-en.md","changelog":"CHANGELOG-0.2.md","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,"zenodo":null}},"created_at":"2022-01-04T05:44:03.000Z","updated_at":"2025-07-08T07:49:33.000Z","dependencies_parsed_at":"2024-06-19T01:39:34.350Z","dependency_job_id":"a1b74300-d5c3-4365-b181-722744b3216b","html_url":"https://github.com/sandwich-go/xconf","commit_stats":null,"previous_names":[],"tags_count":53,"template":false,"template_full_name":null,"purl":"pkg:github/sandwich-go/xconf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandwich-go%2Fxconf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandwich-go%2Fxconf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandwich-go%2Fxconf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandwich-go%2Fxconf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sandwich-go","download_url":"https://codeload.github.com/sandwich-go/xconf/tar.gz/refs/heads/0.3/release","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandwich-go%2Fxconf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001435,"owners_count":26083078,"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","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["cmdline","config","environment-variables","etcdv3","flags","flagset","go","goconf","hot-reload","json","merge","toml","yaml"],"created_at":"2024-11-22T03:13:34.985Z","updated_at":"2025-10-09T12:43:40.529Z","avatar_url":"https://github.com/sandwich-go.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# XCONF\n\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/sandwich-go/xconf/ci.yml?style=flat-square)](https://github.com/sandwich-go/xconf/actions?query=workflow%3ACI)\n![Go Version](https://img.shields.io/badge/go%20version-%3E=1.14-61CFDD.svg?style=flat-square)\n[![Go Report Card](https://goreportcard.com/badge/github.com/sandwich-go/xconf)](https://goreportcard.com/report/github.com/sandwich-go/xconf)\n[![GoDoc](https://godoc.org/github.com/sandwich-go/xconf?status.svg)](https://godoc.org/github.com/sandwich-go/xconf)\n\n[README | 中文](README.md)\n\nGolang configuration file loading parsing, [goconf](https://github.com//timestee/goconf) v2, extended feature support\n\nRun XConf Example: [![run on repl.it](https://repl.it/badge/github/timestee/XConf-example)](https://repl.it//@timestee/XConf-example#main.go)\n\nRun XCmd Example: [![run on repl.it](https://replit.com/badge/github/timestee/XCmd-example)](https://replit.com/@timestee/XCmd-example#main.go)\n\n## Function Introduction\n- Support default value configuration, parsing\n- Support multiple formats, built-in JSON, TOML, YAML, FLAG, ENV support, and can register decoder to extend format support\n- Supports multi-file, multi-`io.Reader` data loading, file inheritance support\n- Support data loading configuration by OS ENV variables\n- Support loading data by command line parameter FLAGS\n- Support loading configuration data by remote URL\n- Support data overwrite merge, when loading multiple copies of data will be automatically merged by `FieldPath` in the order of the loaded files\n- Support binding Env parameters by `${READ_TIMEOUT|5s}`, `${IP_ADDRESS}`, etc.\n- Support configuration hotload, real-time synchronization, built-in memory hotload support, support asynchronous update notification, support [xconf-providers](https://github.com/sandwich-go/xconf-providers): ETCD, file system.\n- Support `WATCH` specific `FieldPath` changes\n- Support export configuration to multiple configuration files\n- Support configuration HASH, easy to compare configuration consistency\n- `FLAGS`, `ENV`, `FieldPath` support complex types, support for custom complex type extension support\n- Support configuration of access secret key\n- Support custom grayscale update based on Label\n- Support numeric aliases, such as `math.MaxInt`,`runtime.NumCPU`\n- Support \",squash\" to mention the fields of sub-structures to the parent structure for configuration expansion\n\n## Explanation of terms\n- `FieldTag`\n    - `xconf` is the field alias used when converting the configuration from Strut to JSON, TOML, YAML, FLAG, ENV, etc. For example: the `FieldTag` of `HttpAddress` in the example configuration is `http_address`.\n    - If `xconf: \"http_address\"` is not configured, the default field name of `SnakeCase` will be used as the `FieldTag`, which can be specified by `xconf.WithFieldTagConvertor` for other programs, such as lowercase field names, etc. Note that the `FieldTag` strategy must be be consistent with the string used in the configuration source, otherwise it will cause the parsing data to fail.\n- `FieldPath`, the Field access path composed by `FieldTag`, such as the `Config.SubTest.HTTPAddress` in the sample configuration `FieldPath` for `config.sub_test.http_address`.\n- `Leaf`,`xconf` in the configuration of the minimum unit, the base type, slice type are the minimum unit, Struct is not the minimum unit of the configuration, will be assigned, override according to the configuration of the property field.\n    - By default map is the minimum unit configured in `xconf`, but you can specify the `notleaf` tag so that map is not the minimum unit, but is merged based on key. But in this case the value of map is still the minimum unit in `xconf`, even if the value is a Struct, it will be the minimum unit for configuration merging\n\t- With `xconf.WithMapMerge(true)` you can activate the `MapMerge` mode, in which both map and its value are no longer the minimum unit of the configuration, but the minimum unit of the configuration is the base type and the slice type.\n\n## Quick start\n### Define the configuration structure\n- Refer to [xconf/tests/conf.go](https://github.com/sandwich-go/xconf/blob/master/tests/conf.go) to use [optiongen](https://github.com/timestee/ optiongen) to define the configuration and specify `--xconf=true` to generate tags that support `xconf` requirements.\n- Customize the structure to specify `xconf`-required tags\n```golang\ntype Server struct {\n\tTimeouts map[string]time.Duration `xconf:\"timeouts\"`\n}\n\ntype SubTest struct {\n\tHTTPAddress string            `xconf:\"http_address\"`\n\tMapNotLeaf  map[string]int    `xconf:\"map_not_leaf,notleaf\"`\n\tMap2        map[string]int    `xconf:\"map2\"`\n\tMap3        map[string]int    `xconf:\"map3\"`\n\tSlice2      []int64           `xconf:\"slice2\"`\n\tServers     map[string]Server `xconf:\"servers,notleaf\"`\n}\n\ntype Config struct {\n\tHttpAddress     string          `xconf:\"http_address\"`\n\tMap1            map[string]int  `xconf:\"map1\"`\n\tMapNotLeaf      map[string]int  `xconf:\"map_not_leaf,notleaf\"`\n\tTimeDurations   []time.Duration `xconf:\"time_durations\"`\n\tInt64Slice      []int64         `xconf:\"int64_slice\"`\n\tFloat64Slice    []float64       `xconf:\"float64_slice\"`\n\tUin64Slice      []uint64        `xconf:\"uin64_slice\"`\n\tStringSlice     []string        `xconf:\"string_slice\"`\n\tReadTimeout     time.Duration   `xconf:\"read_timeout\"`\n\tSubTest         SubTest         `xconf:\"sub_test\"`\n}\n```\n\n### Load configuration from file\nTake the `yaml` format as an example (tests/)\n```yaml\nhttp_address: :3002\nread_timeout: 100s\ndefault_empty_map:\n  test1: 1\nmap1:\n  test1: 1000000\nmap_not_leaf:\n  test1: 1000000\nint64_slice:\n- 1\n- 2\nsub_test:\n  map2:\n    ${IP_ADDRESS}: 2222\n  map_not_leaf:\n    test2222: 2222\n  servers:\n    s1:\n      timeouts:\n        read: ${READ_TIMEOUT|5s} \n```\n\u003e Reference:[test/main/main.go](https://github.com/sandwich-go/xconf/blob/master/tests/main/main.go), inheritance between files is specified by `xconf_inherit_files`, reference [ test/main/c2.toml](https://github.com/sandwich-go/xconf/blob/master/tests/main/c2.toml)\n```golang\ncc := NewTestConfig(\n\txconf.WithFiles(\"c2.toml\"),\n\txconf.WithReaders(bytes.NewBuffer(yamlContents),bytes.NewBuffer(tomlContents),xconf.NewRemoteReader(\"http://127.0.0.1:9001/test.json\", time.Duration(5)*time.Second)),\n\txconf.WithFlagSet(flag.CommandLine),\n\txconf.WithEnviron(os.Environ()),\n)\nxconf.Parse(cc)\n```\n\n### Configuration deposit file\n```golang\n// SaveToFile dumps the built-in parsed data to a file, selecting the codec according to the file suffix.\nfunc SaveToFile(fileName string) error\n// SaveToWriter dumps the built-in parsed data to the writer, type ct\nfunc SaveToWriter(ct ConfigType, writer io.Writer) error \n\n// SaveVarToFile writes the external valPtr to the fileName, selecting the codec according to the file suffix.\nfunc SaveVarToFile(valPtr interface{}, fileName string) error \n\n// SaveVarToWriter writes the external valPtr to the writer, type ct\nfunc SaveVarToWriter(valPtr interface{}, ct ConfigType, writer io.Writer) error \n\n// MustSaveToFile dump the built-in parsed data to a file, choose the codec according to the file suffix, if an error occurs it will panic\nfunc MustSaveToFile(f string) \n// MustSaveToWriter dumps the built-in parsed data to the writer, specify the ConfigType, if an error occurs, it will panic.\nfunc MustSaveToWriter(ct ConfigType, writer io.) \n\n// MustSaveVarToFile write external valPtr to fileName, select codec according to file suffix\nfunc MustSaveVarToFile(v interface{}, f string) \n\n// MustSaveVarToWriter writes the external valPtr to writer, type ct\nfunc MustSaveVarToWriter(v interface{}, ct ConfigType, w io.Writer) \n\n// MustSaveToBytes returns the built-in parsed data as a byte stream, ConfigType must be specified\nfunc MustSaveToBytes(ct ConfigType) []byte { return xx.MustSaveToBytes(ct) }\n\n// SaveVarToWriterAsYAML parses the built-in parsed data to yaml with comment\nfunc SaveVarToWriterAsYAML(valPtr interface{}, writer io.Writer) error\n```\n\n## Available options\n- `WithFiles` : specifies the files to be loaded, the configuration override order depends on the incoming file order\n- `WithReaders`: specifies the loaded `io.Reader`, the configuration override order depends on the incoming `io.Reader` order.\n- CommandLine`, if `nil` is specified, the parameters will not be automatically created to `FlagSet`, and the data in `FlagSet` will not be parsed.\n- `WithFlagArgs`: Specify the parameter data to be parsed by `FlagSet`, default is `os.Args[1:]`.\n- `WithFlagValueProvider`: `FlagSet` supports limited types, some types are extended in `xconf/xflag/vars`, see [Flag and Env support].\n- `WithEnviron`: specifies the value of the environment variable\n- `WithErrorHandling`: Specify the error handling method, same as `flag.\n- `WithLogDebug`: Specify the debug log output\n- `WithLogWarning`: Specify the warn log output\n- `WithFieldTagConvertor`: This method converts `FieldTag` when it cannot be obtained by TagName, default SnakeCase.\n- `WithTagName`: Tag name of the source of the `FieldTag` field, default `xconf`.\n- `WithTagNameDefaultValue`: The Tag name used for the default value, default `default`.\n- `WithParseDefault`: whether to parse the default value, default true, recommended to use [optiongen](https://github.com/timestee/optiongen) to generate the default configuration data\n- `WithDebug`: debug mode, will output detailed log of parsing process\n- `WithDecoderConfigOption`: adjust the mapstructure parameter, `xconf` uses [mapstructure](https://github.com/sandwich-go/mapstructure) for type conversion\n- `FieldPathDeprecated`: deprecated configuration, no error will be reported when parsing, but a warning log will be printed\n- `ErrEnvBindNotExistWithoutDefault`: Error when EnvBind if the specified key does not exist in Env and no default value is specified\n- `FieldFlagSetCreateIgnore`: The specified `FieldPath` or type name will not print the warning log when there is no Flag Provider.\n\n## Flag and Env Support\n- Support for specifying configuration files in Flag via `xconf_files`\n- `xconf/xflag/vars` extends some of the types as follows:\n    - float32,float64\n    - int,int8,int16,int32,int64\n    - uint,uint8,uint16,uint32,uint64\n    - []float32,[]float64\n    - []int,[]int8,[]int16,[]int32,[]int64\n    - []uint,[]uint8,[]uint16,[]uint32,[]uint64\n    - []string\n    - []Duration\n    - map[stirng]string,map[int]int,map[int64]int64,map[int64]string,map[stirng]int,map[stirng]int64,map[stirng]Duration\n- Extended type Slice and Map configuration\n   - slcie is defined in such a way that elements are split by `vars.StringValueDelim`, the default is `,`, for example:`--time_durations=5s,10s,100s`\n   - map is positioned as K,V split by `vars.StringValueDelim`, default is `,`, e.g.:`--sub_test.map_not_leaf=k1,1,k2,2,k3,3`\n- Custom extensions\n    - The extension needs to implement the `flag.Getter` interface, which can be used to implement custom Usage information by implementing the `Usage() string`.\n        ```golang\n        const JsnoPrefix = \"json@\"\n\n        type serverProvider struct {\n            s    string\n            set  bool\n            data *map[string]Server\n        }\n\n        func (sp *serverProvider) String() string {\n            return sp.s\n        }\n        func (sp *serverProvider) Set(s string) error {\n            sp.s = s\n            if sp.set == false {\n                *sp.data = make(map[string]Server)\n            }\n            if !strings.HasPrefix(s, JsnoPrefix) {\n                return errors.New(\"server map need json data with prefix:\" + JsnoPrefix)\n            }\n            s = strings.TrimPrefix(s, JsnoPrefix)\n            return json.Unmarshal([]byte(s), sp.data)\n        }\n        func (sp *serverProvider) Get() interface{} {\n            ret := make(map[string]interface{})\n            for k, v := range *sp.data {\n                ret[k] = v\n            }\n            return ret\n        }\n        func (sp *serverProvider) Usage() string {\n            return fmt.Sprintf(\"server map, json format\")\n        }\n        func newServerProvider(v interface{}) flag.Getter {\n            return \u0026serverProvider{data: v.(*map[string]Server)}\n        }\n\n        ```\n    - Registering extensions\n        - `vars.SetProviderByFieldPath` set extension by `FieldPath`\n        - `vars.SetProviderByFieldType` sets extensions by field type name\n    ```golang\n        cc := \u0026Config{}\n        jsonServer := `json@{\"s1\":{\"timeouts\":{\"read\":5000000000},\"timeouts_not_leaf\":{\"write\":5000000000}}}`\n        x := xconf.New(\n            xconf.WithFlagSet(flag.NewFlagSet(\"xconf-test\", flag.ContinueOnError)),\n            xconf.WithFlagArgs(\"--sub_test.servers=\"+jsonServer),\n            xconf.WithEnviron(\"sub_test_servers=\"+jsonServer),\n        )\n        vars.SetProviderByFieldPath(\"sub_test.servers\", newServerProvider)\n        vars.SetProviderByFieldType(\"map[string]Server\", newServerProvider)\n    ```\n- Keys\n `xconf.DumpInfo` to get the FLAG and ENV names supported by the configuration, as shown below, where Y is the Option configuration item, D is the Deprecated field, and M is the xconf internal field.\n ```shell\n------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nFLAG                              ENV                                         TYPE            USAGE\n------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n--default_empty_map               TEST_PREFIX_DEFAULT_EMPTY_MAP               map[string]int  |Y| xconf/xflag/vars, key and value split by ,\n--float64_slice                   TEST_PREFIX_FLOAT64_SLICE                   []float64       |Y| xconf/xflag/vars, value split by , (default [101.191 202.202 303.303])\n--http_address                    TEST_PREFIX_HTTP_ADDRESS                    string          |Y| http_address (default \"127.0.0.1\")\n--int64_slice                     TEST_PREFIX_INT64_SLICE                     []int64         |Y| xconf/xflag/vars, value split by , (default [101 202 303])\n--int8                            TEST_PREFIX_INT8                            int8            |Y| int8 (default 1)\n--map1                            TEST_PREFIX_MAP1                            map[string]int  |Y| k,v使用,分割 (default map[test1:100 test2:200])\n--map_not_leaf                    TEST_PREFIX_MAP_NOT_LEAF                    map[string]int  |D| Deprecated: 使用Map1 (default map[test1:100 test2:200])\n--max_int                         TEST_PREFIX_MAX_INT                         int             |Y| max_int (default 0)\n--max_uint64                      TEST_PREFIX_MAX_UINT64                      uint64          |Y| max_uint64 (default 0)\n--option_usage                    TEST_PREFIX_OPTION_USAGE                    string          |Y| option_usage (default \"Some application-level configuration rules are described here\")\n--process_count                   TEST_PREFIX_PROCESS_COUNT                   int8            |Y| process_count (default 1)\n--read_timeout                    TEST_PREFIX_READ_TIMEOUT                    Duration        |Y| read_timeout (default 5s)\n--redis.redis_address             TEST_PREFIX_REDIS_REDIS_ADDRESS             string          |Y| redis.redis_address (default \"127.0.0.1:6637\")\n--redis_as_pointer.redis_address  TEST_PREFIX_REDIS_AS_POINTER_REDIS_ADDRESS  string          |Y| redis_as_pointer.redis_address\n--redis_timeout.read_timeout      TEST_PREFIX_REDIS_TIMEOUT_READ_TIMEOUT      Duration        |Y| redis_timeout.read_timeout (default 0s)\n--string_slice                    TEST_PREFIX_STRING_SLICE                    []string        |Y| xconf/xflag/vars, value split by , (default [test1 test2 test3])\n--sub_test.http_address           TEST_PREFIX_SUB_TEST_HTTP_ADDRESS           string          |Y| sub_test.http_address\n--sub_test.map2                   TEST_PREFIX_SUB_TEST_MAP2                   map[string]int  |Y| xconf/xflag/vars, key and value split by ,\n--sub_test.map3                   TEST_PREFIX_SUB_TEST_MAP3                   map[string]int  |Y| xconf/xflag/vars, key and value split by ,\n--sub_test.map_not_leaf           TEST_PREFIX_SUB_TEST_MAP_NOT_LEAF           map[string]int  |Y| xconf/xflag/vars, key and value split by ,\n--sub_test.slice2                 TEST_PREFIX_SUB_TEST_SLICE2                 []int64         |Y| xconf/xflag/vars, value split by ,\n--test_bool                       TEST_PREFIX_TEST_BOOL                       bool            |Y| test_bool (default false)\n--test_bool_true                  TEST_PREFIX_TEST_BOOL_TRUE                  bool            |Y| test_bool_true (default true)\n--time_durations                  TEST_PREFIX_TIME_DURATIONS                  []Duration      |Y| 延迟队列 (default [1s 1s])\n--uin64_slice                     TEST_PREFIX_UIN64_SLICE                     []uint64        |Y| xconf/xflag/vars, value split by , (default [101 202 303])\n--xconf_flag_files                TEST_PREFIX_XCONF_FLAG_FILES                string          |M| xconf files provided by flag, file slice, split by ,\n------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nSome application-level configuration rules are described here\n------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n ```\n \n### ENV binding\nSupport resolving ENV variable names, as in the following example.\n```golang\n\nvar yamlTest2 = []byte(`\nhttp_address: :3002\nread_timeout: 100s\ndefault_empty_map:\n  test1: 1\nmap1:\n  test1: 1000000\nmap_not_leaf:\n  test1: 1000000\nint64_slice:\n- 1\n- 2\nsub_test:\n  map2:\n    ${IP_ADDRESS}: 2222\n  map_not_leaf:\n    test2222: 2222\n  servers:\n    s1:\n      timeouts:\n        read: ${READ_TIMEOUT|5s} \n`)\n\nfunc TestEnvBind(t *testing.T) {\n\tConvey(\"env bind\", t, func(c C) {\n\t\tcc := \u0026Config{}\n\t\tx := xconf.NewWithoutFlagEnv()\n\t\tSo(x.UpdateWithFieldPathValues(\"http_address\", \"${XCONF_HOST}:${XCONF_PORT}\"),ShouldBeNil)\n\t\terr := x.Parse(cc)\n\t\tSo(err, ShouldBeNil)\n\t\tSo(cc.HttpAddress, ShouldEqual, \"\")\n\t\thost := \"127.0.0.1\"\n\t\tport := \"9001\"\n\t\tos.Setenv(\"XCONF_HOST\", host)\n\t\tos.Setenv(\"XCONF_PORT\", port)\n\t\tSo(cc.HttpAddress, ShouldEqual, \"\")\n\t\tSo(x.UpdateWithReader(bytes.NewBuffer(yamlTest2)), ShouldBeNil)\n\t\tSo(x.UpdateWithFieldPathValues(\"http_address\", \"${XCONF_HOST}:${XCONF_PORT}\"), ShouldBeNil)\n\t\tlatest, err := x.Latest()\n\t\tSo(err, ShouldBeNil)\n\t\tcc = latest.(*Config)\n\t\tSo(cc.HttpAddress, ShouldEqual, host+\":\"+port)\n\t\tSo(cc.SubTest.Servers[\"s1\"].Timeouts[\"read\"], ShouldEqual, time.Duration(5)*time.Second)\n\t})\n}\n```\n\n### URL read\n```golang\ncc := \u0026Config{}\nx := xconf.NewWithoutFlagEnv(xconf.WithReaders(xconf.NewRemoteReader(\"http://127.0.0.1:9001/test.yaml\", time.Duration(1)*time.Second)))\n```\n\n## Dynamic updates\n\n### Configuration file based\n```golang\n\ttestBytesInMem := \"memory_test_key\"\n\tmem, err := xmem.New()\n\tpanicErr(err)\n\t// xconf/kv provides an update mechanism based on ETCD/FILE/MEMORY\n\t// You can implement xconf's loader interface or interface to xmem to update the configuration with xmem's mechanism\n\txconf.WatchUpdate(testBytesInMem, mem)\n\tupdated := make(chan *Config, 1)\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase v := \u003c-x.NotifyUpdate():\n\t\t\t\tupdated \u003c- v.(*Config)\n\t\t\t}\n\t\t}\n\t}()\n```\n\n### Based on `FieldPath`\n```golang\nerr := xconf.WatchFieldPath(\"sub_test.http_address\", func(from, to interface{}) {\n\tfmt.Printf(\"sub_test.http_address changed from %v to %v \", from, to)\n})\npanicErr(err)\n```\nFile-based or Buffer-based updates can be implemented by the following methods, and the update results can be obtained asynchronously via `xconf.NotifyUpdate`, or synchronously via `xconf.Latest`.\n- `UpdateWithFiles(files ...string) (err error)`\n- `UpdateWithReader(readers ...io.Reader) (err error)`\n\nFile-based updates can be implemented by the following methods, the update result is obtained asynchronously by `xconf.NotifyUpdate`, or synchronously by `xconf.Latest`.\n- `UpdateWithFlagArgs(flagArgs ...string)  (err error)`\n- `UpdateWithEnviron(environ ...string) (err error)`\n- `UpdateWithFieldPathValues(kv ...string) (err error)`\n\n### Bind the latest configuration\n```golang\nxconf.Latest()\n```\n\n### Atomic auto-update\nUsing [optiongen](https://github.com/timestee/optiongen) to define a configuration and specifying `--xconf=true` to generate a configuration with `XConf` support generates `Atomic` update support by default for.\n```golang\n\nfunc (cc *Config) AtomicSetFunc() func(interface{}) { return AtomicConfigSet }\n\nvar atomicConfig unsafe.Pointer\n\nfunc AtomicConfigSet(update interface{}) {\n\tatomic.StorePointer(\u0026atomicConfig, (unsafe.Pointer)(update.(*Config)))\n}\nfunc AtomicConfig() ConfigVisitor {\n\tcurrent := (*Config)(atomic.LoadPointer(\u0026atomicConfig))\n\tif current == nil {\n\t\tatomic.CompareAndSwapPointer(\u0026atomicConfig, nil, (unsafe.Pointer)(newDefaultConfig()))\n\t\treturn (*Config)(atomic.LoadPointer(\u0026atomicConfig))\n\t}\n\treturn current\n}\n\n```\n\nJust provide `AtomicConfig()` when parsing and automatically call back the `AtomicConfigSet` method for pointer replacement when the configuration is updated.\n```golang\nfunc TestAtomicVal(t *testing.T) {\n\tConvey(\"atomic val\", t, func(c C) {\n\t\tx := xconf.NewWithoutFlagEnv()\n\t\tSo(x.Parse(AtomicConfig()), ShouldBeNil)\n\t\tSo(x.UpdateWithFieldPathValues(\"http_address\", \"10.10.10.10\"), ShouldBeNil)\n\t\tSo(AtomicConfig().HttpAddress, ShouldEqual, \"10.10.10.10\")\n\t})\n}\n\n```\n\n## Usage examples\n### Loading encrypted configuration by URL\n```golang\npackage main\n\nimport (\n\t\"time\"\n\n\t\"github.com/sandwich-go/xconf\"\n\t\"github.com/sandwich-go/xconf/secconf\"\n\t\"github.com/sandwich-go/xconf/tests\"\n)\n\nfunc main() {\n\turlReader := xconf.NewRemoteReader(\"127.0.0.1:9001\", time.Duration(1)*time.Second)\n\tkey, _ := xconf.ParseEnvValue(\"${XXXTEA_KEY}|1dxz29pew\", false)\n\turlReaderSec := secconf.Reader(urlReader, secconf.StandardChainDecode(secconf.NewDecoderXXTEA([]byte(key))))\n\txconf.Parse(tests.AtomicConfig(), xconf.WithReaders(urlReaderSec))\n}\n```\n\n## Usage restrictions\n### Private fields\nIf a private field is defined in the configuration or is hidden from XConf (specified as `-` by the xconf tag), the following usage restrictions apply when using the `Dynamic Update` feature.\n- Bind the latest configuration in the active call to `Latest`.\n- `Atomic` active binding mode, the configuration update\n\n### Flag\n- The configuration fields automatically created and defined in `FlagSet` are limited to the types supported by xconf/xflag.\n- Complex types such as: \"map[string][]time.Durtaion\", \"map[string]*Server\", etc. cannot be created automatically and will have WARNGING logs printed, and these fields can be actively ignored by `WithFlagCreateIgnoreFiledPath`.\n- Fields that cannot be created automatically in `FlagSet` cannot get the information and default values of the fields through `--help` or `Usage()`.\n\nXConf cannot cache private and hidden field data according to `Parse`. In order to prevent possible data multi-processing access problems between the logical layer accessing the configuration and configuration update, when `Atomic` is passively updated or `Latest` is actively called to bind, the incoming structure constructs a new configuration structure, resulting in the data obtained at this time will not contain private fields and hidden fields.\n\nWhen using the `Dynamic Update` feature, it is recommended that the private data or hidden fields be reassigned after the `Latest` call or in the set `InstallCallbackOnAtomicXXXXXXXXXSet` callback logic.\n\n## xcmd Command Line Support\nxcmd relies on xconf to automatically create, bind, and parse flag parameters, and supports custom flags, middleware, and subcommands. Reference: [xcmd/main/main.go](https://github.com/sandwich-go/xconf/blob/master/xcmd/main/main.go)\n\n## help command extension\n- `--help=yaml`\n  - Print the current parsed configuration to the terminal in `-yaml` format\n- `--help=. /test.yaml`\n  - Print the currently parsed configuration in `-yaml` format to the specified file, which will be created automatically if the file does not exist\n\n\u003e Since the help command truncates the configuration parsing process, the output of the help extension command is the content of the incoming structure itself (the default value), not the content of the specified file, FLAG, ENV, etc.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandwich-go%2Fxconf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsandwich-go%2Fxconf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandwich-go%2Fxconf/lists"}