serialize.go 2.58 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
// WriteConfigFile writes the config from `cfg` into `filename`.
func WriteConfigFile(filename string, cfg interface{}) error {
25 26 27 28 29
	err := os.MkdirAll(filepath.Dir(filename), 0775)
	if err != nil {
		return err
	}

30
	f, err := os.Create(filename)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
31 32 33
	if err != nil {
		return err
	}
34
	defer f.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35

36
	return Encode(f, cfg)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
37 38
}

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

46
	f, err := os.Create(filename)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
47 48 49
	if err != nil {
		return err
	}
50
	defer f.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
51

52 53
	_, err = f.Write(buf)
	return err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
54
}
55

56 57 58 59
// 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, "", "  ")
60
	if err != nil {
61
		return err
62 63
	}

64 65 66
	_, err = w.Write(buf)
	return err
}
67

68 69 70 71 72 73 74 75 76 77
// 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
78 79
	}

80 81 82 83 84 85 86 87
	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)
88 89
		}
	}
90
	return cursor, nil
91 92
}

93 94 95 96
// 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 {
97 98 99
		return err
	}

100 101 102
	var ok bool
	var mcursor map[string]interface{}
	cursor := cfg
103

104 105 106 107 108 109 110
	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)
		}
111

112 113 114 115
		// last part? set here
		if i == (len(parts) - 1) {
			mcursor[part] = value
			break
116
		}
117 118 119 120 121

		cursor, ok = mcursor[part]
		if !ok { // create map if this is empty
			mcursor[part] = map[string]interface{}{}
			cursor = mcursor[part]
122 123
		}
	}
124 125

	return WriteConfigFile(filename, cfg)
126
}