...

Source file src/github.com/spf13/viper/internal/encoding/ini/codec.go

Documentation: github.com/spf13/viper/internal/encoding/ini

     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]any) ([]byte, error) {
    23  	cfg := ini.Empty()
    24  	ini.PrettyFormat = false
    25  
    26  	flattened := map[string]any{}
    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]any) 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  }
   100  

View as plain text