Skip to content

Commit

Permalink
WithFilesystem (#110)
Browse files Browse the repository at this point in the history
* WithFilesystem

* configFileLookup was unused

* options.go was unused

* json[_test].go -> json_parser[_test].go
  • Loading branch information
peterbourgon committed Jun 11, 2023
1 parent 61fa353 commit c76f02c
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 9 deletions.
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion options.go

This file was deleted.

26 changes: 18 additions & 8 deletions parse.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package ff

import (
"embed"
"errors"
"flag"
"fmt"
"io"
iofs "io/fs"
"os"
"strings"
)
Expand All @@ -12,8 +15,6 @@ import (
// and calls the set function for each parsed flag pair.
type ConfigFileParser func(r io.Reader, set func(name, value string) error) error

type lookupFunc func(fs *flag.FlagSet, name string) *flag.Flag

// Parse the flags in the flag set from the provided (presumably commandline)
// args. Additional options may be provided to have Parse also read from a
// config file, and/or environment variables, in that priority order.
Expand Down Expand Up @@ -97,9 +98,9 @@ func Parse(fs *flag.FlagSet, args []string, options ...Option) error {
}
}

if c.configFileLookup == nil {
c.configFileLookup = func(fs *flag.FlagSet, name string) *flag.Flag {
return fs.Lookup(name)
if c.configFileOpenFunc == nil {
c.configFileOpenFunc = func(s string) (iofs.File, error) {
return os.Open(s)
}
}

Expand All @@ -109,7 +110,7 @@ func Parse(fs *flag.FlagSet, args []string, options ...Option) error {
parseConfigFile = haveConfigFile && haveParser
)
if parseConfigFile {
f, err := os.Open(configFile)
f, err := c.configFileOpenFunc(configFile)
switch {
case err == nil:
defer f.Close()
Expand Down Expand Up @@ -151,7 +152,7 @@ func Parse(fs *flag.FlagSet, args []string, options ...Option) error {
return err
}

case os.IsNotExist(err) && c.allowMissingConfigFile:
case errors.Is(err, iofs.ErrNotExist) && c.allowMissingConfigFile:
// no problem

default:
Expand All @@ -171,7 +172,7 @@ type Context struct {
configFileVia *string
configFileFlagName string
configFileParser ConfigFileParser
configFileLookup lookupFunc
configFileOpenFunc func(string) (iofs.File, error)
allowMissingConfigFile bool
readEnvVars bool
envVarPrefix string
Expand Down Expand Up @@ -278,6 +279,15 @@ func WithIgnoreUndefined(ignore bool) Option {
}
}

// WithFilesystem tells Parse to use the provided filesystem when accessing
// files on disk, for example when reading a config file. By default, the host
// filesystem is used, via [os.Open].
func WithFilesystem(fs embed.FS) Option {
return func(c *Context) {
c.configFileOpenFunc = fs.Open
}
}

var flagNameToEnvVar = strings.NewReplacer(
"-", "_",
".", "_",
Expand Down
9 changes: 9 additions & 0 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ff_test

import (
"context"
"embed"
"flag"
"os"
"testing"
Expand All @@ -12,6 +13,9 @@ import (
"github.com/peterbourgon/ff/v3/fftest"
)

//go:embed testdata/*.conf
var testdataConfigFS embed.FS

func TestParseBasics(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -149,6 +153,11 @@ func TestParseBasics(t *testing.T) {
opts: []ff.Option{ff.WithEnvVarNoPrefix()},
want: fftest.Vars{S: "xxx", F: 9.87},
},
{
name: "WithFilesystem testdata/1.conf",
opts: []ff.Option{ff.WithFilesystem(testdataConfigFS), ff.WithConfigFile("testdata/1.conf"), ff.WithConfigFileParser(ff.PlainParser)},
want: fftest.Vars{S: "bar", I: 99, B: true, D: 1 * time.Hour},
},
} {
t.Run(testcase.name, func(t *testing.T) {
if testcase.file != "" {
Expand Down

0 comments on commit c76f02c

Please sign in to comment.