# Config **config** is a simple golang library and designed to read configurations from JSON, Yaml files, environment variables and command line. **config** depends on [go-yaml](https://github.com/go-yaml/yaml) to analyze Yaml file and uses built-in golang library to handle JSON file. ## Installation 1. Install [Yaml](https://github.com/go-yaml/yaml) library first: ```sh go get gopkg.in/yaml.v3 ``` 1. Install **config** library: ```sh go get github.com/eschao/config ``` ## Usage ### I. Define configuration name in structure tags Like JSON, Yaml, **config** uses tags to define configurations: | Tag | Example | Function | | --------- | --------------------------------------- | --------------------------------------------------------------- | | json | Host string `json:"host"` | Maps `Host` to a JSON field: **host** | | yaml | Host string `yaml:"host"` | Maps `Host` to a Yaml field: **host** | | env | Host string `env:"HOST"` | Maps `Host` to a Environment variable: **HOST** | | cli | Host string `cli:"host database host"` | Maps `Host` to a command line argument: **-host** or **--host** | | default | Port int `default:"8080"` | Defines the port with default value: **8080** | | separator | Path string `json:"path" separator:";"` | Separator is used to split string to a slice | | usage | Usage string `usage:"host address"` | Usage description | #### 1. Data types **config** supports the following golang data types: * bool * string * int8, int16, int, int32, int64 * uint8, uint16, uint, uint32, uint64 * float32, float64 * slice type. e.g: []string, []int ... #### 2. Defines **default** values Using **default** keyword in structure tags to define default value: ```golang type Log struct { Path string `default:"/var/logs"` Level string `default:"debug"` } ``` #### 3. Defines configuration name for JSON Like parsing JSON object, using **json** keyword to define configuration name: ```golang type Database struct { Host string `json:"host"` Port int `json:"port"` Username string `default:"admin" json:"username"` Password string `default:"admin" json:"password"` Log Log `json:"log"` } ``` Corresponding JSON file: ```json { "host": "test.db.hostname", "port": 8080, "username": "admin", "password": "admin", "log": { "path": "/var/logs/db", "level": "debug" } } ``` #### 4. Defines configuration name for Yaml Like parsing Yaml object, using **yaml** keyword to define configuration name ```golang type Database struct { Host string `yaml:"host"` Port int `yaml:"port"` Username string `default:"admin" yaml:"username"` Password string `default:"admin" yaml:"password"` Log Log `yaml:"log"` } ``` Corresponding Yaml file: ```yaml host: test.db.hostname port: 8080 username: admin password: admin log: path: /var/logs/db level: debug ``` #### 5. Defines configuration name for Environment variable Using **env** keyword to define configuration name ```golang type Database struct { Host string `env:"DB_HOST"` Port int `env:"DB_PORT"` Username string `default:"admin" env:"DB_USER"` Password string `default:"admin" env:"DB_PASSWORD"` Log Log `env:"DB_LOG_"` } ``` Corresponding Environment variables: ```shell export DB_HOST=test.db.hostname export DB_PORT=8080 export DB_USER=admin export DB_PASSWORD=admin export DB_LOG_PATH=/var/logs/db export DB_LOG_LEVEL=debug ``` Since the `Log` is a structure and nested in `Database` structure, the tag of `Log` and tags of its structure members will be combined to be an unique environment variable, for example: `Path` will be mapped to environment var: `DB_LOG_PATH`. But if the `Log` has no tag definition, only tags of its structure members will be used, that means the `Path` will be mapped to `PATH`. #### 6. Defines configuration name for Command line Using **cli** keyword to define configuration name: ```golang type Database struct { Host string `cli:"host" usage:"database host name"` Port int `cli:"port" usage:"database port"` Username string `cli:"username" default:"admin" usage:"database username"` Password string `cli:"password" default:"admin" usage:"database password"` Log Log `cli:"log" usage:"database log configurations"` } ``` For **cli** definition, the string is command line argument, and the **usage** tag are the command line usage and will be outputted when printing usage. Corresponding command line: ```shell ./main --host test.db.hostname --port 8080 --username admin --password admin --log-path /var/logs/db --log-level debug ``` or ```shell ./main --host=test.db.hostname --port=8080 --username=admin --password=admin --log-path=/var/logs/db --log-level=debug ``` #### 7. Defines configuration name as a slice type Using **separator** to split string as a slice: ```golang type Log struct { Levels []string `env:"LEVELS" cli:"levels" separator:";" usage:"log levels"` } ``` If the separator is not given, its default is **:**, The separator only works on **env** and **cli** tags. ```golang logConfig := Log{} // export LEVELS=debug;error;info config.ParseEnv(&logConfig) // logConfig[0] == debug // logConfig[1] == error // logConfig[2] == info ``` ### II. Parses configurations #### 1. Parses default values When default values are defined in tags, calls `config.ParseDefault(interface{})` to assign them to given structure instance **BEFORE** parsing any other configuration types: ```golang logConfig := Log{} config.ParseDefault(&logConfig) ``` >Note: Other parsing functions don't set structure instance with default values whatever if the configuration value is provided or not #### 2. Parses from Environment variables ```golang dbConfig := Database{} config.ParseEnv(&dbConfig) ``` #### 3. Parses from Command line ```golang dbConfig := Database{} config.ParseCli(&dbConfig) ``` #### 4. Parses from default configuration files Calls **ParseConfigFile(interface{}, string)** to parse given configuration file: ```golang dbConfig := Database{} config.ParseConfigFile(&dbConfig, "config.json") ``` If the configuration file is not given, the default configuration files: **config.json** and **config.yaml** will be located under the same folder with fixed searching order. The **config.json** will always be located first, if it doesn't exist, then checks\ **config.yaml**. If all of them are not found, parsing will fail. ```golang dbConfig := Database{} config.ParseConfigFile(&dbConfig, "") ``` #### 4. Parses from configuration file specified by command line Calls **ParseConfig(interface{}, string)** to parse the configuration file given by command line. The second parameter is a command line argument which is used to specify config file: ```golang dbConfig := Database{} config.ParseConfig(&dbConfig, "c") ``` Run application like: ```shell ./main -c config.json ``` **ParseConfig()** will analyze command line arguments and get configure file: **config.json** from argument **-c** ### III. Multi-Configurations You can define all supported configuration tags in a structure and call corresponding functions in your desired order to parse. Examples: ```golang type Log struct { Path string `cli:"path" default:"/var/logs" env:"PATH" json:"path" usage:"log path" yaml:"path"` Levels string `cli:"levels" default:"debug;error" env:"LEVELS" json:"levels" usage:"log levels" yaml:"levels"` } type Database struct { Host string `cli:"host" env:"DB_HOST" json:"host" usage:"database host name" yaml:"host"` Port int `cli:"port" env:"DB_PORT" json:"port" usage:"database port" yaml:"port"` Username string `cli:"username" default:"admin" env:"DB_USER" json:"user" usage:"database username" yaml" user"` Password string `cli:"password" default:"admin" env:"DB_PASSWD" json:"passwd" usage:"database password" yaml:"passwd"` Log Log `cli:"log" env:"DB_LOG_" json:"log" usage:"database log configurations" yaml:"log"` } ``` Then, you can parse as below: ```golang dbConfig := Database{} // parse default values if err := config.ParseDefault(&dbConfig); err != nil { // error handling } // parse configuration file from command line err := config.ParseConfig(&dbConfig, "c") // parse default configurations if err != nil { err = config.ParseConfigFile(&dbConfig), "") } // parse environment variables if err != nil { err = config.ParseEnv(&dbConfig) } // parse command line if err != nil { err = config.ParseCli(&dbConfig) } // check if all required configurations are set ... ``` You don't need to call all of them. Just invokes parsing function that your need. ## License This project is licensed under the Apache License Version 2.0.