vendor/github.com/spf13/viper/internal/encoding/ini/codec.go
changeset 260 445e01aede7e
equal deleted inserted replaced
259:db4911b0c721 260:445e01aede7e
       
     1 package ini
       
     2 
       
     3 import (
       
     4 	"bytes"
       
     5 	"sort"
       
     6 	"strings"
       
     7 
       
     8 	"github.com/spf13/cast"
       
     9 	"gopkg.in/ini.v1"
       
    10 )
       
    11 
       
    12 // LoadOptions contains all customized options used for load data source(s).
       
    13 // This type is added here for convenience: this way consumers can import a single package called "ini".
       
    14 type LoadOptions = ini.LoadOptions
       
    15 
       
    16 // Codec implements the encoding.Encoder and encoding.Decoder interfaces for INI encoding.
       
    17 type Codec struct {
       
    18 	KeyDelimiter string
       
    19 	LoadOptions  LoadOptions
       
    20 }
       
    21 
       
    22 func (c Codec) Encode(v map[string]interface{}) ([]byte, error) {
       
    23 	cfg := ini.Empty()
       
    24 	ini.PrettyFormat = false
       
    25 
       
    26 	flattened := map[string]interface{}{}
       
    27 
       
    28 	flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
       
    29 
       
    30 	keys := make([]string, 0, len(flattened))
       
    31 
       
    32 	for key := range flattened {
       
    33 		keys = append(keys, key)
       
    34 	}
       
    35 
       
    36 	sort.Strings(keys)
       
    37 
       
    38 	for _, key := range keys {
       
    39 		sectionName, keyName := "", key
       
    40 
       
    41 		lastSep := strings.LastIndex(key, ".")
       
    42 		if lastSep != -1 {
       
    43 			sectionName = key[:(lastSep)]
       
    44 			keyName = key[(lastSep + 1):]
       
    45 		}
       
    46 
       
    47 		// TODO: is this a good idea?
       
    48 		if sectionName == "default" {
       
    49 			sectionName = ""
       
    50 		}
       
    51 
       
    52 		cfg.Section(sectionName).Key(keyName).SetValue(cast.ToString(flattened[key]))
       
    53 	}
       
    54 
       
    55 	var buf bytes.Buffer
       
    56 
       
    57 	_, err := cfg.WriteTo(&buf)
       
    58 	if err != nil {
       
    59 		return nil, err
       
    60 	}
       
    61 
       
    62 	return buf.Bytes(), nil
       
    63 }
       
    64 
       
    65 func (c Codec) Decode(b []byte, v map[string]interface{}) error {
       
    66 	cfg := ini.Empty(c.LoadOptions)
       
    67 
       
    68 	err := cfg.Append(b)
       
    69 	if err != nil {
       
    70 		return err
       
    71 	}
       
    72 
       
    73 	sections := cfg.Sections()
       
    74 
       
    75 	for i := 0; i < len(sections); i++ {
       
    76 		section := sections[i]
       
    77 		keys := section.Keys()
       
    78 
       
    79 		for j := 0; j < len(keys); j++ {
       
    80 			key := keys[j]
       
    81 			value := cfg.Section(section.Name()).Key(key.Name()).String()
       
    82 
       
    83 			deepestMap := deepSearch(v, strings.Split(section.Name(), c.keyDelimiter()))
       
    84 
       
    85 			// set innermost value
       
    86 			deepestMap[key.Name()] = value
       
    87 		}
       
    88 	}
       
    89 
       
    90 	return nil
       
    91 }
       
    92 
       
    93 func (c Codec) keyDelimiter() string {
       
    94 	if c.KeyDelimiter == "" {
       
    95 		return "."
       
    96 	}
       
    97 
       
    98 	return c.KeyDelimiter
       
    99 }