vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go
changeset 260 445e01aede7e
equal deleted inserted replaced
259:db4911b0c721 260:445e01aede7e
       
     1 package javaproperties
       
     2 
       
     3 import (
       
     4 	"bytes"
       
     5 	"sort"
       
     6 	"strings"
       
     7 
       
     8 	"github.com/magiconair/properties"
       
     9 	"github.com/spf13/cast"
       
    10 )
       
    11 
       
    12 // Codec implements the encoding.Encoder and encoding.Decoder interfaces for Java properties encoding.
       
    13 type Codec struct {
       
    14 	KeyDelimiter string
       
    15 
       
    16 	// Store read properties on the object so that we can write back in order with comments.
       
    17 	// This will only be used if the configuration read is a properties file.
       
    18 	// TODO: drop this feature in v2
       
    19 	// TODO: make use of the global properties object optional
       
    20 	Properties *properties.Properties
       
    21 }
       
    22 
       
    23 func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) {
       
    24 	if c.Properties == nil {
       
    25 		c.Properties = properties.NewProperties()
       
    26 	}
       
    27 
       
    28 	flattened := map[string]interface{}{}
       
    29 
       
    30 	flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
       
    31 
       
    32 	keys := make([]string, 0, len(flattened))
       
    33 
       
    34 	for key := range flattened {
       
    35 		keys = append(keys, key)
       
    36 	}
       
    37 
       
    38 	sort.Strings(keys)
       
    39 
       
    40 	for _, key := range keys {
       
    41 		_, _, err := c.Properties.Set(key, cast.ToString(flattened[key]))
       
    42 		if err != nil {
       
    43 			return nil, err
       
    44 		}
       
    45 	}
       
    46 
       
    47 	var buf bytes.Buffer
       
    48 
       
    49 	_, err := c.Properties.WriteComment(&buf, "#", properties.UTF8)
       
    50 	if err != nil {
       
    51 		return nil, err
       
    52 	}
       
    53 
       
    54 	return buf.Bytes(), nil
       
    55 }
       
    56 
       
    57 func (c *Codec) Decode(b []byte, v map[string]interface{}) error {
       
    58 	var err error
       
    59 	c.Properties, err = properties.Load(b, properties.UTF8)
       
    60 	if err != nil {
       
    61 		return err
       
    62 	}
       
    63 
       
    64 	for _, key := range c.Properties.Keys() {
       
    65 		// ignore existence check: we know it's there
       
    66 		value, _ := c.Properties.Get(key)
       
    67 
       
    68 		// recursively build nested maps
       
    69 		path := strings.Split(key, c.keyDelimiter())
       
    70 		lastKey := strings.ToLower(path[len(path)-1])
       
    71 		deepestMap := deepSearch(v, path[0:len(path)-1])
       
    72 
       
    73 		// set innermost value
       
    74 		deepestMap[lastKey] = value
       
    75 	}
       
    76 
       
    77 	return nil
       
    78 }
       
    79 
       
    80 func (c Codec) keyDelimiter() string {
       
    81 	if c.KeyDelimiter == "" {
       
    82 		return "."
       
    83 	}
       
    84 
       
    85 	return c.KeyDelimiter
       
    86 }