2016-02-09 14:32:36 +00:00
|
|
|
// Package userConfig eases the use of config files in a user's home directory
|
|
|
|
package userConfig
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2017-03-01 12:58:34 +00:00
|
|
|
"encoding/json"
|
2016-02-09 14:32:36 +00:00
|
|
|
"errors"
|
|
|
|
"io/ioutil"
|
2017-07-28 12:21:40 +00:00
|
|
|
"os"
|
2017-02-04 22:14:19 +00:00
|
|
|
"strconv"
|
2016-02-09 14:32:36 +00:00
|
|
|
"strings"
|
2017-02-04 22:14:19 +00:00
|
|
|
"time"
|
2016-02-09 14:32:36 +00:00
|
|
|
|
|
|
|
"github.com/BurntSushi/toml"
|
|
|
|
)
|
|
|
|
|
|
|
|
// GeneralConfig is the basic config structure
|
|
|
|
// All configs make with package userConfig will have this file
|
|
|
|
type GeneralConfig struct {
|
|
|
|
Name string `toml:"-"`
|
|
|
|
Path string `toml:"-"`
|
|
|
|
ConfigFiles []string `toml:"additional_config"`
|
|
|
|
RawFiles []string `toml:"raw_files"`
|
|
|
|
Values map[string]string `toml:"general"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewGeneralConfig generates a General Config struct
|
|
|
|
func NewGeneralConfig(name, path string) (*GeneralConfig, error) {
|
|
|
|
gf := &GeneralConfig{Name: name, Path: path}
|
|
|
|
gf.ConfigFiles = []string{}
|
|
|
|
gf.RawFiles = []string{}
|
|
|
|
gf.Values = make(map[string]string)
|
|
|
|
|
|
|
|
if err := gf.Load(); err != nil {
|
|
|
|
return gf, err
|
|
|
|
}
|
|
|
|
return gf, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load loads config files into the config
|
|
|
|
func (gf *GeneralConfig) Load() error {
|
|
|
|
if strings.TrimSpace(gf.Name) == "" || strings.TrimSpace(gf.Path) == "" {
|
2017-03-01 14:04:29 +00:00
|
|
|
return errors.New("Invalid ConfigFile Name: " + gf.Path + string(os.PathSeparator) + gf.Name)
|
2016-02-09 14:32:36 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 13:45:16 +00:00
|
|
|
// Config files end with .conf
|
|
|
|
cfgPath := gf.Path + string(os.PathSeparator) + gf.Name + ".conf"
|
2016-02-09 14:32:36 +00:00
|
|
|
tomlData, err := ioutil.ReadFile(cfgPath)
|
|
|
|
if err != nil {
|
2017-03-01 14:04:29 +00:00
|
|
|
// Couldn't find the file, save a new one
|
|
|
|
if err = gf.Save(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-02-09 14:32:36 +00:00
|
|
|
}
|
|
|
|
if _, err := toml.Decode(string(tomlData), &gf); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save writes the config to file(s)
|
|
|
|
func (gf *GeneralConfig) Save() error {
|
|
|
|
buf := new(bytes.Buffer)
|
2017-09-14 13:45:16 +00:00
|
|
|
cfgPath := gf.Path + string(os.PathSeparator) + gf.Name + ".conf"
|
2016-02-09 14:32:36 +00:00
|
|
|
if err := toml.NewEncoder(buf).Encode(gf); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return ioutil.WriteFile(cfgPath, buf.Bytes(), 0644)
|
|
|
|
}
|
|
|
|
|
2017-02-04 22:14:19 +00:00
|
|
|
// GetKeyList returns a list of all keys in the config file
|
|
|
|
func (gf *GeneralConfig) GetKeyList() []string {
|
|
|
|
var ret []string
|
|
|
|
for k, _ := range gf.Values {
|
|
|
|
ret = append(ret, k)
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2016-02-09 14:32:36 +00:00
|
|
|
// Set sets a key/value pair in gf, if unable to save, revert to old value
|
|
|
|
// (and return the error)
|
|
|
|
func (gf *GeneralConfig) Set(k, v string) error {
|
|
|
|
oldVal := gf.Values[k]
|
|
|
|
gf.Values[k] = v
|
|
|
|
if err := gf.Save(); err != nil {
|
|
|
|
gf.Values[k] = oldVal
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-09-14 13:45:16 +00:00
|
|
|
// SetBytes at the config level sets a value in the <c.name>.conf file
|
2017-02-04 22:14:19 +00:00
|
|
|
func (gf *GeneralConfig) SetBytes(k string, v []byte) error {
|
|
|
|
return gf.Set(k, string(v))
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetInt sets an integer value (as a string) in the config file
|
|
|
|
func (gf *GeneralConfig) SetInt(k string, v int) error {
|
|
|
|
return gf.Set(k, strconv.Itoa(v))
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetDateTime sets a DateTime value (as a string) in the config file
|
|
|
|
func (gf *GeneralConfig) SetDateTime(k string, v time.Time) error {
|
|
|
|
return gf.Set(k, v.Format(time.RFC3339))
|
|
|
|
}
|
|
|
|
|
2017-03-01 12:58:34 +00:00
|
|
|
// SetArray sets a string slice value (as a string) in the config file
|
|
|
|
func (gf *GeneralConfig) SetArray(k string, v []string) error {
|
|
|
|
b, e := json.Marshal(v)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
return gf.SetBytes(k, b)
|
|
|
|
}
|
|
|
|
|
2016-02-09 14:32:36 +00:00
|
|
|
// Get gets a key/value pair from gf
|
|
|
|
func (gf *GeneralConfig) Get(k string) string {
|
|
|
|
return gf.Values[k]
|
2017-02-04 22:14:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetInt gets a key/value pair from gf and return it as an integer
|
|
|
|
// An error if it can't be converted
|
|
|
|
func (gf *GeneralConfig) GetInt(k string) (int, error) {
|
|
|
|
return strconv.Atoi(gf.Get(k))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDateTime gets a key/value pair from gf and returns it as a time.Time
|
|
|
|
// An error if it can't be converted
|
|
|
|
func (gf *GeneralConfig) GetDateTime(k string) (time.Time, error) {
|
2017-03-01 12:58:34 +00:00
|
|
|
return time.Parse(time.RFC3339, gf.Get(k))
|
2017-02-04 22:14:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetBytes gets a key/value pair from gf and returns it as a byte slice
|
|
|
|
// Or an error if it fails for whatever reason
|
|
|
|
func (gf *GeneralConfig) GetBytes(k string) []byte {
|
|
|
|
return []byte(gf.Get(k))
|
|
|
|
}
|
|
|
|
|
2017-03-01 12:58:34 +00:00
|
|
|
func (gf *GeneralConfig) GetArray(k string) ([]string, error) {
|
|
|
|
var ret []string
|
|
|
|
err := json.Unmarshal(gf.GetBytes(k), &ret)
|
|
|
|
return ret, err
|
|
|
|
}
|
|
|
|
|
2017-02-04 22:14:19 +00:00
|
|
|
// DeleteKey removes a key from the file
|
2017-03-01 12:58:34 +00:00
|
|
|
func (gf *GeneralConfig) DeleteKey(k string) error {
|
|
|
|
oldVal := gf.Get(k)
|
2017-02-04 22:14:19 +00:00
|
|
|
delete(gf.Values, k)
|
2017-03-01 12:58:34 +00:00
|
|
|
if err := gf.Save(); err != nil {
|
|
|
|
gf.Values[k] = oldVal
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2017-02-04 22:14:19 +00:00
|
|
|
}
|