-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a naïve parser for .env files (#89)
* Add a naïve parser for .env files * Remove dead code * Cleanup
- Loading branch information
1 parent
f564689
commit 72c982b
Showing
17 changed files
with
311 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package ff | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// EnvParser is a parser for .env files. Each line is tokenized on the first `=` | ||
// character. The first token is interpreted as the flag name, and the second | ||
// token is interpreted as the value. Both tokens are trimmed of leading and | ||
// trailing whitespace. If the value is "double quoted", control characters like | ||
// `\n` are expanded. Lines beginning with `#` are interpreted as comments. | ||
// | ||
// EnvParser respects WithEnvVarPrefix, e.g. an .env file containing `A_B=c` | ||
// will set a flag named "b" if Parse is called with WithEnvVarPrefix("A"). | ||
func EnvParser(r io.Reader, set func(name, value string) error) error { | ||
s := bufio.NewScanner(r) | ||
for s.Scan() { | ||
line := strings.TrimSpace(s.Text()) | ||
if line == "" { | ||
continue // skip empties | ||
} | ||
|
||
if line[0] == '#' { | ||
continue // skip comments | ||
} | ||
|
||
index := strings.IndexRune(line, '=') | ||
if index < 0 { | ||
return fmt.Errorf("invalid line: %s", line) | ||
} | ||
|
||
var ( | ||
name = strings.TrimSpace(line[:index]) | ||
value = strings.TrimSpace(line[index+1:]) | ||
) | ||
|
||
if len(name) <= 0 { | ||
return fmt.Errorf("invalid line: %s", line) | ||
} | ||
|
||
if len(value) <= 0 { | ||
return fmt.Errorf("invalid line: %s", line) | ||
} | ||
|
||
if unquoted, err := strconv.Unquote(value); err == nil { | ||
value = unquoted | ||
} | ||
|
||
if err := set(name, value); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package ff_test | ||
|
||
import ( | ||
"path/filepath" | ||
"testing" | ||
"time" | ||
|
||
"github.com/peterbourgon/ff/v3" | ||
"github.com/peterbourgon/ff/v3/fftest" | ||
) | ||
|
||
func TestEnvFileParser(t *testing.T) { | ||
t.Parallel() | ||
|
||
for _, testcase := range []struct { | ||
file string | ||
opts []ff.Option | ||
want fftest.Vars | ||
}{ | ||
{ | ||
file: "testdata/empty.env", | ||
want: fftest.Vars{}, | ||
}, | ||
{ | ||
file: "testdata/basic.env", | ||
want: fftest.Vars{S: "bar", I: 99, B: true, D: time.Hour}, | ||
}, | ||
{ | ||
file: "testdata/prefix.env", | ||
opts: []ff.Option{ff.WithEnvVarPrefix("MYPROG")}, | ||
want: fftest.Vars{S: "bingo", I: 123}, | ||
}, | ||
{ | ||
file: "testdata/prefix-undef.env", | ||
opts: []ff.Option{ff.WithEnvVarPrefix("MYPROG"), ff.WithIgnoreUndefined(true)}, | ||
want: fftest.Vars{S: "bango", I: 9}, | ||
}, | ||
{ | ||
file: "testdata/quotes.env", | ||
want: fftest.Vars{S: "", I: 32, X: []string{"1", "2 2", "3 3 3"}}, | ||
}, | ||
{ | ||
file: "testdata/no-value.env", | ||
want: fftest.Vars{WantParseErrorString: "invalid line: D="}, | ||
}, | ||
{ | ||
file: "testdata/spaces.env", | ||
want: fftest.Vars{X: []string{"1", "2", "3", "4", "5", " 6", " 7 ", " 8 "}}, | ||
}, | ||
{ | ||
file: "testdata/newlines.env", | ||
want: fftest.Vars{S: "one\ntwo\nthree\n\n", X: []string{`A\nB\n\n`}}, | ||
}, | ||
{ | ||
file: "testdata/capitalization.env", | ||
want: fftest.Vars{S: "hello", I: 12345}, | ||
}, | ||
} { | ||
t.Run(filepath.Base(testcase.file), func(t *testing.T) { | ||
testcase.opts = append(testcase.opts, ff.WithConfigFile(testcase.file), ff.WithConfigFileParser(ff.EnvParser)) | ||
fs, vars := fftest.Pair() | ||
vars.ParseError = ff.Parse(fs, []string{}, testcase.opts...) | ||
fftest.Compare(t, &testcase.want, vars) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package ff |
Oops, something went wrong.