From f452b09dd9b7815ed29927f6a682621d0f11371c Mon Sep 17 00:00:00 2001 From: Mark Sagi-Kazar Date: Mon, 3 Jun 2024 09:32:13 +0200 Subject: [PATCH] feat: add finder Signed-off-by: Mark Sagi-Kazar --- .github/workflows/ci.yaml | 2 +- file.go | 2 +- file_finder.go | 26 +++++++++++++--------- finder.go | 47 +++++++++++++++++++++++++++++++++++++++ finder_test.go | 42 ++++++++++++++++++++++++++++++++++ viper.go | 14 ++++++++++++ 6 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 finder.go create mode 100644 finder_test.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 95aa237..cc42da7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -45,7 +45,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] go: ["1.21", "1.22"] - tags: ["", "finder", "viper_bind_struct"] + tags: ["", "viper_finder", "viper_bind_struct"] steps: - name: Checkout repository diff --git a/file.go b/file.go index a54fe5a..101624d 100644 --- a/file.go +++ b/file.go @@ -1,4 +1,4 @@ -//go:build !finder +//go:build !viper_finder package viper diff --git a/file_finder.go b/file_finder.go index d96a1bd..c873621 100644 --- a/file_finder.go +++ b/file_finder.go @@ -1,4 +1,4 @@ -//go:build finder +//go:build viper_finder package viper @@ -11,18 +11,22 @@ import ( // Search all configPaths for any config file. // Returns the first path that exists (and is a config file). func (v *Viper) findConfigFile() (string, error) { - var names []string + finder := v.finder - if v.configType != "" { - names = locafero.NameWithOptionalExtensions(v.configName, SupportedExts...) - } else { - names = locafero.NameWithExtensions(v.configName, SupportedExts...) - } + if finder == nil { + var names []string - finder := locafero.Finder{ - Paths: v.configPaths, - Names: names, - Type: locafero.FileTypeFile, + if v.configType != "" { + names = locafero.NameWithOptionalExtensions(v.configName, SupportedExts...) + } else { + names = locafero.NameWithExtensions(v.configName, SupportedExts...) + } + + finder = locafero.Finder{ + Paths: v.configPaths, + Names: names, + Type: locafero.FileTypeFile, + } } results, err := finder.Find(v.fs) diff --git a/finder.go b/finder.go new file mode 100644 index 0000000..58a321b --- /dev/null +++ b/finder.go @@ -0,0 +1,47 @@ +package viper + +import ( + "errors" + + "github.com/spf13/afero" +) + +// WithFinder sets a custom [Finder]. +func WithFinder(f Finder) Option { + return optionFunc(func(v *Viper) { + v.finder = f + }) +} + +// Finder looks for files and directories in an [afero.Fs] filesystem. +type Finder interface { + Find(fsys afero.Fs) ([]string, error) +} + +// Finders combines multiple finders into one. +func Finders(finders ...Finder) Finder { + return &CombinedFinder{finders: finders} +} + +// CombinedFinder is a Finder that combines multiple finders. +type CombinedFinder struct { + finders []Finder +} + +// Find implements the [Finder] interface. +func (c *CombinedFinder) Find(fsys afero.Fs) ([]string, error) { + var results []string + var errs []error + + for _, finder := range c.finders { + r, err := finder.Find(fsys) + if err != nil { + errs = append(errs, err) + continue + } + + results = append(results, r...) + } + + return results, errors.Join(errs...) +} diff --git a/finder_test.go b/finder_test.go new file mode 100644 index 0000000..d57a413 --- /dev/null +++ b/finder_test.go @@ -0,0 +1,42 @@ +package viper + +import ( + "testing" + + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type finderStub struct { + results []string +} + +func (f finderStub) Find(_ afero.Fs) ([]string, error) { + return f.results, nil +} + +func TestFinders(t *testing.T) { + finder := Finders( + finderStub{ + results: []string{ + "/home/user/.viper.yaml", + }, + }, + finderStub{ + results: []string{ + "/etc/viper/config.yaml", + }, + }, + ) + + results, err := finder.Find(afero.NewMemMapFs()) + require.NoError(t, err) + + expected := []string{ + "/home/user/.viper.yaml", + "/etc/viper/config.yaml", + } + + assert.Equal(t, expected, results) +} diff --git a/viper.go b/viper.go index cebdde6..1ddeb2c 100644 --- a/viper.go +++ b/viper.go @@ -158,6 +158,8 @@ type Viper struct { // The filesystem to read config from. fs afero.Fs + finder Finder + // A set of remote providers to search for the configuration remoteProviders []*defaultRemoteProvider @@ -506,6 +508,12 @@ func (v *Viper) ConfigFileUsed() string { return v.configFile } func AddConfigPath(in string) { v.AddConfigPath(in) } func (v *Viper) AddConfigPath(in string) { + if v.finder != nil { + v.logger.Warn("call to AddConfigPath is ineffective when a custom finder is configured") + + return + } + if in != "" { absin := absPathify(v.logger, in) @@ -1955,6 +1963,12 @@ func (v *Viper) SetFs(fs afero.Fs) { func SetConfigName(in string) { v.SetConfigName(in) } func (v *Viper) SetConfigName(in string) { + if v.finder != nil { + v.logger.Warn("call to SetConfigName is ineffective when a custom finder is configured") + + return + } + if in != "" { v.configName = in v.configFile = ""