serialize.go 2.5 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3
package config

import (
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
4
	"encoding/json"
5
	"fmt"
6
	"io"
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
7
	"os"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8
	"path/filepath"
9
	"strings"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10 11
)

12 13 14
// ReadConfigFile reads the config from `filename` into `cfg`.
func ReadConfigFile(filename string, cfg interface{}) error {
	f, err := os.Open(filename)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
15 16 17
	if err != nil {
		return err
	}
18
	defer f.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
19

20
	return Decode(f, cfg)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
21 22
}

23 24 25
// WriteConfigFile writes the config from `cfg` into `filename`.
func WriteConfigFile(filename string, cfg interface{}) error {
	f, err := os.Create(filename)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
26 27 28
	if err != nil {
		return err
	}
29
	defer f.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
30

31
	return Encode(f, cfg)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
32 33
}

34 35
// WriteFile writes the buffer at filename
func WriteFile(filename string, buf []byte) error {
36
	err := os.MkdirAll(filepath.Dir(filename), 0775)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
37 38 39 40
	if err != nil {
		return err
	}

41
	f, err := os.Create(filename)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
42 43 44
	if err != nil {
		return err
	}
45
	defer f.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
46

47 48
	_, err = f.Write(buf)
	return err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
49
}
50

51 52 53 54
// Encode configuration with JSON
func Encode(w io.Writer, value interface{}) error {
	// need to prettyprint, hence MarshalIndent, instead of Encoder
	buf, err := json.MarshalIndent(value, "", "  ")
55
	if err != nil {
56
		return err
57 58
	}

59 60 61
	_, err = w.Write(buf)
	return err
}
62

63 64 65 66 67 68 69 70 71 72
// Decode configuration with JSON
func Decode(r io.Reader, value interface{}) error {
	return json.NewDecoder(r).Decode(value)
}

// ReadConfigKey retrieves only the value of a particular key
func ReadConfigKey(filename, key string) (interface{}, error) {
	var cfg interface{}
	if err := ReadConfigFile(filename, &cfg); err != nil {
		return nil, err
73 74
	}

75 76 77 78 79 80 81 82
	var ok bool
	cursor := cfg
	parts := strings.Split(key, ".")
	for i, part := range parts {
		cursor, ok = cursor.(map[string]interface{})[part]
		if !ok {
			sofar := strings.Join(parts[:i], ".")
			return nil, fmt.Errorf("%s key has no attributes", sofar)
83 84
		}
	}
85
	return cursor, nil
86 87
}

88 89 90 91
// WriteConfigKey writes the value of a particular key
func WriteConfigKey(filename, key string, value interface{}) error {
	var cfg interface{}
	if err := ReadConfigFile(filename, &cfg); err != nil {
92 93 94
		return err
	}

95 96 97
	var ok bool
	var mcursor map[string]interface{}
	cursor := cfg
98

99 100 101 102 103 104 105
	parts := strings.Split(key, ".")
	for i, part := range parts {
		mcursor, ok = cursor.(map[string]interface{})
		if !ok {
			sofar := strings.Join(parts[:i], ".")
			return fmt.Errorf("%s key is not a map", sofar)
		}
106

107 108 109 110
		// last part? set here
		if i == (len(parts) - 1) {
			mcursor[part] = value
			break
111
		}
112 113 114 115 116

		cursor, ok = mcursor[part]
		if !ok { // create map if this is empty
			mcursor[part] = map[string]interface{}{}
			cursor = mcursor[part]
117 118
		}
	}
119 120

	return WriteConfigFile(filename, cfg)
121
}