From f884b56a1045f37e24d774ccdabb469d1af07619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20=D0=91=D0=B0?= =?UTF-8?q?=D0=B4=D1=8F=D0=B5=D0=B2?= Date: Sat, 19 Oct 2024 23:05:20 +0700 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BE=D0=BF=D0=B5=D1=87=D0=B0=D1=82=D0=BA?= =?UTF-8?q?=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 4 +- README.md | 137 ++++++++++++++++++++++++++++++------------ config.go | 5 +- go.mod | 2 +- 4 files changed, 106 insertions(+), 42 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7e5bbad..248c1c5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,8 @@ { "cSpell.words": [ "eschao", - "stretchr" + "gopkg", + "stretchr", + "struct" ] } \ No newline at end of file diff --git a/README.md b/README.md index 0e56bc9..134e345 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,25 @@ -## Introduction -**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 anlayze Yaml file and uses built-in golang library to handle JSON file. +# 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 ``` -2. Install **config** library: -``` +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 | @@ -25,27 +31,32 @@ Like JSON, Yaml, **config** uses tags to define configurations: | 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 | - #### 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 ... + +* 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 { +type Log struct { Path string `default:"/var/logs"` Level string `default:"debug"` - } +} ``` -#### 3. Defines configruation name for JSON +#### 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"` @@ -57,11 +68,12 @@ Like parsing JSON object, using **json** keyword to define configuration name: ``` Corresponding JSON file: + ```json { "host": "test.db.hostname", "port": 8080, - "username": "amdin", + "username": "admin", "password": "admin", "log": { "path": "/var/logs/db", @@ -71,7 +83,9 @@ Corresponding JSON file: ``` #### 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"` @@ -81,19 +95,23 @@ Like parsing Yaml object, using **yaml** keyword to define configuration name Log Log `yaml:"log"` } ``` + Corresponding Yaml file: + ```yaml - host: test.db.hostname - port: 8080 - username: amdin - password: admin - log: - path: /var/logs/db - level: debug + 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"` @@ -105,6 +123,7 @@ Using **env** keyword to define configuration name ``` Corresponding Environment variables: + ```shell export DB_HOST=test.db.hostname export DB_PORT=8080 @@ -113,10 +132,17 @@ Corresponding Environment variables: 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```. + +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 database host name"` @@ -126,26 +152,35 @@ Using **cli** keyword to define configuration name Log Log `cli:"log database log configurations"` } ``` -For **cli** definition, the string before the first space is command line argument, the rest string are the command line usage and will be oupputed when printing usage + +For **cli** definition, the string before the first space is command line argument, +the rest string 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 -level debug ``` + or + ```shell ./main -host=test.db.hostname -port=8080 -username=admin -password=admin log -path=/var/logs/db -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 log levels" separator:";"` } ``` -If the separator is not given, its default is **:**, The separator only works on **env** and **cli** tags +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 @@ -156,57 +191,83 @@ If the separator is not given, its default is **:**, The separator only works on ``` ### 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: + +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 + +>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. +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. -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 specifiy config file: + +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. +**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 `json:"path" yaml:"path" env:"PATH" cli:"path log path" default:"/var/logs"` @@ -221,7 +282,9 @@ Examples: Log Log `json:"log" yaml:"log" env:"DB_LOG_" cli:"log database log configurations"` } ``` + Then, you can parse as below: + ```golang dbConfig := Database{} @@ -248,12 +311,12 @@ Then, you can parse as below: err = config.ParseCli(&dbConfig) } - // check if all requried configurations are set + // 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. +This project is licensed under the Apache License Version 2.0. diff --git a/config.go b/config.go index 229d9d3..62f5700 100644 --- a/config.go +++ b/config.go @@ -19,7 +19,6 @@ import ( "encoding/json" "flag" "fmt" - "io/ioutil" "os" "path/filepath" "reflect" @@ -190,7 +189,7 @@ func ParseConfigFile(i interface{}, configFile string) error { // parseJSON parses JSON file and set structure with its value func parseJSON(i interface{}, jsonFile string) error { - raw, err := ioutil.ReadFile(jsonFile) + raw, err := os.ReadFile(jsonFile) if err != nil { return fmt.Errorf("open json config file: %s", err.Error()) } @@ -200,7 +199,7 @@ func parseJSON(i interface{}, jsonFile string) error { // parseYaml parses Yaml file and set structure with its value func parseYaml(i interface{}, yamlFile string) error { - raw, err := ioutil.ReadFile(yamlFile) + raw, err := os.ReadFile(yamlFile) if err != nil { return fmt.Errorf("open yaml config file: %s", err.Error()) } diff --git a/go.mod b/go.mod index b47746a..85edf85 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module git.mousesoft.ru/ms/config -go 1.23 +go 1.22 require ( github.com/stretchr/testify v1.9.0