55 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			55 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"os"
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // EnvOptions holds program options loaded from the process environment
 | |
| type EnvOptions map[string]interface{}
 | |
| 
 | |
| // LoadEnvForStruct loads environment variables for each field in an options
 | |
| // struct passed into it.
 | |
| //
 | |
| // Fields in the options struct must have an `env` and `cfg` tag to be read
 | |
| // from the environment
 | |
| func (cfg EnvOptions) LoadEnvForStruct(options interface{}) {
 | |
| 	val := reflect.ValueOf(options)
 | |
| 	var typ reflect.Type
 | |
| 	if val.Kind() == reflect.Ptr {
 | |
| 		typ = val.Elem().Type()
 | |
| 	} else {
 | |
| 		typ = val.Type()
 | |
| 	}
 | |
| 
 | |
| 	for i := 0; i < typ.NumField(); i++ {
 | |
| 		// pull out the struct tags:
 | |
| 		//    flag - the name of the command line flag
 | |
| 		//    deprecated - (optional) the name of the deprecated command line flag
 | |
| 		//    cfg - (optional, defaults to underscored flag) the name of the config file option
 | |
| 		field := typ.Field(i)
 | |
| 		fieldV := reflect.Indirect(val).Field(i)
 | |
| 
 | |
| 		if field.Type.Kind() == reflect.Struct {
 | |
| 			cfg.LoadEnvForStruct(fieldV.Interface())
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		flagName := field.Tag.Get("flag")
 | |
| 		envName := field.Tag.Get("env")
 | |
| 		cfgName := field.Tag.Get("cfg")
 | |
| 		if cfgName == "" && flagName != "" {
 | |
| 			cfgName = strings.ReplaceAll(flagName, "-", "_")
 | |
| 		}
 | |
| 		if envName == "" || cfgName == "" {
 | |
| 			// resolvable fields must have the `env` and `cfg` struct tag
 | |
| 			continue
 | |
| 		}
 | |
| 		v := os.Getenv(envName)
 | |
| 		if v != "" {
 | |
| 			cfg[cfgName] = v
 | |
| 		}
 | |
| 	}
 | |
| }
 |