Add support to save file with no extension (#813) - viper - [fork] go viper port for 9front
(HTM) git clone git@git.drkhsh.at/viper.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit 97ee7adfef4882d78c0ef26e22a0c8a7a8bf6776
(DIR) parent b31a49291e7b00e5ba5db5d08c232755a458d1e1
(HTM) Author: Gustavo Bazan <gssbzn@gmail.com>
Date: Wed, 19 Feb 2020 23:41:04 +0000
Add support to save file with no extension (#813)
* Add support to save file with no extension
The support introduced for files with no file extension is only partial as trying to save the config file would fail with `<file name> requires valid extension`
This adds support to saving such files
Diffstat:
M viper.go | 13 ++++++++++---
M viper_test.go | 370 +++++++++++++++++++------------
2 files changed, 237 insertions(+), 146 deletions(-)
---
(DIR) diff --git a/viper.go b/viper.go
@@ -1413,11 +1413,18 @@ func (v *Viper) SafeWriteConfigAs(filename string) error {
func (v *Viper) writeConfig(filename string, force bool) error {
jww.INFO.Println("Attempting to write configuration to file.")
+ var configType string
+
ext := filepath.Ext(filename)
- if len(ext) <= 1 {
- return fmt.Errorf("filename: %s requires valid extension", filename)
+ if ext != "" {
+ configType = ext[1:]
+ } else {
+ configType = v.configType
}
- configType := ext[1:]
+ if configType == "" {
+ return fmt.Errorf("config type could not be determined for %s", filename)
+ }
+
if !stringInSlice(configType, SupportedExts) {
return UnsupportedConfigError(configType)
}
(DIR) diff --git a/viper_test.go b/viper_test.go
@@ -1279,26 +1279,6 @@ var hclWriteExpected = []byte(`"foos" = {
"type" = "donut"`)
-func TestWriteConfigHCL(t *testing.T) {
- v := New()
- fs := afero.NewMemMapFs()
- v.SetFs(fs)
- v.SetConfigName("c")
- v.SetConfigType("hcl")
- err := v.ReadConfig(bytes.NewBuffer(hclExample))
- if err != nil {
- t.Fatal(err)
- }
- if err := v.WriteConfigAs("c.hcl"); err != nil {
- t.Fatal(err)
- }
- read, err := afero.ReadFile(fs, "c.hcl")
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, hclWriteExpected, read)
-}
-
var jsonWriteExpected = []byte(`{
"batters": {
"batter": [
@@ -1322,26 +1302,6 @@ var jsonWriteExpected = []byte(`{
"type": "donut"
}`)
-func TestWriteConfigJson(t *testing.T) {
- v := New()
- fs := afero.NewMemMapFs()
- v.SetFs(fs)
- v.SetConfigName("c")
- v.SetConfigType("json")
- err := v.ReadConfig(bytes.NewBuffer(jsonExample))
- if err != nil {
- t.Fatal(err)
- }
- if err := v.WriteConfigAs("c.json"); err != nil {
- t.Fatal(err)
- }
- read, err := afero.ReadFile(fs, "c.json")
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, jsonWriteExpected, read)
-}
-
var propertiesWriteExpected = []byte(`p_id = 0001
p_type = donut
p_name = Cake
@@ -1349,95 +1309,6 @@ p_ppu = 0.55
p_batters.batter.type = Regular
`)
-func TestWriteConfigProperties(t *testing.T) {
- v := New()
- fs := afero.NewMemMapFs()
- v.SetFs(fs)
- v.SetConfigName("c")
- v.SetConfigType("properties")
- err := v.ReadConfig(bytes.NewBuffer(propertiesExample))
- if err != nil {
- t.Fatal(err)
- }
- if err := v.WriteConfigAs("c.properties"); err != nil {
- t.Fatal(err)
- }
- read, err := afero.ReadFile(fs, "c.properties")
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, propertiesWriteExpected, read)
-}
-
-func TestWriteConfigTOML(t *testing.T) {
- fs := afero.NewMemMapFs()
- v := New()
- v.SetFs(fs)
- v.SetConfigName("c")
- v.SetConfigType("toml")
- err := v.ReadConfig(bytes.NewBuffer(tomlExample))
- if err != nil {
- t.Fatal(err)
- }
- if err := v.WriteConfigAs("c.toml"); err != nil {
- t.Fatal(err)
- }
-
- // The TOML String method does not order the contents.
- // Therefore, we must read the generated file and compare the data.
- v2 := New()
- v2.SetFs(fs)
- v2.SetConfigName("c")
- v2.SetConfigType("toml")
- v2.SetConfigFile("c.toml")
- err = v2.ReadInConfig()
- if err != nil {
- t.Fatal(err)
- }
-
- assert.Equal(t, v.GetString("title"), v2.GetString("title"))
- assert.Equal(t, v.GetString("owner.bio"), v2.GetString("owner.bio"))
- assert.Equal(t, v.GetString("owner.dob"), v2.GetString("owner.dob"))
- assert.Equal(t, v.GetString("owner.organization"), v2.GetString("owner.organization"))
-}
-
-var dotenvWriteExpected = []byte(`
-TITLE="DotEnv Write Example"
-NAME=Oreo
-KIND=Biscuit
-`)
-
-func TestWriteConfigDotEnv(t *testing.T) {
- fs := afero.NewMemMapFs()
- v := New()
- v.SetFs(fs)
- v.SetConfigName("c")
- v.SetConfigType("env")
- err := v.ReadConfig(bytes.NewBuffer(dotenvWriteExpected))
- if err != nil {
- t.Fatal(err)
- }
- if err := v.WriteConfigAs("c.env"); err != nil {
- t.Fatal(err)
- }
-
- // The TOML String method does not order the contents.
- // Therefore, we must read the generated file and compare the data.
- v2 := New()
- v2.SetFs(fs)
- v2.SetConfigName("c")
- v2.SetConfigType("env")
- v2.SetConfigFile("c.env")
- err = v2.ReadInConfig()
- if err != nil {
- t.Fatal(err)
- }
-
- assert.Equal(t, v.GetString("title"), v2.GetString("title"))
- assert.Equal(t, v.GetString("type"), v2.GetString("type"))
- assert.Equal(t, v.GetString("kind"), v2.GetString("kind"))
-}
-
var yamlWriteExpected = []byte(`age: 35
beard: true
clothing:
@@ -1454,24 +1325,237 @@ hobbies:
name: steve
`)
-func TestWriteConfigYAML(t *testing.T) {
- v := New()
+func TestWriteConfig(t *testing.T) {
fs := afero.NewMemMapFs()
- v.SetFs(fs)
- v.SetConfigName("c")
- v.SetConfigType("yaml")
- err := v.ReadConfig(bytes.NewBuffer(yamlExample))
- if err != nil {
- t.Fatal(err)
+ testCases := map[string]struct {
+ configName string
+ inConfigType string
+ outConfigType string
+ fileName string
+ input []byte
+ expectedContent []byte
+ }{
+ "hcl with file extension": {
+ configName: "c",
+ inConfigType: "hcl",
+ outConfigType: "hcl",
+ fileName: "c.hcl",
+ input: hclExample,
+ expectedContent: hclWriteExpected,
+ },
+ "hcl without file extension": {
+ configName: "c",
+ inConfigType: "hcl",
+ outConfigType: "hcl",
+ fileName: "c",
+ input: hclExample,
+ expectedContent: hclWriteExpected,
+ },
+ "hcl with file extension and mismatch type": {
+ configName: "c",
+ inConfigType: "hcl",
+ outConfigType: "json",
+ fileName: "c.hcl",
+ input: hclExample,
+ expectedContent: hclWriteExpected,
+ },
+ "json with file extension": {
+ configName: "c",
+ inConfigType: "json",
+ outConfigType: "json",
+ fileName: "c.json",
+ input: jsonExample,
+ expectedContent: jsonWriteExpected,
+ },
+ "json without file extension": {
+ configName: "c",
+ inConfigType: "json",
+ outConfigType: "json",
+ fileName: "c",
+ input: jsonExample,
+ expectedContent: jsonWriteExpected,
+ },
+ "json with file extension and mismatch type": {
+ configName: "c",
+ inConfigType: "json",
+ outConfigType: "hcl",
+ fileName: "c.json",
+ input: jsonExample,
+ expectedContent: jsonWriteExpected,
+ },
+ "properties with file extension": {
+ configName: "c",
+ inConfigType: "properties",
+ outConfigType: "properties",
+ fileName: "c.properties",
+ input: propertiesExample,
+ expectedContent: propertiesWriteExpected,
+ },
+ "properties without file extension": {
+ configName: "c",
+ inConfigType: "properties",
+ outConfigType: "properties",
+ fileName: "c",
+ input: propertiesExample,
+ expectedContent: propertiesWriteExpected,
+ },
+ "yaml with file extension": {
+ configName: "c",
+ inConfigType: "yaml",
+ outConfigType: "yaml",
+ fileName: "c.yaml",
+ input: yamlExample,
+ expectedContent: yamlWriteExpected,
+ },
+ "yaml without file extension": {
+ configName: "c",
+ inConfigType: "yaml",
+ outConfigType: "yaml",
+ fileName: "c",
+ input: yamlExample,
+ expectedContent: yamlWriteExpected,
+ },
+ "yaml with file extension and mismatch type": {
+ configName: "c",
+ inConfigType: "yaml",
+ outConfigType: "json",
+ fileName: "c.yaml",
+ input: yamlExample,
+ expectedContent: yamlWriteExpected,
+ },
}
- if err := v.WriteConfigAs("c.yaml"); err != nil {
- t.Fatal(err)
+ for name, tc := range testCases {
+ t.Run(name, func(t *testing.T) {
+ v := New()
+ v.SetFs(fs)
+ v.SetConfigName(tc.fileName)
+ v.SetConfigType(tc.inConfigType)
+
+ err := v.ReadConfig(bytes.NewBuffer(tc.input))
+ if err != nil {
+ t.Fatal(err)
+ }
+ v.SetConfigType(tc.outConfigType)
+ if err := v.WriteConfigAs(tc.fileName); err != nil {
+ t.Fatal(err)
+ }
+ read, err := afero.ReadFile(fs, tc.fileName)
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, tc.expectedContent, read)
+ })
}
- read, err := afero.ReadFile(fs, "c.yaml")
- if err != nil {
- t.Fatal(err)
+}
+
+func TestWriteConfigTOML(t *testing.T) {
+ fs := afero.NewMemMapFs()
+
+ testCases := map[string]struct {
+ configName string
+ configType string
+ fileName string
+ input []byte
+ }{
+ "with file extension": {
+ configName: "c",
+ configType: "toml",
+ fileName: "c.toml",
+ input: tomlExample,
+ },
+ "without file extension": {
+ configName: "c",
+ configType: "toml",
+ fileName: "c",
+ input: tomlExample,
+ },
+ }
+ for name, tc := range testCases {
+ t.Run(name, func(t *testing.T) {
+ v := New()
+ v.SetFs(fs)
+ v.SetConfigName(tc.configName)
+ v.SetConfigType(tc.configType)
+ err := v.ReadConfig(bytes.NewBuffer(tc.input))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := v.WriteConfigAs(tc.fileName); err != nil {
+ t.Fatal(err)
+ }
+
+ // The TOML String method does not order the contents.
+ // Therefore, we must read the generated file and compare the data.
+ v2 := New()
+ v2.SetFs(fs)
+ v2.SetConfigName(tc.configName)
+ v2.SetConfigType(tc.configType)
+ v2.SetConfigFile(tc.fileName)
+ err = v2.ReadInConfig()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert.Equal(t, v.GetString("title"), v2.GetString("title"))
+ assert.Equal(t, v.GetString("owner.bio"), v2.GetString("owner.bio"))
+ assert.Equal(t, v.GetString("owner.dob"), v2.GetString("owner.dob"))
+ assert.Equal(t, v.GetString("owner.organization"), v2.GetString("owner.organization"))
+ })
+ }
+}
+
+func TestWriteConfigDotEnv(t *testing.T) {
+ fs := afero.NewMemMapFs()
+ testCases := map[string]struct {
+ configName string
+ configType string
+ fileName string
+ input []byte
+ }{
+ "with file extension": {
+ configName: "c",
+ configType: "env",
+ fileName: "c.env",
+ input: dotenvExample,
+ },
+ "without file extension": {
+ configName: "c",
+ configType: "env",
+ fileName: "c",
+ input: dotenvExample,
+ },
+ }
+ for name, tc := range testCases {
+ t.Run(name, func(t *testing.T) {
+ v := New()
+ v.SetFs(fs)
+ v.SetConfigName(tc.configName)
+ v.SetConfigType(tc.configType)
+ err := v.ReadConfig(bytes.NewBuffer(tc.input))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := v.WriteConfigAs(tc.fileName); err != nil {
+ t.Fatal(err)
+ }
+
+ // The TOML String method does not order the contents.
+ // Therefore, we must read the generated file and compare the data.
+ v2 := New()
+ v2.SetFs(fs)
+ v2.SetConfigName(tc.configName)
+ v2.SetConfigType(tc.configType)
+ v2.SetConfigFile(tc.fileName)
+ err = v2.ReadInConfig()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert.Equal(t, v.GetString("title_dotenv"), v2.GetString("title_dotenv"))
+ assert.Equal(t, v.GetString("type_dotenv"), v2.GetString("type_dotenv"))
+ assert.Equal(t, v.GetString("kind_dotenv"), v2.GetString("kind_dotenv"))
+ })
}
- assert.Equal(t, yamlWriteExpected, read)
}
func TestSafeWriteConfig(t *testing.T) {