diff --git a/backend/file/file.go b/backend/file/file.go index 351a8d3..18592ae 100644 --- a/backend/file/file.go +++ b/backend/file/file.go @@ -7,6 +7,7 @@ import ( "path/filepath" "github.com/BurntSushi/toml" + "github.com/heetch/confita/backend" "github.com/pkg/errors" "gopkg.in/yaml.v2" ) @@ -14,12 +15,14 @@ import ( // Backend that loads a configuration from a file. // It supports json and yaml formats. type Backend struct { - path string - name string + path string + name string + optional bool } // NewBackend creates a configuration loader that loads from a file. // The content will get decoded based on the file extension. +// If optional parameter is set to true, calling Unmarshal won't return an error if the file doesn't exist. func NewBackend(path string) *Backend { name := filepath.Ext(path) if name != "" { @@ -32,11 +35,29 @@ func NewBackend(path string) *Backend { } } +// NewOptionalBackend implementation is exactly the same as NewBackend except that +// if the file is not found, backend.ErrNotFound will be returned. +func NewOptionalBackend(path string) *Backend { + name := filepath.Ext(path) + if name != "" { + name = name[1:] + } + + return &Backend{ + path: path, + name: name, + optional: true, + } +} + // Unmarshal takes a struct pointer and unmarshals the file into it, // using either json or yaml based on the file extention. func (b *Backend) Unmarshal(ctx context.Context, to interface{}) error { f, err := os.Open(b.path) if err != nil { + if b.optional { + return backend.ErrNotFound + } return errors.Wrapf(err, "failed to open file at path \"%s\"", b.path) } defer f.Close() diff --git a/backend/file/file_test.go b/backend/file/file_test.go index dcced62..9ad8b7f 100644 --- a/backend/file/file_test.go +++ b/backend/file/file_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/heetch/confita/backend" "github.com/heetch/confita/backend/file" "github.com/stretchr/testify/require" ) @@ -96,11 +97,19 @@ timeout = 10 require.Error(t, err) }) - t.Run("File not found", func(t *testing.T) { + t.Run("Required file not found", func(t *testing.T) { var c config b := file.NewBackend("some path") err := b.Unmarshal(context.Background(), &c) require.Error(t, err) }) + + t.Run("Optional file not found", func(t *testing.T) { + var c config + b := file.NewOptionalBackend("some path") + + err := b.Unmarshal(context.Background(), &c) + require.EqualError(t, err, backend.ErrNotFound.Error()) + }) } diff --git a/config.go b/config.go index 9f7a437..5b6f70e 100644 --- a/config.go +++ b/config.go @@ -172,6 +172,9 @@ func (l *Loader) resolve(ctx context.Context, s *StructConfig) error { if u, ok := b.(Unmarshaler); ok { err := u.Unmarshal(ctx, s.S) if err != nil { + if err == backend.ErrNotFound { + continue + } return err } @@ -201,7 +204,6 @@ func (l *Loader) resolve(ctx context.Context, s *StructConfig) error { if err == backend.ErrNotFound { continue } - return err }