2
0

Исправлены опечатки.

This commit is contained in:
Алексей Бадяев 2024-10-19 23:05:20 +07:00
parent 3c1422ca10
commit f884b56a10
Signed by: alexey
GPG Key ID: 686FBC1363E4AFAE
4 changed files with 106 additions and 42 deletions

View File

@ -1,6 +1,8 @@
{ {
"cSpell.words": [ "cSpell.words": [
"eschao", "eschao",
"stretchr" "gopkg",
"stretchr",
"struct"
] ]
} }

137
README.md
View File

@ -1,19 +1,25 @@
## Introduction # 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 anlayze Yaml file and uses built-in golang library to handle JSON file.
**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 ## Installation
1. Install [Yaml](https://github.com/go-yaml/yaml) library first: 1. Install [Yaml](https://github.com/go-yaml/yaml) library first:
```
```sh
go get gopkg.in/yaml.v3 go get gopkg.in/yaml.v3
``` ```
2. Install **config** library: 1. Install **config** library:
```
```sh
go get github.com/eschao/config go get github.com/eschao/config
``` ```
## Usage ## Usage
### I. Define configuration name in structure tags ### I. Define configuration name in structure tags
Like JSON, Yaml, **config** uses tags to define configurations: Like JSON, Yaml, **config** uses tags to define configurations:
| Tag | Example | Function | | 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** | | 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 | | separator | Path string `json:"path" separator:";"` | Separator is used to split string to a slice |
#### 1. Data types #### 1. Data types
**config** supports the following golang data types: **config** supports the following golang data types:
* bool
* string * bool
* int8, int16, int, int32, int64 * string
* uint8, uint16, uint, uint32, uint64 * int8, int16, int, int32, int64
* float32, float64 * uint8, uint16, uint, uint32, uint64
* slice type. e.g: []string, []int ... * float32, float64
* slice type. e.g: []string, []int ...
#### 2. Defines **default** values #### 2. Defines **default** values
Using **default** keyword in structure tags to define default value: Using **default** keyword in structure tags to define default value:
```golang ```golang
type Log struct { type Log struct {
Path string `default:"/var/logs"` Path string `default:"/var/logs"`
Level string `default:"debug"` 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: Like parsing JSON object, using **json** keyword to define configuration name:
```golang ```golang
type Database struct { type Database struct {
Host string `json:"host"` Host string `json:"host"`
@ -57,11 +68,12 @@ Like parsing JSON object, using **json** keyword to define configuration name:
``` ```
Corresponding JSON file: Corresponding JSON file:
```json ```json
{ {
"host": "test.db.hostname", "host": "test.db.hostname",
"port": 8080, "port": 8080,
"username": "amdin", "username": "admin",
"password": "admin", "password": "admin",
"log": { "log": {
"path": "/var/logs/db", "path": "/var/logs/db",
@ -71,7 +83,9 @@ Corresponding JSON file:
``` ```
#### 4. Defines configuration name for Yaml #### 4. Defines configuration name for Yaml
Like parsing Yaml object, using **yaml** keyword to define configuration name Like parsing Yaml object, using **yaml** keyword to define configuration name
```golang ```golang
type Database struct { type Database struct {
Host string `yaml:"host"` Host string `yaml:"host"`
@ -81,19 +95,23 @@ Like parsing Yaml object, using **yaml** keyword to define configuration name
Log Log `yaml:"log"` Log Log `yaml:"log"`
} }
``` ```
Corresponding Yaml file: Corresponding Yaml file:
```yaml ```yaml
host: test.db.hostname host: test.db.hostname
port: 8080 port: 8080
username: amdin username: admin
password: admin password: admin
log: log:
path: /var/logs/db path: /var/logs/db
level: debug level: debug
``` ```
#### 5. Defines configuration name for Environment variable #### 5. Defines configuration name for Environment variable
Using **env** keyword to define configuration name Using **env** keyword to define configuration name
```golang ```golang
type Database struct { type Database struct {
Host string `env:"DB_HOST"` Host string `env:"DB_HOST"`
@ -105,6 +123,7 @@ Using **env** keyword to define configuration name
``` ```
Corresponding Environment variables: Corresponding Environment variables:
```shell ```shell
export DB_HOST=test.db.hostname export DB_HOST=test.db.hostname
export DB_PORT=8080 export DB_PORT=8080
@ -113,10 +132,17 @@ Corresponding Environment variables:
export DB_LOG_PATH=/var/logs/db export DB_LOG_PATH=/var/logs/db
export DB_LOG_LEVEL=debug 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 #### 6. Defines configuration name for Command line
Using **cli** keyword to define configuration name Using **cli** keyword to define configuration name
```golang ```golang
type Database struct { type Database struct {
Host string `cli:"host database host name"` 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"` 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: Corresponding command line:
```shell ```shell
./main -host test.db.hostname -port 8080 -username admin -password admin log -path /var/logs/db -level debug ./main -host test.db.hostname -port 8080 -username admin -password admin log -path /var/logs/db -level debug
``` ```
or or
```shell ```shell
./main -host=test.db.hostname -port=8080 -username=admin -password=admin log -path=/var/logs/db -level=debug ./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 #### 7. Defines configuration name as a slice type
Using **separator** to split string as a slice: Using **separator** to split string as a slice:
```golang ```golang
type Log struct { type Log struct {
Levels []string `env:"LEVELS" cli:"levels log levels" separator:";"` 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 ```golang
logConfig := Log{} logConfig := Log{}
// export LEVELS=debug;error;info // 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 ### II. Parses configurations
#### 1. Parses default values #### 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 ```golang
logConfig := Log{} logConfig := Log{}
config.ParseDefault(&logConfig) 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 #### 2. Parses from Environment variables
```golang ```golang
dbConfig := Database{} dbConfig := Database{}
config.ParseEnv(&dbConfig) config.ParseEnv(&dbConfig)
``` ```
#### 3. Parses from Command line #### 3. Parses from Command line
```golang ```golang
dbConfig := Database{} dbConfig := Database{}
config.ParseCli(&dbConfig) config.ParseCli(&dbConfig)
``` ```
#### 4. Parses from default configuration files #### 4. Parses from default configuration files
Calls **ParseConfigFile(interface{}, string)** to parse given configuration file: Calls **ParseConfigFile(interface{}, string)** to parse given configuration file:
```golang ```golang
dbConfig := Database{} dbConfig := Database{}
config.ParseConfigFile(&dbConfig, "config.json") 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 ```golang
dbConfig := Database{} dbConfig := Database{}
config.ParseConfigFile(&dbConfig, "") config.ParseConfigFile(&dbConfig, "")
``` ```
#### 4. Parses from configuration file specified by command line #### 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 ```golang
dbConfig := Database{} dbConfig := Database{}
config.ParseConfig(&dbConfig, "c") config.ParseConfig(&dbConfig, "c")
``` ```
Run application like: Run application like:
```shell ```shell
./main -c config.json ./main -c config.json
``` ```
**ParseConfig()** will analyze command line arguments and get configure file: **config.json** from argument **-c**
### III. Multi-Configurations **ParseConfig()** will analyze command line arguments and get configure file:
You can define all supported configuration tags in a structure and call corresponding functions in your desired order to parse. **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: Examples:
```golang ```golang
type Log struct { type Log struct {
Path string `json:"path" yaml:"path" env:"PATH" cli:"path log path" default:"/var/logs"` 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"` Log Log `json:"log" yaml:"log" env:"DB_LOG_" cli:"log database log configurations"`
} }
``` ```
Then, you can parse as below: Then, you can parse as below:
```golang ```golang
dbConfig := Database{} dbConfig := Database{}
@ -248,12 +311,12 @@ Then, you can parse as below:
err = config.ParseCli(&dbConfig) 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. You don't need to call all of them. Just invokes parsing function that your need.
## License ## License
This project is licensed under the Apache License Version 2.0.
This project is licensed under the Apache License Version 2.0.

View File

@ -19,7 +19,6 @@ import (
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
@ -190,7 +189,7 @@ func ParseConfigFile(i interface{}, configFile string) error {
// parseJSON parses JSON file and set structure with its value // parseJSON parses JSON file and set structure with its value
func parseJSON(i interface{}, jsonFile string) error { func parseJSON(i interface{}, jsonFile string) error {
raw, err := ioutil.ReadFile(jsonFile) raw, err := os.ReadFile(jsonFile)
if err != nil { if err != nil {
return fmt.Errorf("open json config file: %s", err.Error()) 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 // parseYaml parses Yaml file and set structure with its value
func parseYaml(i interface{}, yamlFile string) error { func parseYaml(i interface{}, yamlFile string) error {
raw, err := ioutil.ReadFile(yamlFile) raw, err := os.ReadFile(yamlFile)
if err != nil { if err != nil {
return fmt.Errorf("open yaml config file: %s", err.Error()) return fmt.Errorf("open yaml config file: %s", err.Error())
} }

2
go.mod
View File

@ -1,6 +1,6 @@
module git.mousesoft.ru/ms/config module git.mousesoft.ru/ms/config
go 1.23 go 1.22
require ( require (
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0