github.com/crspeller/mattermost-server@v0.0.0-20190328001957-a200beb3d111/config/environment.go (about)

     1  // Copyright (c) 2019-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package config
     5  
     6  import (
     7  	"reflect"
     8  
     9  	"github.com/crspeller/mattermost-server/model"
    10  )
    11  
    12  // removeEnvOverrides returns a new config without the given environment overrides.
    13  // If a config variable has an environment override, that variable is set to the value that was
    14  // read from the store.
    15  func removeEnvOverrides(cfg, cfgWithoutEnv *model.Config, envOverrides map[string]interface{}) *model.Config {
    16  	paths := getPaths(envOverrides)
    17  	newCfg := cfg.Clone()
    18  	for _, path := range paths {
    19  		originalVal := getVal(cfgWithoutEnv, path)
    20  		getVal(newCfg, path).Set(originalVal)
    21  	}
    22  	return newCfg
    23  }
    24  
    25  // getPaths turns a nested map into a slice of paths describing the keys of the map. Eg:
    26  // map[string]map[string]map[string]bool{"this":{"is first":{"path":true}, "is second":{"path":true}))) is turned into:
    27  // [][]string{{"this", "is first", "path"}, {"this", "is second", "path"}}
    28  func getPaths(m map[string]interface{}) [][]string {
    29  	return getPathsRec(m, nil)
    30  }
    31  
    32  // getPathsRec assembles the paths (see `getPaths` above)
    33  func getPathsRec(src interface{}, curPath []string) [][]string {
    34  	if srcMap, ok := src.(map[string]interface{}); ok {
    35  		paths := [][]string{}
    36  		for k, v := range srcMap {
    37  			paths = append(paths, getPathsRec(v, append(curPath, k))...)
    38  		}
    39  		return paths
    40  	}
    41  
    42  	return [][]string{curPath}
    43  }
    44  
    45  // getVal walks `src` (here it starts with a model.Config, then recurses into its leaves)
    46  // and returns the reflect.Value of the leaf at the end `path`
    47  func getVal(src interface{}, path []string) reflect.Value {
    48  	var val reflect.Value
    49  	if reflect.ValueOf(src).Kind() == reflect.Ptr {
    50  		val = reflect.ValueOf(src).Elem().FieldByName(path[0])
    51  	} else {
    52  		val = reflect.ValueOf(src).FieldByName(path[0])
    53  	}
    54  	if val.Kind() == reflect.Ptr {
    55  		val = val.Elem()
    56  	}
    57  	if val.Kind() == reflect.Struct {
    58  		return getVal(val.Interface(), path[1:])
    59  	}
    60  	return val
    61  }