diff --git a/altsrc.go b/altsrc.go index e3b159f..c99b9c2 100644 --- a/altsrc.go +++ b/altsrc.go @@ -6,6 +6,8 @@ import ( "os" "runtime" "strings" + + "github.com/urfave/cli/v3" ) var ( @@ -80,3 +82,72 @@ func NestedVal(name string, tree map[any]any) (any, bool) { } return nil, false } + +type Sourcer interface { + SourceURI() string +} + +type StringSourcer string + +func (s StringSourcer) SourceURI() string { + return string(s) +} + +type StringPtrSourcer struct { + ptr *string +} + +func NewStringPtrSourcer(p *string) StringPtrSourcer { + return StringPtrSourcer{ + ptr: p, + } +} + +func (s StringPtrSourcer) SourceURI() string { + return *s.ptr +} + +type valueSource struct { + key string + desc string + sourcer Sourcer + um func([]byte, any) error +} + +func (vs *valueSource) Lookup() (string, bool) { + maafsc := NewMapAnyAnyURISourceCache(vs.sourcer.SourceURI(), vs.um) + if v, ok := NestedVal(vs.key, maafsc.Get()); ok { + return fmt.Sprintf("%[1]v", v), ok + } + + return "", false +} + +func (vs *valueSource) String() string { + return fmt.Sprintf("%s file %[2]q at key %[3]q", vs.desc, vs.sourcer.SourceURI(), vs.key) +} + +func (vs *valueSource) GoString() string { + return fmt.Sprintf("%sValueSource{file:%[2]q,keyPath:%[3]q}", vs.desc, vs.sourcer.SourceURI(), vs.key) +} + +func NewValueSource(f func([]byte, any) error, desc string, key string, uriSrc Sourcer) cli.ValueSource { + return &valueSource{ + sourcer: uriSrc, + key: key, + desc: desc, + um: f, + } +} + +func NewValueSourceChain(f func([]byte, any) error, desc string, key string, uris ...Sourcer) cli.ValueSourceChain { + vs := []cli.ValueSource{} + + for _, uri := range uris { + vs = append(vs, NewValueSource(f, desc, key, uri)) + } + + return cli.ValueSourceChain{ + Chain: vs, + } +} diff --git a/go.mod b/go.mod index a9c38ab..97e3a67 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require github.com/stretchr/testify v1.9.0 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/urfave/cli/v3 v3.0.0-beta1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 60ce688..65148ad 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg= +github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/json/examples_test.go b/json/examples_test.go index 28e64e3..e48b96a 100644 --- a/json/examples_test.go +++ b/json/examples_test.go @@ -22,9 +22,9 @@ var ( ) func ExampleJSON() { - configFiles := []string{ - filepath.Join(testdataDir, "config.json"), - filepath.Join(testdataDir, "alt-config.json"), + configFiles := []altsrc.Sourcer{ + altsrc.StringSourcer(filepath.Join(testdataDir, "config.json")), + altsrc.StringSourcer(filepath.Join(testdataDir, "alt-config.json")), } app := &cli.Command{ diff --git a/json/go.mod b/json/go.mod index 77efb49..d64f906 100644 --- a/json/go.mod +++ b/json/go.mod @@ -4,14 +4,15 @@ go 1.23.2 require ( github.com/stretchr/testify v1.9.0 + github.com/urfave/cli-altsrc/v3 v3.0.0-alpha9.3 github.com/urfave/cli-altsrc/yaml v0.0.1 - github.com/urfave/cli/v3 v3.0.0-alpha9.3 + github.com/urfave/cli/v3 v3.0.0-beta1 + gopkg.in/yaml.v2 v2.4.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/urfave/cli-altsrc/v3 v3.0.0-alpha9.3 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/json/go.sum b/json/go.sum index 3d44f9d..985ac38 100644 --- a/json/go.sum +++ b/json/go.sum @@ -4,9 +4,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/urfave/cli/v3 v3.0.0-alpha9.3 h1:RfQlgUHMRxDMwEEmGsrHd+mXYJpWpXlcJM8w86cpjGs= -github.com/urfave/cli/v3 v3.0.0-alpha9.3/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= +github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg= +github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/json/json_value_source.go b/json/json_value_source.go index 4236602..5e8d91c 100644 --- a/json/json_value_source.go +++ b/json/json_value_source.go @@ -1,12 +1,13 @@ package json import ( - yaml "github.com/urfave/cli-altsrc/yaml" + altsrc "github.com/urfave/cli-altsrc/v3" "github.com/urfave/cli/v3" + "gopkg.in/yaml.v2" ) // JSON is a helper function that wraps the YAML helper function // and loads via yaml.Unmarshal -func JSON(key string, paths ...string) cli.ValueSourceChain { - return yaml.YAML(key, paths...) +func JSON(key string, sources ...altsrc.Sourcer) cli.ValueSourceChain { + return altsrc.NewValueSourceChain(yaml.Unmarshal, "json", key, sources...) } diff --git a/json/json_value_source_test.go b/json/json_value_source_test.go index 3cbc5c2..d2e7998 100644 --- a/json/json_value_source_test.go +++ b/json/json_value_source_test.go @@ -28,9 +28,9 @@ func TestJSON(t *testing.T) { vsc := yaml.YAML( "water_fountain.water", - "/dev/null/nonexistent.json", - configPath, - altConfigPath, + altsrc.StringSourcer("/dev/null/nonexistent.json"), + altsrc.StringSourcer(configPath), + altsrc.StringSourcer(altConfigPath), ) v, ok := vsc.Lookup() r.Equal("false", v) @@ -38,5 +38,5 @@ func TestJSON(t *testing.T) { yvs := vsc.Chain[0] r.Equal("yaml file \"/dev/null/nonexistent.json\" at key \"water_fountain.water\"", yvs.String()) - r.Equal("&yamlValueSource{file:\"/dev/null/nonexistent.json\",keyPath:\"water_fountain.water\"}", yvs.GoString()) + r.Equal("yamlValueSource{file:\"/dev/null/nonexistent.json\",keyPath:\"water_fountain.water\"}", yvs.GoString()) } diff --git a/toml/examples_test.go b/toml/examples_test.go index d9cd138..de076c0 100644 --- a/toml/examples_test.go +++ b/toml/examples_test.go @@ -22,9 +22,9 @@ var ( ) func ExampleTOML() { - configFiles := []string{ - filepath.Join(testdataDir, "config.toml"), - filepath.Join(testdataDir, "alt-config.toml"), + configFiles := []altsrc.Sourcer{ + altsrc.StringSourcer(filepath.Join(testdataDir, "config.toml")), + altsrc.StringSourcer(filepath.Join(testdataDir, "alt-config.toml")), } app := &cli.Command{ diff --git a/toml/go.mod b/toml/go.mod index 81721c7..5247a16 100644 --- a/toml/go.mod +++ b/toml/go.mod @@ -5,8 +5,8 @@ go 1.23.2 require ( github.com/BurntSushi/toml v1.4.0 github.com/stretchr/testify v1.9.0 - github.com/urfave/cli/v3 v3.0.0-alpha9.3 - github.com/urfave/cli-altsrc/v3 v3.0.0-alpha9 + github.com/urfave/cli-altsrc/v3 v3.0.0-alpha9 + github.com/urfave/cli/v3 v3.0.0-beta1 ) require ( @@ -15,4 +15,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/urfave/cli-altsrc/v3 v3.0.0-alpha9 => ../ \ No newline at end of file +replace github.com/urfave/cli-altsrc/v3 v3.0.0-alpha9 => ../ diff --git a/toml/go.sum b/toml/go.sum index e1c2e72..a0a77eb 100644 --- a/toml/go.sum +++ b/toml/go.sum @@ -6,8 +6,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/urfave/cli/v3 v3.0.0-alpha9.3 h1:RfQlgUHMRxDMwEEmGsrHd+mXYJpWpXlcJM8w86cpjGs= -github.com/urfave/cli/v3 v3.0.0-alpha9.3/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= +github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg= +github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/toml/toml_value_source.go b/toml/toml_value_source.go index 994abcd..da6a037 100644 --- a/toml/toml_value_source.go +++ b/toml/toml_value_source.go @@ -1,53 +1,13 @@ package toml import ( - "fmt" - "github.com/BurntSushi/toml" altsrc "github.com/urfave/cli-altsrc/v3" "github.com/urfave/cli/v3" ) -type tomlMapFileSourceCache = altsrc.FileSourceCache[tomlMap] - // TOML is a helper function to encapsulate a number of // tomlValueSource together as a cli.ValueSourceChain -func TOML(key string, paths ...string) cli.ValueSourceChain { - vsc := cli.ValueSourceChain{Chain: []cli.ValueSource{}} - - for _, path := range paths { - vsc.Chain = append( - vsc.Chain, - &tomlValueSource{ - file: path, - key: key, - tmc: *altsrc.NewFileSourceCache[tomlMap](path, toml.Unmarshal), - }, - ) - } - - return vsc -} - -type tomlValueSource struct { - file string - key string - - tmc tomlMapFileSourceCache -} - -func (tvs *tomlValueSource) Lookup() (string, bool) { - if v, ok := altsrc.NestedVal(tvs.key, tvs.tmc.Get().Map); ok { - return fmt.Sprintf("%[1]v", v), ok - } - - return "", false -} - -func (tvs *tomlValueSource) String() string { - return fmt.Sprintf("toml file %[1]q at key %[2]q", tvs.file, tvs.key) -} - -func (tvs *tomlValueSource) GoString() string { - return fmt.Sprintf("&tomlValueSource{file:%[1]q,keyPath:%[2]q}", tvs.file, tvs.key) +func TOML(key string, sources ...altsrc.Sourcer) cli.ValueSourceChain { + return altsrc.NewValueSourceChain(toml.Unmarshal, "toml", key, sources...) } diff --git a/toml/toml_value_source_test.go b/toml/toml_value_source_test.go index 6d17e76..d11cf2a 100644 --- a/toml/toml_value_source_test.go +++ b/toml/toml_value_source_test.go @@ -27,15 +27,15 @@ func TestTOML(t *testing.T) { vsc := TOML( "water_fountain.water", - "/dev/null/nonexistent.toml", - configPath, - altConfigPath, + altsrc.StringSourcer("/dev/null/nonexistent.toml"), + altsrc.StringSourcer(configPath), + altsrc.StringSourcer(altConfigPath), ) v, ok := vsc.Lookup() r.Equal("false", v) r.True(ok) - tvs := vsc.Chain[0].(*tomlValueSource) + tvs := vsc.Chain[0] r.Equal("toml file \"/dev/null/nonexistent.toml\" at key \"water_fountain.water\"", tvs.String()) - r.Equal("&tomlValueSource{file:\"/dev/null/nonexistent.toml\",keyPath:\"water_fountain.water\"}", tvs.GoString()) + r.Equal("tomlValueSource{file:\"/dev/null/nonexistent.toml\",keyPath:\"water_fountain.water\"}", tvs.GoString()) } diff --git a/uri_source_cache.go b/uri_source_cache.go index 5075f38..d45f841 100644 --- a/uri_source_cache.go +++ b/uri_source_cache.go @@ -39,14 +39,14 @@ func readURI(uriString string) ([]byte, error) { } type URISourceCache[T any] struct { - file string + uri string m *T unmarshaller func([]byte, any) error } -func NewURISourceCache[T any](file string, f func([]byte, any) error) *URISourceCache[T] { +func NewURISourceCache[T any](uri string, f func([]byte, any) error) *URISourceCache[T] { return &URISourceCache[T]{ - file: file, + uri: uri, unmarshaller: f, } } @@ -54,10 +54,10 @@ func NewURISourceCache[T any](file string, f func([]byte, any) error) *URISource func (fsc *URISourceCache[T]) Get() T { if fsc.m == nil { res := new(T) - if b, err := readURI(fsc.file); err != nil { - tracef("failed to read uri %[1]q: %[2]v", fsc.file, err) + if b, err := readURI(fsc.uri); err != nil { + tracef("failed to read uri %[1]q: %[2]v", fsc.uri, err) } else if err := fsc.unmarshaller(b, res); err != nil { - tracef("failed to unmarshal from file %[1]q: %[2]v", fsc.file, err) + tracef("failed to unmarshal from file %[1]q: %[2]v", fsc.uri, err) } else { fsc.m = res } diff --git a/yaml/examples_test.go b/yaml/examples_test.go index 56979af..4191544 100644 --- a/yaml/examples_test.go +++ b/yaml/examples_test.go @@ -22,9 +22,9 @@ var ( ) func ExampleYAML() { - configFiles := []string{ - filepath.Join(testdataDir, "config.yaml"), - filepath.Join(testdataDir, "alt-config.yaml"), + configFiles := []altsrc.Sourcer{ + altsrc.StringSourcer(filepath.Join(testdataDir, "config.yaml")), + altsrc.StringSourcer(filepath.Join(testdataDir, "alt-config.yaml")), } app := &cli.Command{ diff --git a/yaml/go.mod b/yaml/go.mod index 78132f0..34ad638 100644 --- a/yaml/go.mod +++ b/yaml/go.mod @@ -5,7 +5,7 @@ go 1.23.2 require ( github.com/stretchr/testify v1.9.0 github.com/urfave/cli-altsrc/v3 v3.0.0-alpha2 - github.com/urfave/cli/v3 v3.0.0-alpha9.3 + github.com/urfave/cli/v3 v3.0.0-beta1 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/yaml/go.sum b/yaml/go.sum index 3d44f9d..65148ad 100644 --- a/yaml/go.sum +++ b/yaml/go.sum @@ -4,8 +4,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/urfave/cli/v3 v3.0.0-alpha9.3 h1:RfQlgUHMRxDMwEEmGsrHd+mXYJpWpXlcJM8w86cpjGs= -github.com/urfave/cli/v3 v3.0.0-alpha9.3/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= +github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg= +github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/yaml/yaml_value_source.go b/yaml/yaml_value_source.go index 9af6f84..cb741bf 100644 --- a/yaml/yaml_value_source.go +++ b/yaml/yaml_value_source.go @@ -1,8 +1,6 @@ package yaml import ( - "fmt" - altsrc "github.com/urfave/cli-altsrc/v3" "github.com/urfave/cli/v3" "gopkg.in/yaml.v3" @@ -10,42 +8,6 @@ import ( // YAML is a helper function to encapsulate a number of // yamlValueSource together as a cli.ValueSourceChain -func YAML(key string, paths ...string) cli.ValueSourceChain { - vsc := cli.ValueSourceChain{Chain: []cli.ValueSource{}} - - for _, path := range paths { - vsc.Chain = append( - vsc.Chain, - &yamlValueSource{ - file: path, - key: key, - maafsc: altsrc.NewMapAnyAnyFileSourceCache(path, yaml.Unmarshal), - }, - ) - } - - return vsc -} - -type yamlValueSource struct { - file string - key string - - maafsc *altsrc.MapAnyAnyFileSourceCache -} - -func (yvs *yamlValueSource) Lookup() (string, bool) { - if v, ok := altsrc.NestedVal(yvs.key, yvs.maafsc.Get()); ok { - return fmt.Sprintf("%[1]v", v), ok - } - - return "", false -} - -func (yvs *yamlValueSource) String() string { - return fmt.Sprintf("yaml file %[1]q at key %[2]q", yvs.file, yvs.key) -} - -func (yvs *yamlValueSource) GoString() string { - return fmt.Sprintf("&yamlValueSource{file:%[1]q,keyPath:%[2]q}", yvs.file, yvs.key) +func YAML(key string, sources ...altsrc.Sourcer) cli.ValueSourceChain { + return altsrc.NewValueSourceChain(yaml.Unmarshal, "yaml", key, sources...) } diff --git a/yaml/yaml_value_source_test.go b/yaml/yaml_value_source_test.go index bb3b1a8..dd7265c 100644 --- a/yaml/yaml_value_source_test.go +++ b/yaml/yaml_value_source_test.go @@ -27,15 +27,15 @@ func TestYAML(t *testing.T) { vsc := YAML( "water_fountain.water", - "/dev/null/nonexistent.yaml", - configPath, - altConfigPath, + altsrc.StringSourcer("/dev/null/nonexistent.yaml"), + altsrc.StringSourcer(configPath), + altsrc.StringSourcer(altConfigPath), ) v, ok := vsc.Lookup() r.Equal("false", v) r.True(ok) - yvs := vsc.Chain[0].(*yamlValueSource) + yvs := vsc.Chain[0] r.Equal("yaml file \"/dev/null/nonexistent.yaml\" at key \"water_fountain.water\"", yvs.String()) - r.Equal("&yamlValueSource{file:\"/dev/null/nonexistent.yaml\",keyPath:\"water_fountain.water\"}", yvs.GoString()) + r.Equal("yamlValueSource{file:\"/dev/null/nonexistent.yaml\",keyPath:\"water_fountain.water\"}", yvs.GoString()) }