Skip to content

Commit

Permalink
Merge pull request #11 from dearchap/issue_10
Browse files Browse the repository at this point in the history
Feat:(issue_10) Move providers into separate paths
  • Loading branch information
dearchap authored Dec 27, 2024
2 parents d37d3ea + 6bc58c0 commit ed4233e
Show file tree
Hide file tree
Showing 26 changed files with 745 additions and 322 deletions.
67 changes: 35 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,44 @@ features which are otherwise not used throughout [`urfave/cli/v3`].
### Example

```go
configFiles := []string{
filepath.Join(testdataDir, "config.yaml"),
filepath.Join(testdataDir, "alt-config.yaml"),
}

app := &cli.Command{
Name: "greet",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Sources: altsrc.YAML("greet.name", configFiles...),
configFiles := []string{
filepath.Join(testdataDir, "config.yaml"),
filepath.Join(testdataDir, "alt-config.yaml"),
}

app := &cli.Command{
Name: "greet",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Sources: yaml.YAML("greet.name", configFiles...),
},
&cli.IntFlag{
Name: "enthusiasm",
Aliases: []string{"!"},
Sources: yaml.YAML("greet.enthusiasm", configFiles...),
},
},
&cli.IntFlag{
Name: "enthusiasm",
Aliases: []string{"!"},
Sources: altsrc.YAML("greet.enthusiasm", configFiles...),
},
},
Action: func(cCtx *cli.Context) error {
punct := ""
if cCtx.Int("enthusiasm") > 9000 {
punct = "!"
}
Action: func(ctx context.Context, cmd *cli.Command) error {
punct := ""
if cmd.Int("enthusiasm") > 9000 {
punct = "!"
}

fmt.Fprintf(os.Stdout, "Hello, %[1]v%[2]v\n", cmd.String("name"), punct)

fmt.Fprintf(os.Stdout, "Hello, %[1]v%[2]v\n", cCtx.String("name"), punct)
return nil
},
}

return nil
},
}
// Simulating os.Args
os.Args = []string{"greet"}

// Simulating os.Args
os.Args = []string{"greet"}
if err := app.Run(context.Background(), os.Args); err != nil {
fmt.Fprintf(os.Stdout, "OH NO: %[1]v\n", err)
}

if err := app.Run(context.Background(), os.Args); err != nil {
fmt.Fprintf(os.Stdout, "OH NO: %[1]v\n", err)
}
// Output:
// Hello, Berry!
```
35 changes: 2 additions & 33 deletions altsrc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ package altsrc
import (
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"runtime"
"strings"
Expand Down Expand Up @@ -45,38 +42,10 @@ func tracef(format string, a ...any) {
)
}

func readURI(uriString string) ([]byte, error) {
u, err := url.Parse(uriString)
if err != nil {
return nil, err
}

if u.Host != "" { // i have a host, now do i support the scheme?
switch u.Scheme {
case "http", "https":
res, err := http.Get(uriString)
if err != nil {
return nil, err
}
return io.ReadAll(res.Body)
default:
return nil, fmt.Errorf("%[1]w: scheme of %[2]q is unsupported", Err, uriString)
}
} else if u.Path != "" ||
(runtime.GOOS == "windows" && strings.Contains(u.String(), "\\")) {
if _, notFoundFileErr := os.Stat(uriString); notFoundFileErr != nil {
return nil, fmt.Errorf("%[1]w: cannot read from %[2]q because it does not exist", Err, uriString)
}
return os.ReadFile(uriString)
}

return nil, fmt.Errorf("%[1]w: unable to determine how to load from %[2]q", Err, uriString)
}

// nestedVal checks if the name has '.' delimiters.
// NestedVal checks if the name has '.' delimiters.
// If so, it tries to traverse the tree by the '.' delimited sections to find
// a nested value for the key.
func nestedVal(name string, tree map[any]any) (any, bool) {
func NestedVal(name string, tree map[any]any) (any, bool) {
if sections := strings.Split(name, "."); len(sections) > 1 {
node := tree
for _, section := range sections[:len(sections)-1] {
Expand Down
130 changes: 128 additions & 2 deletions altsrc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,142 @@ package altsrc

import (
"context"
"testing"
"time"

"github.com/urfave/cli-altsrc/v3/internal"
"github.com/stretchr/testify/assert"
)

var (
testdataDir = func() string {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

return internal.MustTestdataDir(ctx)
return MustTestdataDir(ctx)
}()
)

func TestNestedVal(t *testing.T) {
tests := []struct {
name string
key string
m map[any]any
val any
b bool
}{
{
name: "No map no key",
},
{
name: "No map with key",
key: "foo",
},
{
name: "Empty map no key",
m: map[any]any{},
},
{
name: "Empty map with key",
key: "foo",
m: map[any]any{},
},
{
name: "Level 1 no key",
key: ".foob",
m: map[any]any{
"foo": 10,
},
},
{
name: "Level 2",
key: "foo.bar",
m: map[any]any{
"foo": map[any]any{
"bar": 10,
},
},
val: 10,
b: true,
},
{
name: "Level 2 invalid key",
key: "foo.bar1",
m: map[any]any{
"foo": map[any]any{
"bar": 10,
},
},
},
{
name: "Level 3 no entry",
key: "foo.bar.t",
m: map[any]any{
"foo": map[any]any{
"bar": "sss",
},
},
},
{
name: "Level 3",
key: "foo.bar.t",
m: map[any]any{
"foo": map[any]any{
"bar": map[any]any{
"t": "sss",
},
},
},
val: "sss",
b: true,
},
{
name: "Level 3 invalid key",
key: "foo.bar.t",
m: map[any]any{
"foo": map[any]any{
"bar": map[any]any{
"t1": 10,
},
},
},
},
{
name: "Level 4 no entry",
key: "foo.bar.t.gh",
m: map[any]any{
"foo": map[any]any{
"bar": map[any]any{
"t1": 10,
},
},
},
},
{
name: "Level 4 slice entry",
key: "foo.bar.t.gh",
m: map[any]any{
"foo": map[any]any{
"bar": map[any]any{
"t": map[any]any{
"gh": []int{10},
},
},
},
},
val: []int{10},
b: true,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
val, b := NestedVal(test.key, test.m)
if !test.b {
assert.False(t, b)
} else {
assert.True(t, b)
assert.Equal(t, val, test.val)
}
})
}
}
Loading

0 comments on commit ed4233e

Please sign in to comment.