This commit is contained in:
Herkermer Sherwood 2017-02-18 03:13:25 +00:00 committed by GitHub
commit d41277840c
2 changed files with 129 additions and 2 deletions

53
util.go
View file

@ -21,12 +21,14 @@ import (
"strings"
"unicode"
yaml "gopkg.in/yaml.v2"
"github.com/hashicorp/hcl"
"github.com/magiconair/properties"
toml "github.com/pelletier/go-toml"
"github.com/spf13/afero"
"github.com/spf13/cast"
jww "github.com/spf13/jwalterweatherman"
"gopkg.in/yaml.v2"
)
// ConfigParseError denotes failing to parse configuration file.
@ -39,6 +41,16 @@ func (pe ConfigParseError) Error() string {
return fmt.Sprintf("While parsing config: %s", pe.err.Error())
}
// ConfigMarshalError happens when failing to marshal the configuration.
type ConfigMarshalError struct {
err error
}
// Error returns the formatted configuration error.
func (e ConfigMarshalError) Error() string {
return fmt.Sprintf("While marshaling config: %s", e.err.Error())
}
// toCaseInsensitiveValue checks if the value is a map;
// if so, create a copy and lower-case the keys recursively.
func toCaseInsensitiveValue(value interface{}) interface{} {
@ -152,6 +164,45 @@ func userHomeDir() string {
return os.Getenv("HOME")
}
func marshalConfigWriter(f afero.File, c map[string]interface{}, configType string) error {
switch configType {
case "json":
b, err := json.MarshalIndent(v.AllSettings(), "", " ")
if err != nil {
return ConfigMarshalError{err}
}
_, err = f.WriteString(string(b))
if err != nil {
return ConfigMarshalError{err}
}
case "hcl":
// TODO: How to convert map to hcl???
case "prop", "props", "properties":
case "toml":
t := toml.TreeFromMap(v.AllSettings())
s := t.String()
_, err := f.WriteString(s)
if err != nil {
return ConfigMarshalError{err}
}
case "yaml", "yml":
b, err := yaml.Marshal(v.AllSettings())
if err != nil {
return ConfigMarshalError{err}
}
_, err = f.WriteString(string(b))
if err != nil {
return ConfigMarshalError{err}
}
}
return nil
}
func unmarshallConfigReader(in io.Reader, c map[string]interface{}, configType string) error {
buf := new(bytes.Buffer)
buf.ReadFrom(in)

View file

@ -30,12 +30,12 @@ import (
"strings"
"time"
"github.com/fsnotify/fsnotify"
"github.com/mitchellh/mapstructure"
"github.com/spf13/afero"
"github.com/spf13/cast"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/pflag"
"gopkg.in/fsnotify.v1"
)
var v *Viper
@ -1147,6 +1147,73 @@ func (v *Viper) MergeConfig(in io.Reader) error {
return nil
}
func writeConfig(filename string, force bool) error { return v.writeConfig(filename, force) }
func (v *Viper) writeConfig(filename string, force bool) error {
jww.INFO.Println("Attempting to write configuration to file.")
ext := filepath.Ext(filename)
if len(ext) <= 1 {
return fmt.Errorf("Filename: %s requires valid extension.", filename)
}
configType := ext[1:]
if !stringInSlice(configType, SupportedExts) {
return UnsupportedConfigError(configType)
}
if v.config == nil {
v.config = make(map[string]interface{})
}
var flags int
if force == true {
flags = os.O_CREATE | os.O_WRONLY
} else {
if _, err := os.Stat(filename); os.IsNotExist(err) {
flags = os.O_WRONLY
} else {
return fmt.Errorf("File: %s exists. Use WriteConfig to overwrite.", filename)
}
}
f, err := v.fs.OpenFile(filename, flags, os.FileMode(0644))
if err != nil {
return err
}
return v.marshalWriter(f, v.config, configType)
}
// WriteConfig writes the current configuration to a file.
func WriteConfig() error { return v.WriteConfig() }
func (v *Viper) WriteConfig() error {
filename, err := v.getConfigFile()
if err != nil {
return err
}
return v.writeConfig(filename, true)
}
// SafeWriteConfig writes current configuration to file only if the file does not exist.
func SafeWriteConfig() error { return v.SafeWriteConfig() }
func (v *Viper) SafeWriteConfig() error {
filename, err := v.getConfigFile()
if err != nil {
return err
}
return v.writeConfig(filename, false)
}
// WriteConfigAs writes current configuration to a given filename.
func WriteConfigAs(filename string) error { return v.WriteConfigAs(filename) }
func (v *Viper) WriteConfigAs(filename string) error {
return v.writeConfig(filename, true)
}
// SafeWriteConfigAs writes current configuration to a given filename is it does not exist.
func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) }
func (v *Viper) SafeWriteConfigAs(filename string) error {
return v.writeConfig(filename, false)
}
// WriteConfigKey writes given key and value to file.
// WriteConfigKeyAs writes given key and value to a given filename.
func keyExists(k string, m map[string]interface{}) string {
lk := strings.ToLower(k)
for mk := range m {
@ -1265,6 +1332,15 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
return unmarshallConfigReader(in, c, v.getConfigType())
}
// Marshal a map into Writer.
func marshalWriter(out afero.File, c map[string]interface{}, configType string) error {
return v.marshalWriter(out, c, configType)
}
func (v *Viper) marshalWriter(out afero.File, c map[string]interface{}, configType string) error {
return marshalConfigWriter(out, c, configType)
}
func (v *Viper) insensitiviseMaps() {
insensitiviseMap(v.config)
insensitiviseMap(v.defaults)