Skip to content

Commit

Permalink
Fix override for OverLoad and co. (#15)
Browse files Browse the repository at this point in the history
This commit adds an override-flag to make local variables override
environment variables.

Closes #14.
  • Loading branch information
5nord authored May 22, 2022
1 parent cc6b967 commit 958dbdf
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 11 deletions.
25 changes: 14 additions & 11 deletions gotenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func loadenv(override bool, filenames ...string) error {

// parse and set :)
func parset(r io.Reader, override bool) error {
env, err := StrictParse(r)
env, err := strictParse(r, override)
if err != nil {
return err
}
Expand All @@ -110,14 +110,18 @@ func setenv(key, val string, override bool) {
// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
// This function is skipping any invalid lines and only processing the valid one.
func Parse(r io.Reader) Env {
env, _ := StrictParse(r)
env, _ := strictParse(r, false)
return env
}

// StrictParse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
// This function is returning an error if there are any invalid lines.
func StrictParse(r io.Reader) (Env, error) {
return strictParse(r, false)
}

func strictParse(r io.Reader, override bool) (Env, error) {
env := make(Env)
scanner := bufio.NewScanner(r)

Expand All @@ -133,16 +137,15 @@ func StrictParse(r io.Reader) (Env, error) {

i++

err := parseLine(line, env)
err := parseLine(line, env, override)
if err != nil {
return env, err
}
}

return env, nil
}

func parseLine(s string, env Env) error {
func parseLine(s string, env Env, override bool) error {
rl := regexp.MustCompile(linePattern)
rm := rl.FindStringSubmatch(s)

Expand Down Expand Up @@ -177,11 +180,11 @@ func parseLine(s string, env Env) error {

rv := regexp.MustCompile(variablePattern)
fv := func(s string) string {
return varReplacement(s, hsq, env)
return varReplacement(s, hsq, env, override)
}

val = rv.ReplaceAllStringFunc(val, fv)
val = parseVal(val, env, hdq)
val = parseVal(val, env, hdq, override)

env[key] = val
return nil
Expand All @@ -201,7 +204,7 @@ func parseExport(st string, env Env) error {
return nil
}

func varReplacement(s string, hsq bool, env Env) string {
func varReplacement(s string, hsq bool, env Env, override bool) string {
if strings.HasPrefix(s, "\\") {
return strings.TrimPrefix(s, "\\")
}
Expand All @@ -220,7 +223,7 @@ func varReplacement(s string, hsq bool, env Env) string {

v := mn[3]

if replace, ok := os.LookupEnv(v); ok {
if replace, ok := os.LookupEnv(v); ok && !override {
return replace
}

Expand All @@ -246,15 +249,15 @@ func checkFormat(s string, env Env) error {
return fmt.Errorf("line `%s` doesn't match format", s)
}

func parseVal(val string, env Env, ignoreNewlines bool) string {
func parseVal(val string, env Env, ignoreNewlines bool, override bool) string {
if strings.Contains(val, "=") && !ignoreNewlines {
kv := strings.Split(val, "\r")

if len(kv) > 1 {
val = kv[0]

for i := 1; i < len(kv); i++ {
parseLine(kv[i], env)
parseLine(kv[i], env, override)
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions gotenv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,24 @@ func TestOverLoad_overriding(t *testing.T) {
os.Clearenv()
}

func TestOverLoad_overrideVars(t *testing.T) {
os.Setenv("A", "fromEnv")
err := gotenv.OverLoad("fixtures/vars.env")
assert.Nil(t, err)
assert.Equal(t, "fromFile", os.Getenv("B"))
os.Clearenv()
}

func TestOverLoad_overrideVars2(t *testing.T) {
os.Setenv("C", "fromEnv")
err := gotenv.OverLoad("fixtures/vars.env")
assert.Nil(t, err)
// The value for D is not "fromFile" because C is defined after the
// definition of D.
assert.Equal(t, "fromEnv", os.Getenv("D"), "C defined after usage")
os.Clearenv()
}

func TestMustOverLoad_nonExist(t *testing.T) {
assert.Panics(t, func() { gotenv.Must(gotenv.OverLoad, ".env.not.exist") }, "Caling gotenv.Must with Overgotenv.Load and non exist file SHOULD panic")
}
Expand Down

0 comments on commit 958dbdf

Please sign in to comment.