Adds a LoadFiles function
This commit is contained in:
parent
0b733588c4
commit
a5b2b78546
5 changed files with 161 additions and 1 deletions
11
CHANGELOG.md
Normal file
11
CHANGELOG.md
Normal 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
|
||||
|
18
config.go
18
config.go
|
@ -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)
|
||||
|
|
110
config_test.go
110
config_test.go
|
@ -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
10
go.mod
|
@ -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
13
go.sum
Normal 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=
|
Loading…
Reference in a new issue