ReadConfigMap reads the configuration from the environment and the passed in data map. Config and defaults are supposed to be pointers to structs of the same type
(target interface{}, defaults interface{}, data map[string]string)
| 65 | // ReadConfigMap reads the configuration from the environment and the passed in data map. |
| 66 | // Config and defaults are supposed to be pointers to structs of the same type |
| 67 | func ReadConfigMap(target interface{}, defaults interface{}, data map[string]string) { //nolint: gocognit |
| 68 | ensurePointerToCompatibleStruct("target", target, "default", defaults) |
| 69 | |
| 70 | count := reflect.TypeOf(defaults).Elem().NumField() |
| 71 | for i := 0; i < count; i++ { |
| 72 | field := reflect.TypeOf(defaults).Elem().Field(i) |
| 73 | envName := field.Tag.Get("env") |
| 74 | |
| 75 | // Fields without env tag are skipped. |
| 76 | if envName == "" { |
| 77 | continue |
| 78 | } |
| 79 | |
| 80 | // Initialize value with default |
| 81 | var value string |
| 82 | var sliceValue []string |
| 83 | |
| 84 | valueField := reflect.ValueOf(defaults).Elem().FieldByName(field.Name) |
| 85 | switch valueField.Kind() { |
| 86 | case reflect.Bool: |
| 87 | value = strconv.FormatBool(valueField.Bool()) |
| 88 | |
| 89 | case reflect.Int: |
| 90 | value = fmt.Sprintf("%v", valueField.Int()) |
| 91 | |
| 92 | case reflect.Pointer: |
| 93 | // Handle pointer types - if not nil, get the underlying value |
| 94 | if !valueField.IsNil() { |
| 95 | switch valueField.Elem().Kind() { |
| 96 | case reflect.Int: |
| 97 | value = fmt.Sprintf("%v", valueField.Elem().Int()) |
| 98 | default: |
| 99 | configparserLog.Info( |
| 100 | "Skipping unsupported pointer type while parsing default configuration", |
| 101 | "field", field.Name, "kind", valueField.Elem().Kind()) |
| 102 | continue |
| 103 | } |
| 104 | } |
| 105 | // If nil, value stays empty, which means we'll only set it if env/data provides a value |
| 106 | |
| 107 | case reflect.Slice: |
| 108 | if valueField.Type().Elem().Kind() != reflect.String { |
| 109 | configparserLog.Info( |
| 110 | "Skipping invalid slice type while parsing default configuration", |
| 111 | "field", field.Name, "value", value) |
| 112 | } else { |
| 113 | sliceValue = valueField.Interface().([]string) |
| 114 | } |
| 115 | |
| 116 | default: |
| 117 | value = valueField.String() |
| 118 | } |
| 119 | // If the key is present in the environment, use its value |
| 120 | if envValue := os.Getenv(envName); envValue != "" { |
| 121 | value = envValue |
| 122 | } |
| 123 | // If the key is present in the passed data, use its value |
| 124 | if mapValue, ok := data[envName]; ok { |