@@ -28,14 +28,26 @@ import (
28
28
29
29
const doubleQuoteSpecialChars = "\\ \n \r \" !$`"
30
30
31
+ // LookupFn represents a lookup function to resolve variables from
32
+ type LookupFn func (string ) (string , bool )
33
+
34
+ var noLookupFn = func (s string ) (string , bool ) {
35
+ return "" , false
36
+ }
37
+
31
38
// Parse reads an env file from io.Reader, returning a map of keys and values.
32
39
func Parse (r io.Reader ) (map [string ]string , error ) {
40
+ return ParseWithLookup (r , nil )
41
+ }
42
+
43
+ // ParseWithLookup reads an env file from io.Reader, returning a map of keys and values.
44
+ func ParseWithLookup (r io.Reader , lookupFn LookupFn ) (map [string ]string , error ) {
33
45
data , err := ioutil .ReadAll (r )
34
46
if err != nil {
35
47
return nil , err
36
48
}
37
49
38
- return UnmarshalBytes (data )
50
+ return UnmarshalBytesWithLookup (data , lookupFn )
39
51
}
40
52
41
53
// Load will read your env file(s) and load them into ENV for this process.
@@ -50,15 +62,7 @@ func Parse(r io.Reader) (map[string]string, error) {
50
62
//
51
63
// It's important to note that it WILL NOT OVERRIDE an env variable that already exists - consider the .env file to set dev vars or sensible defaults
52
64
func Load (filenames ... string ) (err error ) {
53
- filenames = filenamesOrDefault (filenames )
54
-
55
- for _ , filename := range filenames {
56
- err = loadFile (filename , false )
57
- if err != nil {
58
- return // return early on a spazout
59
- }
60
- }
61
- return
65
+ return load (false , filenames ... )
62
66
}
63
67
64
68
// Overload will read your env file(s) and load them into ENV for this process.
@@ -73,25 +77,29 @@ func Load(filenames ...string) (err error) {
73
77
//
74
78
// It's important to note this WILL OVERRIDE an env variable that already exists - consider the .env file to forcefilly set all vars.
75
79
func Overload (filenames ... string ) (err error ) {
80
+ return load (true , filenames ... )
81
+ }
82
+
83
+ func load (overload bool , filenames ... string ) (err error ) {
76
84
filenames = filenamesOrDefault (filenames )
77
85
78
86
for _ , filename := range filenames {
79
- err = loadFile (filename , true )
87
+ err = loadFile (filename , overload )
80
88
if err != nil {
81
89
return // return early on a spazout
82
90
}
83
91
}
84
92
return
85
93
}
86
94
87
- // Read all env (with same file loading semantics as Load) but return values as
95
+ // ReadWithLookup gets all env vars from the files and/or lookup function and return values as
88
96
// a map rather than automatically writing values into env
89
- func Read ( filenames ... string ) (envMap map [string ]string , err error ) {
97
+ func ReadWithLookup ( lookupFn LookupFn , filenames ... string ) (envMap map [string ]string , err error ) {
90
98
filenames = filenamesOrDefault (filenames )
91
99
envMap = make (map [string ]string )
92
100
93
101
for _ , filename := range filenames {
94
- individualEnvMap , individualErr := readFile (filename )
102
+ individualEnvMap , individualErr := readFile (filename , lookupFn )
95
103
96
104
if individualErr != nil {
97
105
err = individualErr
@@ -106,15 +114,26 @@ func Read(filenames ...string) (envMap map[string]string, err error) {
106
114
return
107
115
}
108
116
117
+ // Read all env (with same file loading semantics as Load) but return values as
118
+ // a map rather than automatically writing values into env
119
+ func Read (filenames ... string ) (envMap map [string ]string , err error ) {
120
+ return ReadWithLookup (nil , filenames ... )
121
+ }
122
+
109
123
// Unmarshal reads an env file from a string, returning a map of keys and values.
110
124
func Unmarshal (str string ) (envMap map [string ]string , err error ) {
111
125
return UnmarshalBytes ([]byte (str ))
112
126
}
113
127
114
128
// UnmarshalBytes parses env file from byte slice of chars, returning a map of keys and values.
115
129
func UnmarshalBytes (src []byte ) (map [string ]string , error ) {
130
+ return UnmarshalBytesWithLookup (src , nil )
131
+ }
132
+
133
+ // UnmarshalBytesWithLookup parses env file from byte slice of chars, returning a map of keys and values.
134
+ func UnmarshalBytesWithLookup (src []byte , lookupFn LookupFn ) (map [string ]string , error ) {
116
135
out := make (map [string ]string )
117
- err := parseBytes (src , out )
136
+ err := parseBytes (src , out , lookupFn )
118
137
return out , err
119
138
}
120
139
@@ -178,7 +197,7 @@ func filenamesOrDefault(filenames []string) []string {
178
197
}
179
198
180
199
func loadFile (filename string , overload bool ) error {
181
- envMap , err := readFile (filename )
200
+ envMap , err := readFile (filename , nil )
182
201
if err != nil {
183
202
return err
184
203
}
@@ -199,14 +218,14 @@ func loadFile(filename string, overload bool) error {
199
218
return nil
200
219
}
201
220
202
- func readFile (filename string ) (envMap map [string ]string , err error ) {
221
+ func readFile (filename string , lookupFn LookupFn ) (envMap map [string ]string , err error ) {
203
222
file , err := os .Open (filename )
204
223
if err != nil {
205
224
return
206
225
}
207
226
defer file .Close ()
208
227
209
- return Parse (file )
228
+ return ParseWithLookup (file , lookupFn )
210
229
}
211
230
212
231
var exportRegex = regexp .MustCompile (`^\s*(?:export\s+)?(.*?)\s*$` )
0 commit comments