Codebase list golang-github-spf13-viper / 72453f7
feat(encoding): integrate Java properties codec into Viper Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com> Mark Sagi-Kazar authored 2 years ago Márk Sági-Kazár committed 2 years ago
3 changed file(s) with 56 addition(s) and 48 deletion(s). Raw diff Collapse all Expand all
1111 // Codec implements the encoding.Encoder and encoding.Decoder interfaces for Java properties encoding.
1212 type Codec struct {
1313 KeyDelimiter string
14
15 // Store read properties on the object so that we can write back in order with comments.
16 // This will only be used if the configuration read is a properties file.
17 // TODO: drop this feature in v2
18 // TODO: make use of the global properties object optional
19 Properties *properties.Properties
1420 }
1521
16 func (c Codec) Encode(v map[string]interface{}) ([]byte, error) {
17 p := properties.NewProperties()
22 func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) {
23 if c.Properties == nil {
24 c.Properties = properties.NewProperties()
25 }
1826
1927 flattened := map[string]interface{}{}
2028
2937 sort.Strings(keys)
3038
3139 for _, key := range keys {
32 _, _, err := p.Set(key, cast.ToString(flattened[key]))
40 _, _, err := c.Properties.Set(key, cast.ToString(flattened[key]))
3341 if err != nil {
3442 return nil, err
3543 }
3745
3846 var buf bytes.Buffer
3947
40 _, err := p.WriteComment(&buf, "#", properties.UTF8)
48 _, err := c.Properties.WriteComment(&buf, "#", properties.UTF8)
4149 if err != nil {
4250 return nil, err
4351 }
4553 return buf.Bytes(), nil
4654 }
4755
48 func (c Codec) Decode(b []byte, v map[string]interface{}) error {
49 p, err := properties.Load(b, properties.UTF8)
56 func (c *Codec) Decode(b []byte, v map[string]interface{}) error {
57 var err error
58 c.Properties, err = properties.Load(b, properties.UTF8)
5059 if err != nil {
5160 return err
5261 }
5362
54 for _, key := range p.Keys() {
63 for _, key := range c.Properties.Keys() {
5564 // ignore existence check: we know it's there
56 value, _ := p.Get(key)
65 value, _ := c.Properties.Get(key)
5766
5867 // recursively build nested maps
5968 path := strings.Split(key, c.keyDelimiter())
55 )
66
77 // original form of the data
8 const original = `# key-value pair
8 const original = `#key-value pair
99 key = value
1010 map.key = value
1111 `
6666 }
6767 })
6868 }
69
70 func TestCodec_DecodeEncode(t *testing.T) {
71 codec := Codec{}
72
73 v := map[string]interface{}{}
74
75 err := codec.Decode([]byte(original), v)
76 if err != nil {
77 t.Fatal(err)
78 }
79
80 b, err := codec.Encode(data)
81 if err != nil {
82 t.Fatal(err)
83 }
84
85 if original != string(b) {
86 t.Fatalf("encoded value does not match the original\nactual: %#v\nexpected: %#v", string(b), original)
87 }
88 }
3434 "time"
3535
3636 "github.com/fsnotify/fsnotify"
37 "github.com/magiconair/properties"
3837 "github.com/mitchellh/mapstructure"
3938 "github.com/spf13/afero"
4039 "github.com/spf13/cast"
4443 "github.com/spf13/viper/internal/encoding"
4544 "github.com/spf13/viper/internal/encoding/hcl"
4645 "github.com/spf13/viper/internal/encoding/ini"
46 "github.com/spf13/viper/internal/encoding/javaproperties"
4747 "github.com/spf13/viper/internal/encoding/json"
4848 "github.com/spf13/viper/internal/encoding/toml"
4949 "github.com/spf13/viper/internal/encoding/yaml"
214214 aliases map[string]string
215215 typeByDefValue bool
216216
217 // Store read properties on the object so that we can write back in order with comments.
218 // This will only be used if the configuration read is a properties file.
219 properties *properties.Properties
220
221217 onConfigChange func(fsnotify.Event)
222218
223219 logger Logger
353349
354350 encoderRegistry.RegisterEncoder("ini", codec)
355351 decoderRegistry.RegisterDecoder("ini", codec)
352 }
353
354 {
355 codec := &javaproperties.Codec{
356 KeyDelimiter: v.keyDelim,
357 }
358
359 encoderRegistry.RegisterEncoder("properties", codec)
360 decoderRegistry.RegisterDecoder("properties", codec)
361
362 encoderRegistry.RegisterEncoder("props", codec)
363 decoderRegistry.RegisterDecoder("props", codec)
364
365 encoderRegistry.RegisterEncoder("prop", codec)
366 decoderRegistry.RegisterDecoder("prop", codec)
356367 }
357368
358369 v.encoderRegistry = encoderRegistry
16551666 buf.ReadFrom(in)
16561667
16571668 switch format := strings.ToLower(v.getConfigType()); format {
1658 case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini":
1669 case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "properties", "props", "prop":
16591670 err := v.decoderRegistry.Decode(format, buf.Bytes(), c)
16601671 if err != nil {
16611672 return ConfigParseError{err}
16691680 for k, v := range env {
16701681 c[k] = v
16711682 }
1672
1673 case "properties", "props", "prop":
1674 v.properties = properties.NewProperties()
1675 var err error
1676 if v.properties, err = properties.Load(buf.Bytes(), properties.UTF8); err != nil {
1677 return ConfigParseError{err}
1678 }
1679 for _, key := range v.properties.Keys() {
1680 value, _ := v.properties.Get(key)
1681 // recursively build nested maps
1682 path := strings.Split(key, ".")
1683 lastKey := strings.ToLower(path[len(path)-1])
1684 deepestMap := deepSearch(c, path[0:len(path)-1])
1685 // set innermost value
1686 deepestMap[lastKey] = value
1687 }
16881683 }
16891684
16901685 insensitiviseMap(c)
16951690 func (v *Viper) marshalWriter(f afero.File, configType string) error {
16961691 c := v.AllSettings()
16971692 switch configType {
1698 case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini":
1693 case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "prop", "props", "properties":
16991694 b, err := v.encoderRegistry.Encode(configType, c)
17001695 if err != nil {
17011696 return ConfigMarshalError{err}
17021697 }
17031698
17041699 _, err = f.WriteString(string(b))
1705 if err != nil {
1706 return ConfigMarshalError{err}
1707 }
1708
1709 case "prop", "props", "properties":
1710 if v.properties == nil {
1711 v.properties = properties.NewProperties()
1712 }
1713 p := v.properties
1714 for _, key := range v.AllKeys() {
1715 _, _, err := p.Set(key, v.GetString(key))
1716 if err != nil {
1717 return ConfigMarshalError{err}
1718 }
1719 }
1720 _, err := p.WriteComment(f, "#", properties.UTF8)
17211700 if err != nil {
17221701 return ConfigMarshalError{err}
17231702 }