feat: add finder

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
This commit is contained in:
Mark Sagi-Kazar 2024-06-03 09:32:13 +02:00 committed by Márk Sági-Kazár
parent 272344e426
commit f452b09dd9
6 changed files with 120 additions and 13 deletions

View file

@ -45,7 +45,7 @@ jobs:
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
go: ["1.21", "1.22"] go: ["1.21", "1.22"]
tags: ["", "finder", "viper_bind_struct"] tags: ["", "viper_finder", "viper_bind_struct"]
steps: steps:
- name: Checkout repository - name: Checkout repository

View file

@ -1,4 +1,4 @@
//go:build !finder //go:build !viper_finder
package viper package viper

View file

@ -1,4 +1,4 @@
//go:build finder //go:build viper_finder
package viper package viper
@ -11,18 +11,22 @@ import (
// Search all configPaths for any config file. // Search all configPaths for any config file.
// Returns the first path that exists (and is a config file). // Returns the first path that exists (and is a config file).
func (v *Viper) findConfigFile() (string, error) { func (v *Viper) findConfigFile() (string, error) {
var names []string finder := v.finder
if v.configType != "" { if finder == nil {
names = locafero.NameWithOptionalExtensions(v.configName, SupportedExts...) var names []string
} else {
names = locafero.NameWithExtensions(v.configName, SupportedExts...)
}
finder := locafero.Finder{ if v.configType != "" {
Paths: v.configPaths, names = locafero.NameWithOptionalExtensions(v.configName, SupportedExts...)
Names: names, } else {
Type: locafero.FileTypeFile, names = locafero.NameWithExtensions(v.configName, SupportedExts...)
}
finder = locafero.Finder{
Paths: v.configPaths,
Names: names,
Type: locafero.FileTypeFile,
}
} }
results, err := finder.Find(v.fs) results, err := finder.Find(v.fs)

47
finder.go Normal file
View file

@ -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...)
}

42
finder_test.go Normal file
View file

@ -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)
}

View file

@ -158,6 +158,8 @@ type Viper struct {
// The filesystem to read config from. // The filesystem to read config from.
fs afero.Fs fs afero.Fs
finder Finder
// A set of remote providers to search for the configuration // A set of remote providers to search for the configuration
remoteProviders []*defaultRemoteProvider remoteProviders []*defaultRemoteProvider
@ -506,6 +508,12 @@ func (v *Viper) ConfigFileUsed() string { return v.configFile }
func AddConfigPath(in string) { v.AddConfigPath(in) } func AddConfigPath(in string) { v.AddConfigPath(in) }
func (v *Viper) AddConfigPath(in string) { 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 != "" { if in != "" {
absin := absPathify(v.logger, 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 SetConfigName(in string) { v.SetConfigName(in) }
func (v *Viper) SetConfigName(in string) { 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 != "" { if in != "" {
v.configName = in v.configName = in
v.configFile = "" v.configFile = ""