Skip to content

Commit

Permalink
Merge pull request #13 from jmervine/master
Browse files Browse the repository at this point in the history
Add Overload methods.
  • Loading branch information
joho committed Sep 7, 2015
2 parents 443e926 + 008304c commit 4ed1339
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 9 deletions.
29 changes: 26 additions & 3 deletions godotenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,30 @@ func Load(filenames ...string) (err error) {
filenames = filenamesOrDefault(filenames)

for _, filename := range filenames {
err = loadFile(filename)
err = loadFile(filename, false)
if err != nil {
return // return early on a spazout
}
}
return
}

// Overload will read your env file(s) and load them into ENV for this process.
//
// Call this function as close as possible to the start of your program (ideally in main)
//
// If you call Overload without any args it will default to loading .env in the current path
//
// You can otherwise tell it which files to load (there can be more than one) like
//
// godotenv.Overload("fileone", "filetwo")
//
// It's important to note this WILL OVERRIDE an env variable that already exists - consider the .env file to forcefilly set all vars.
func Overload(filenames ...string) (err error) {
filenames = filenamesOrDefault(filenames)

for _, filename := range filenames {
err = loadFile(filename, true)
if err != nil {
return // return early on a spazout
}
Expand Down Expand Up @@ -90,14 +113,14 @@ func filenamesOrDefault(filenames []string) []string {
return filenames
}

func loadFile(filename string) error {
func loadFile(filename string, overload bool) error {
envMap, err := readFile(filename)
if err != nil {
return err
}

for key, value := range envMap {
if os.Getenv(key) == "" {
if os.Getenv(key) == "" || overload {
os.Setenv(key, value)
}
}
Expand Down
61 changes: 55 additions & 6 deletions godotenv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@ import (
"testing"
)

var noopPresets = make(map[string]string)

func parseAndCompare(t *testing.T, rawEnvLine string, expectedKey string, expectedValue string) {
key, value, _ := parseLine(rawEnvLine)
if key != expectedKey || value != expectedValue {
t.Errorf("Expected '%v' to parse as '%v' => '%v', got '%v' => '%v' instead", rawEnvLine, expectedKey, expectedValue, key, value)
}
}

func loadEnvAndCompareValues(t *testing.T, envFileName string, expectedValues map[string]string) {
func loadEnvAndCompareValues(t *testing.T, loader func(files ...string) error, envFileName string, expectedValues map[string]string, presets map[string]string) {
// first up, clear the env
os.Clearenv()

err := Load(envFileName)
for k, v := range presets {
os.Setenv(k, v)
}

err := loader(envFileName)
if err != nil {
t.Fatalf("Error loading %v", envFileName)
}
Expand All @@ -38,13 +44,28 @@ func TestLoadWithNoArgsLoadsDotEnv(t *testing.T) {
}
}

func TestOverloadWithNoArgsOverloadsDotEnv(t *testing.T) {
err := Overload()
pathError := err.(*os.PathError)
if pathError == nil || pathError.Op != "open" || pathError.Path != ".env" {
t.Errorf("Didn't try and open .env by default")
}
}

func TestLoadFileNotFound(t *testing.T) {
err := Load("somefilethatwillneverexistever.env")
if err == nil {
t.Error("File wasn't found but Load didn't return an error")
}
}

func TestOverloadFileNotFound(t *testing.T) {
err := Overload("somefilethatwillneverexistever.env")
if err == nil {
t.Error("File wasn't found but Overload didn't return an error")
}
}

func TestReadPlainEnv(t *testing.T) {
envFileName := "fixtures/plain.env"
expectedValues := map[string]string{
Expand All @@ -71,6 +92,34 @@ func TestReadPlainEnv(t *testing.T) {
}
}

func TestLoadDoesNotOverride(t *testing.T) {
envFileName := "fixtures/plain.env"

// ensure NO overload
presets := map[string]string{
"OPTION_A": "do_not_override",
}

expectedValues := map[string]string{
"OPTION_A": "do_not_override",
}
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, presets)
}

func TestOveroadDoesOverride(t *testing.T) {
envFileName := "fixtures/plain.env"

// ensure NO overload
presets := map[string]string{
"OPTION_A": "do_not_override",
}

expectedValues := map[string]string{
"OPTION_A": "1",
}
loadEnvAndCompareValues(t, Overload, envFileName, expectedValues, presets)
}

func TestLoadPlainEnv(t *testing.T) {
envFileName := "fixtures/plain.env"
expectedValues := map[string]string{
Expand All @@ -81,7 +130,7 @@ func TestLoadPlainEnv(t *testing.T) {
"OPTION_E": "5",
}

loadEnvAndCompareValues(t, envFileName, expectedValues)
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
}

func TestLoadExportedEnv(t *testing.T) {
Expand All @@ -91,7 +140,7 @@ func TestLoadExportedEnv(t *testing.T) {
"OPTION_B": "\n",
}

loadEnvAndCompareValues(t, envFileName, expectedValues)
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
}

func TestLoadEqualsEnv(t *testing.T) {
Expand All @@ -100,7 +149,7 @@ func TestLoadEqualsEnv(t *testing.T) {
"OPTION_A": "postgres://localhost:5432/database?sslmode=disable",
}

loadEnvAndCompareValues(t, envFileName, expectedValues)
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
}

func TestLoadQuotedEnv(t *testing.T) {
Expand All @@ -116,7 +165,7 @@ func TestLoadQuotedEnv(t *testing.T) {
"OPTION_H": "\n",
}

loadEnvAndCompareValues(t, envFileName, expectedValues)
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
}

func TestActualEnvVarsAreLeftAlone(t *testing.T) {
Expand Down

0 comments on commit 4ed1339

Please sign in to comment.