fix: make WriteConfig and SafeWriteConfig work as expected

When a config file is set using SetConfigFile:
– WriteConfig failed if the file did not already exist,
– SafeWriteConfig did not use it.

Fixes #430
Fixes #433

Signed-off-by: Yann Soubeyrand <yann.soubeyrand@camptocamp.com>
This commit is contained in:
Yann Soubeyrand 2025-02-09 11:34:53 +01:00
parent 8b223a45ce
commit 29bf0d0e8f
2 changed files with 107 additions and 9 deletions

View file

@ -1577,19 +1577,40 @@ func WriteConfig() error { return v.WriteConfig() }
func (v *Viper) WriteConfig() error {
filename, err := v.getConfigFile()
if err != nil {
if _, ok := err.(ConfigFileNotFoundError); !ok {
return err
}
return v.writeConfig(filename, true)
filename, err = v.getDefaultConfigFile()
if err != nil {
return err
}
}
v.configFile = filename
return v.WriteConfigAs(v.configFile)
}
// SafeWriteConfig writes current configuration to file only if the file does not exist.
func SafeWriteConfig() error { return v.SafeWriteConfig() }
func (v *Viper) SafeWriteConfig() error {
if len(v.configPaths) < 1 {
return errors.New("missing configuration for 'configPath'")
filename, err := v.getConfigFile()
if err != nil {
if _, ok := err.(ConfigFileNotFoundError); !ok {
return err
}
return v.SafeWriteConfigAs(filepath.Join(v.configPaths[0], v.configName+"."+v.configType))
filename, err = v.getDefaultConfigFile()
if err != nil {
return err
}
}
v.configFile = filename
return v.SafeWriteConfigAs(v.configFile)
}
// WriteConfigAs writes current configuration to a given filename.
@ -2013,6 +2034,18 @@ func (v *Viper) getConfigFile() (string, error) {
return v.configFile, nil
}
func (v *Viper) getDefaultConfigFile() (string, error) {
if len(v.configPaths) < 1 {
return "", errors.New("missing configuration for 'configPath'")
}
if v.configType == "" {
v.configType = SupportedExts[0]
}
return filepath.Join(v.configPaths[0], v.configName+"."+v.configType), nil
}
// Debug prints all configuration registries for debugging
// purposes.
func Debug() { v.Debug() }

View file

@ -1731,7 +1731,7 @@ var jsonWriteExpected = []byte(`{
// name: steve
// `)
func TestWriteConfig(t *testing.T) {
func TestWriteConfigAs(t *testing.T) {
fs := afero.NewMemMapFs()
testCases := map[string]struct {
configName string
@ -1809,7 +1809,7 @@ func TestWriteConfig(t *testing.T) {
}
}
func TestWriteConfigTOML(t *testing.T) {
func TestWriteConfigAsTOML(t *testing.T) {
fs := afero.NewMemMapFs()
testCases := map[string]struct {
@ -1860,7 +1860,7 @@ func TestWriteConfigTOML(t *testing.T) {
}
}
func TestWriteConfigDotEnv(t *testing.T) {
func TestWriteConfigAsDotEnv(t *testing.T) {
fs := afero.NewMemMapFs()
testCases := map[string]struct {
configName string
@ -1909,6 +1909,56 @@ func TestWriteConfigDotEnv(t *testing.T) {
}
}
func TestWriteConfig(t *testing.T) {
v := New()
fs := afero.NewMemMapFs()
v.SetFs(fs)
v.AddConfigPath("/test")
v.SetConfigName("c")
v.SetConfigType("yaml")
require.NoError(t, v.ReadConfig(bytes.NewBuffer(yamlExample)))
require.NoError(t, v.WriteConfig())
read, err := afero.ReadFile(fs, "/test/c.yaml")
require.NoError(t, err)
assert.Equal(t, yamlWriteExpected, read)
}
func TestWriteConfigWithExplicitlySetFile(t *testing.T) {
v := New()
fs := afero.NewMemMapFs()
v.SetFs(fs)
v.AddConfigPath("/test1")
v.SetConfigName("c1")
v.SetConfigType("yaml")
v.SetConfigFile("/test2/c2.yaml")
require.NoError(t, v.ReadConfig(bytes.NewBuffer(yamlExample)))
require.NoError(t, v.WriteConfig())
read, err := afero.ReadFile(fs, "/test2/c2.yaml")
require.NoError(t, err)
assert.Equal(t, yamlWriteExpected, read)
}
func TestWriteConfigWithMissingConfigPath(t *testing.T) {
v := New()
fs := afero.NewMemMapFs()
v.SetFs(fs)
v.SetConfigName("c")
v.SetConfigType("yaml")
require.EqualError(t, v.WriteConfig(), "missing configuration for 'configPath'")
}
func TestWriteConfigWithExistingFile(t *testing.T) {
v := New()
fs := afero.NewMemMapFs()
fs.Create("/test/c.yaml")
v.SetFs(fs)
v.AddConfigPath("/test")
v.SetConfigName("c")
v.SetConfigType("yaml")
err := v.WriteConfig()
require.NoError(t, err)
}
func TestSafeWriteConfig(t *testing.T) {
v := New()
fs := afero.NewMemMapFs()
@ -1923,6 +1973,21 @@ func TestSafeWriteConfig(t *testing.T) {
assert.YAMLEq(t, string(yamlWriteExpected), string(read))
}
func TestSafeWriteConfigWithExplicitlySetFile(t *testing.T) {
v := New()
fs := afero.NewMemMapFs()
v.SetFs(fs)
v.AddConfigPath("/test1")
v.SetConfigName("c1")
v.SetConfigType("yaml")
v.SetConfigFile("/test2/c2.yaml")
require.NoError(t, v.ReadConfig(bytes.NewBuffer(yamlExample)))
require.NoError(t, v.SafeWriteConfig())
read, err := afero.ReadFile(fs, "/test2/c2.yaml")
require.NoError(t, err)
assert.Equal(t, yamlWriteExpected, read)
}
func TestSafeWriteConfigWithMissingConfigPath(t *testing.T) {
v := New()
fs := afero.NewMemMapFs()
@ -1946,7 +2011,7 @@ func TestSafeWriteConfigWithExistingFile(t *testing.T) {
assert.True(t, ok, "Expected ConfigFileAlreadyExistsError")
}
func TestSafeWriteAsConfig(t *testing.T) {
func TestSafeWriteConfigAs(t *testing.T) {
v := New()
fs := afero.NewMemMapFs()
v.SetFs(fs)