Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Overload methods. #13

Merged
merged 1 commit into from
Sep 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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