Adds a LoadFiles function

This commit is contained in:
Bruno Carlin 2021-12-19 20:43:33 +01:00
parent 0b733588c4
commit a5b2b78546
5 changed files with 161 additions and 1 deletions

11
CHANGELOG.md Normal file
View file

@ -0,0 +1,11 @@
# Changelog
## Unreleased
- Added License
- Changed the go version to 1.17
- Added a Loadfiles function to load at once several config files
## v0.1.0 (2020-03-17)
- Initial varsion

View file

@ -4,6 +4,7 @@ package conf
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
@ -16,6 +17,23 @@ func LoadFile(path string, data interface{}) error {
return read(path, data)
}
// LoadFiles tries to load all the given paths in the given order.
//
// If a path does not exist, it is ignored.
//
// It returns an error only if the content of a file is invalid, i.e. it
// cannot be unmarshaled by json.
func LoadFiles(data interface{}, paths ...string) error {
for _, p := range paths {
err := read(p, data)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("cannot load %q: %w", p, err)
}
}
return nil
}
// SaveFile writes the given data serialized in JSON in the given path
func SaveFile(path string, data interface{}) error {
return write(path, data)

View file

@ -3,6 +3,7 @@ package conf
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
. "github.com/smartystreets/goconvey/convey"
@ -94,6 +95,115 @@ func TestLoadFile(t *testing.T) {
})
}
func TestLoadFiles(t *testing.T) {
Convey("Given a config struct", t, func() {
c := &testconf{}
tmpDir := t.TempDir()
Convey("Given two existing files setting different options", func() {
content1 := []byte(`{"String": "foo"}`)
content2 := []byte(`{"Int": 42}`)
paths := []string{
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := ioutil.WriteFile(paths[0], content1, 0o600)
So(err, ShouldBeNil)
err = ioutil.WriteFile(paths[1], content2, 0o600)
So(err, ShouldBeNil)
Convey("When LoadFiles is called", func() {
err := LoadFiles(&c, paths...)
Convey("Then there is no error", func() {
So(err, ShouldBeNil)
Convey("And the options from both files have been set", func() {
So(c.String, ShouldEqual, "foo")
So(c.Int, ShouldEqual, 42)
})
})
})
})
Convey("Given two existing files setting the same option", func() {
content1 := []byte(`{"String": "foo"}`)
content2 := []byte(`{"String": "bar"}`)
paths := []string{
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := ioutil.WriteFile(paths[0], content1, 0o600)
So(err, ShouldBeNil)
err = ioutil.WriteFile(paths[1], content2, 0o600)
So(err, ShouldBeNil)
Convey("When LoadFiles is called", func() {
err := LoadFiles(&c, paths...)
Convey("Then there is no error", func() {
So(err, ShouldBeNil)
Convey("And the last file overwrote the first", func() {
So(c.String, ShouldEqual, "bar")
})
})
})
})
Convey("Given one non-existing and one existing files", func() {
content2 := []byte(`{"String": "bar"}`)
paths := []string{
"does-not-exist.json",
filepath.Join(tmpDir, "file2.json"),
}
err := ioutil.WriteFile(paths[1], content2, 0o600)
So(err, ShouldBeNil)
Convey("When LoadFiles is called", func() {
err := LoadFiles(&c, paths...)
Convey("Then there is no error", func() {
So(err, ShouldBeNil)
Convey("And the options from the last file have been set", func() {
So(c.String, ShouldEqual, "bar")
})
})
})
})
Convey("Given one invalid and one valid files", func() {
content1 := []byte(`{"`)
content2 := []byte(`{"String": "bar"}`)
paths := []string{
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := ioutil.WriteFile(paths[0], content1, 0o600)
So(err, ShouldBeNil)
err = ioutil.WriteFile(paths[1], content2, 0o600)
So(err, ShouldBeNil)
Convey("When LoadFiles is called", func() {
err := LoadFiles(&c, paths...)
Convey("Then an error is returned", func() {
So(err, ShouldBeError)
Convey("And the last file has not been read", func() {
So(c.String, ShouldNotEqual, "bar")
})
})
})
})
})
}
func TestSaveFile(t *testing.T) {
Convey("Given a config struct", t, func() {
c := testconf{

10
go.mod
View file

@ -1,3 +1,11 @@
module code.bcarlin.xyz/go/conf
go 1.14
go 1.17
require github.com/smartystreets/goconvey v1.7.2
require (
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/smartystreets/assertions v1.2.0 // indirect
)

13
go.sum Normal file
View file

@ -0,0 +1,13 @@
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=