github.com/legenove/viper@v1.7.5/parsers.go (about) 1 package viper 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "strings" 9 10 "github.com/hashicorp/hcl" 11 "github.com/hashicorp/hcl/hcl/printer" 12 jsoniter "github.com/json-iterator/go" 13 "github.com/magiconair/properties" 14 "github.com/pelletier/go-toml" 15 "github.com/spf13/afero" 16 "github.com/subosito/gotenv" 17 "gopkg.in/ini.v1" 18 "gopkg.in/yaml.v3" 19 ) 20 21 var SupportedParsers map[string]Parser 22 var SupportedExts map[string][]string 23 24 type Parser interface { 25 UnmarshalReader(v *Viper, in io.Reader, c map[string]interface{}) error // Unmarshal a Reader into a map. 26 MarshalWriter(v *Viper, f afero.File, c map[string]interface{}) error // Marshal a map into Writer. 27 } 28 29 // add support parser 30 func AddParser(parser Parser, names ...string) { 31 for _, n := range names { 32 SupportedParsers[n] = parser 33 SupportedExts[n] = names 34 } 35 } 36 37 func parserInit() { 38 SupportedParsers = make(map[string]Parser, 32) 39 SupportedExts = make(map[string][]string, 32) 40 AddParser(&JSONParser{}, "json") 41 AddParser(&TOMLParser{}, "toml") 42 AddParser(&YAMLParser{}, "yaml", "yml") 43 AddParser(&PROPSParser{}, "properties", "props", "prop") 44 AddParser(&HCLParser{}, "hcl") 45 AddParser(&DOTENVParser{}, "dotenv", "env") 46 AddParser(&INIParser{}, "ini") 47 } 48 49 func parserReset() { 50 parserInit() 51 } 52 53 // json parser 54 type JSONParser struct { 55 } 56 57 func (pp *JSONParser) UnmarshalReader(v *Viper, in io.Reader, c map[string]interface{}) error { 58 buf := new(bytes.Buffer) 59 buf.ReadFrom(in) 60 return jsoniter.Unmarshal(buf.Bytes(), &c) 61 } 62 func (pp *JSONParser) MarshalWriter(v *Viper, f afero.File, c map[string]interface{}) error { 63 b, err := json.MarshalIndent(c, "", " ") 64 if err != nil { 65 return err 66 } 67 _, err = f.WriteString(string(b)) 68 return err 69 } 70 71 // toml parser 72 type TOMLParser struct { 73 } 74 75 func (pp *TOMLParser) UnmarshalReader(v *Viper, in io.Reader, c map[string]interface{}) error { 76 buf := new(bytes.Buffer) 77 buf.ReadFrom(in) 78 tree, err := toml.LoadReader(buf) 79 if err != nil { 80 return err 81 } 82 tmap := tree.ToMap() 83 for k, v := range tmap { 84 c[k] = v 85 } 86 return nil 87 } 88 func (pp *TOMLParser) MarshalWriter(v *Viper, f afero.File, c map[string]interface{}) error { 89 t, err := toml.TreeFromMap(c) 90 if err != nil { 91 return err 92 } 93 s := t.String() 94 if _, err := f.WriteString(s); err != nil { 95 return err 96 } 97 return nil 98 } 99 100 // yaml parser 101 type YAMLParser struct { 102 } 103 104 func (pp *YAMLParser) UnmarshalReader(v *Viper, in io.Reader, c map[string]interface{}) error { 105 buf := new(bytes.Buffer) 106 buf.ReadFrom(in) 107 return yaml.Unmarshal(buf.Bytes(), &c) 108 } 109 func (pp *YAMLParser) MarshalWriter(v *Viper, f afero.File, c map[string]interface{}) error { 110 b, err := yaml.Marshal(c) 111 if err != nil { 112 return err 113 } 114 if _, err = f.WriteString(string(b)); err != nil { 115 return err 116 } 117 return nil 118 } 119 120 // ini parser 121 type INIParser struct { 122 } 123 124 func (pp *INIParser) UnmarshalReader(v *Viper, in io.Reader, c map[string]interface{}) error { 125 buf := new(bytes.Buffer) 126 buf.ReadFrom(in) 127 cfg := ini.Empty() 128 err := cfg.Append(buf.Bytes()) 129 if err != nil { 130 return err 131 } 132 sections := cfg.Sections() 133 for i := 0; i < len(sections); i++ { 134 section := sections[i] 135 keys := section.Keys() 136 for j := 0; j < len(keys); j++ { 137 key := keys[j] 138 value := cfg.Section(section.Name()).Key(key.Name()).String() 139 c[section.Name()+"."+key.Name()] = value 140 } 141 } 142 return nil 143 } 144 func (pp *INIParser) MarshalWriter(v *Viper, f afero.File, c map[string]interface{}) error { 145 keys := v.AllKeys() 146 cfg := ini.Empty() 147 ini.PrettyFormat = false 148 for i := 0; i < len(keys); i++ { 149 key := keys[i] 150 lastSep := strings.LastIndex(key, ".") 151 sectionName := key[:(lastSep)] 152 keyName := key[(lastSep + 1):] 153 if sectionName == "default" { 154 sectionName = "" 155 } 156 cfg.Section(sectionName).Key(keyName).SetValue(v.Get(key).(string)) 157 } 158 cfg.WriteTo(f) 159 return nil 160 } 161 162 // hcl parser 163 type HCLParser struct { 164 } 165 166 func (pp *HCLParser) UnmarshalReader(v *Viper, in io.Reader, c map[string]interface{}) error { 167 buf := new(bytes.Buffer) 168 buf.ReadFrom(in) 169 170 obj, err := hcl.Parse(buf.String()) 171 if err != nil { 172 return err 173 } 174 if err = hcl.DecodeObject(&c, obj); err != nil { 175 return err 176 } 177 return nil 178 } 179 func (pp *HCLParser) MarshalWriter(v *Viper, f afero.File, c map[string]interface{}) error { 180 b, err := json.Marshal(c) 181 if err != nil { 182 return err 183 } 184 ast, err := hcl.Parse(string(b)) 185 if err != nil { 186 return err 187 } 188 err = printer.Fprint(f, ast.Node) 189 if err != nil { 190 return err 191 } 192 return nil 193 } 194 195 // dot env parser 196 type DOTENVParser struct { 197 } 198 199 func (pp *DOTENVParser) UnmarshalReader(v *Viper, in io.Reader, c map[string]interface{}) error { 200 buf := new(bytes.Buffer) 201 buf.ReadFrom(in) 202 203 env, err := gotenv.StrictParse(buf) 204 if err != nil { 205 return err 206 } 207 for k, v := range env { 208 c[k] = v 209 } 210 211 return nil 212 } 213 func (pp *DOTENVParser) MarshalWriter(v *Viper, f afero.File, c map[string]interface{}) error { 214 lines := []string{} 215 for _, key := range v.AllKeys() { 216 envName := strings.ToUpper(strings.Replace(key, ".", "_", -1)) 217 val := v.Get(key) 218 lines = append(lines, fmt.Sprintf("%v=%v", envName, val)) 219 } 220 s := strings.Join(lines, "\n") 221 if _, err := f.WriteString(s); err != nil { 222 return err 223 } 224 return nil 225 } 226 227 // props parser 228 type PROPSParser struct { 229 } 230 231 func (pp *PROPSParser) UnmarshalReader(v *Viper, in io.Reader, c map[string]interface{}) error { 232 buf := new(bytes.Buffer) 233 buf.ReadFrom(in) 234 235 v.properties = properties.NewProperties() 236 var err error 237 if v.properties, err = properties.Load(buf.Bytes(), properties.UTF8); err != nil { 238 return ConfigParseError{err} 239 } 240 for _, key := range v.properties.Keys() { 241 value, _ := v.properties.Get(key) 242 // recursively build nested maps 243 path := strings.Split(key, ".") 244 lastKey := strings.ToLower(path[len(path)-1]) 245 deepestMap := deepSearch(c, path[0:len(path)-1]) 246 // set innermost value 247 deepestMap[lastKey] = value 248 } 249 return nil 250 } 251 func (pp *PROPSParser) MarshalWriter(v *Viper, f afero.File, c map[string]interface{}) error { 252 if v.properties == nil { 253 v.properties = properties.NewProperties() 254 } 255 p := v.properties 256 for _, key := range v.AllKeys() { 257 _, _, err := p.Set(key, v.GetString(key)) 258 if err != nil { 259 return err 260 } 261 } 262 _, err := p.WriteComment(f, "#", properties.UTF8) 263 if err != nil { 264 return err 265 } 266 return nil 267 }