Skip to content

Commit 87ccb43

Browse files
Search up parent directories until we find our files.
Fixes joho#165
1 parent c40e9c6 commit 87ccb43

File tree

2 files changed

+87
-5
lines changed

2 files changed

+87
-5
lines changed

godotenv.go

+54-5
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import (
1818
"errors"
1919
"fmt"
2020
"io"
21+
"io/ioutil"
2122
"os"
2223
"os/exec"
24+
"path/filepath"
2325
"regexp"
2426
"sort"
2527
"strconv"
@@ -28,6 +30,14 @@ import (
2830

2931
const doubleQuoteSpecialChars = "\\\n\r\"!$`"
3032

33+
func stringSet(s []string) map[string]interface{} {
34+
m := make(map[string]interface{})
35+
for _, str := range s {
36+
m[str] = true
37+
}
38+
return m
39+
}
40+
3141
// Load will read your env file(s) and load them into ENV for this process.
3242
//
3343
// Call this function as close as possible to the start of your program (ideally in main)
@@ -42,7 +52,46 @@ const doubleQuoteSpecialChars = "\\\n\r\"!$`"
4252
func Load(filenames ...string) (err error) {
4353
filenames = filenamesOrDefault(filenames)
4454

45-
for _, filename := range filenames {
55+
filenamesMap := stringSet(filenames)
56+
57+
// We start in the current working directory and look up until we find all
58+
// of our files or hit the root path.
59+
currentDirectory, err := os.Getwd()
60+
if err != nil {
61+
return err
62+
}
63+
64+
filePaths := make([]string, 0)
65+
for {
66+
files, err := ioutil.ReadDir(currentDirectory)
67+
if err != nil {
68+
return err
69+
}
70+
71+
// Check if any of our desired files are in the current directory.
72+
for _, directoryFile := range files {
73+
for filename := range filenamesMap {
74+
if filename == directoryFile.Name() {
75+
filePaths = append(filePaths, currentDirectory+"/"+directoryFile.Name())
76+
delete(filenamesMap, directoryFile.Name())
77+
}
78+
79+
}
80+
}
81+
// We've found all of our files.
82+
if len(filenamesMap) == 0 {
83+
break
84+
}
85+
parent := filepath.Dir(currentDirectory)
86+
87+
// We've hit the file system root.
88+
if parent == currentDirectory {
89+
break
90+
}
91+
currentDirectory = parent
92+
}
93+
94+
for _, filename := range filePaths {
4695
err = loadFile(filename, false)
4796
if err != nil {
4897
return // return early on a spazout
@@ -187,8 +236,8 @@ func filenamesOrDefault(filenames []string) []string {
187236
return filenames
188237
}
189238

190-
func loadFile(filename string, overload bool) error {
191-
envMap, err := readFile(filename)
239+
func loadFile(filePath string, overload bool) error {
240+
envMap, err := readFile(filePath)
192241
if err != nil {
193242
return err
194243
}
@@ -209,8 +258,8 @@ func loadFile(filename string, overload bool) error {
209258
return nil
210259
}
211260

212-
func readFile(filename string) (envMap map[string]string, err error) {
213-
file, err := os.Open(filename)
261+
func readFile(filePath string) (envMap map[string]string, err error) {
262+
file, err := os.Open(filePath)
214263
if err != nil {
215264
return
216265
}

godotenv_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,39 @@ func TestLoadFileNotFound(t *testing.T) {
6363
}
6464
}
6565

66+
func TestLoadFileInParent(t *testing.T) {
67+
directory, err := os.MkdirTemp("", "sample")
68+
if err != nil {
69+
t.Error("Couldn't create temp directory.")
70+
}
71+
f, err := os.Create(directory + "/someparentfile.env")
72+
if err != nil {
73+
t.Error("Failed to create file.")
74+
}
75+
defer f.Close()
76+
77+
f.WriteString("GODOT_LOAD_FILE_IN_PARENT_TEST=1\n")
78+
79+
nestedPath := directory + "/some/nested/path"
80+
err = os.MkdirAll(nestedPath, 0755)
81+
if err != nil {
82+
t.Error("Failed to create directories.")
83+
}
84+
err = os.Chdir(nestedPath)
85+
if err != nil {
86+
t.Error("Failed to change directory.")
87+
}
88+
89+
err = Load("someparentfile.env")
90+
if err != nil {
91+
t.Error("Error loading file.")
92+
}
93+
94+
if os.Getenv("GODOT_LOAD_FILE_IN_PARENT_TEST") != "1" {
95+
t.Error("Failed to set env.")
96+
}
97+
}
98+
6699
func TestOverloadFileNotFound(t *testing.T) {
67100
err := Overload("somefilethatwillneverexistever.env")
68101
if err == nil {

0 commit comments

Comments
 (0)