[Go] Package Viper

Package Viper

viper

환경 설정 파일들을 다루기 위해 Viper Package 를 사용한다.

Table of Contents

viper Basic

viper 은 유명한 configuration 패키지로써 많은 Go 프로젝트들 내에서 사용되었다.

env variable

환경 변수는 실행 환경 정보의 값을 지니고 있다.
Go 에서 env variable 을 관리하기 위해 자주 사용되는 패키지들은 세가지가 있다.

  1. os package
  2. godotenv package
  3. viper package

이 중 viper package 에 대해 알아보자.

Install

go get github.com/spf13/viper

기본 사용법

Instance
viper 인스턴스 생성하기


**Set File & Path**  
config 파일과 경로를 설정하기 위해서 ```SetConfigFile``` 이라는 메서드를 사용한다.  
```viper.SetConfigFile(".env")```  
* Viper 는 env 파일 외에 다양한 파일들을 지원한다.
    * HCL
    * TOML
    * JSON
    * YAML
    * etc..

**Read Config File**   
viper 에서 config 파일을 읽어들이는 메서드는 두 가지가 있다. 
1. ```ReadConfig()```  
    * yaml
    * json

1. ```ReadInConfig()```  
    * byte buffer

[↑ return to TOC](#table-of-contents)


## viper 코드 열어보기
### viper.ReadConfig
Configuration 파일을 읽어들인다.  
```go
func (v *Viper) ReadConfig(in io.Reader) error {
    v.config = make(map[string]interface{})
    return v.unmarshalReader(in, v.config)
}

↑ return to TOC

viper.ReadInConfig

미리 설정해둔 경로로 가서 디스크나 키-값 스토리지에 있는 config 파일을 찾아 읽어들인다.

↑ return to TOC

viper.WriteConfig

현재의 viper configuration 을 파일에 쓴다. 파일이 작성되는 위치는 미리 지정해둔 경로이다.
만약 경로가 설정되 있지 않다면 err 를 리턴한다.

func (v *Viper) WriteConfig() error {
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}
	return v.writeConfig(filename, true)
}

↑ return to TOC

viper.SafeWriteConfig

SafeWriteConfig 는 해당 경로에 config 파일이 존재하지 않을시에만 파일을 작성한다.
그로인해 덮어쓰기가 발생하지 않는다. 안전한 파일 작성이 가능하다.

func (v *Viper) SafeWriteConfig() error {
	if len(v.configPaths) < 1 {
		return errors.New("missing configuration for 'configPath'")
	}
	return v.SafeWriteConfigAs(filepath.Join(v.configPaths[0], v.configName+"."+v.configType))
}

↑ return to TOC

viper.Set

Set을 통해 직접 config 의 key 와 value 를 설정

func (v *Viper) Set(key string, value interface{}) {
	key = v.realKey(strings.ToLower(key))
	value = toCaseInsensitiveValue(value)

	path := strings.Split(key, v.keyDelim)
	lastKey := strings.ToLower(path[len(path)-1])
	deepestMap := deepSearch(v.override, path[0:len(path)-1])

	deepestMap[lastKey] = value
}

↑ return to TOC

viper.MergeInConfig

새 config 파일과 기존에 존재하는 config 파일을 합병시킨다.

func (v *Viper) MergeInConfig() error {
	jww.INFO.Println("Attempting to merge in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}

	if !stringInSlice(v.getConfigType(), SupportedExts) {
		return UnsupportedConfigError(v.getConfigType())
	}

	file, err := afero.ReadFile(v.fs, filename)
	if err != nil {
		return err
	}

	return v.MergeConfig(bytes.NewReader(file))
}

↑ return to TOC