equal
deleted
inserted
replaced
1 // Package gotenv provides functionality to dynamically load the environment variables |
1 // Package gotenv provides functionality to dynamically load the environment variables |
2 package gotenv |
2 package gotenv |
3 |
3 |
4 import ( |
4 import ( |
5 "bufio" |
5 "bufio" |
|
6 "bytes" |
6 "fmt" |
7 "fmt" |
7 "io" |
8 "io" |
8 "os" |
9 "os" |
9 "path/filepath" |
10 "path/filepath" |
10 "regexp" |
11 "regexp" |
172 } |
173 } |
173 |
174 |
174 return file.Sync() |
175 return file.Sync() |
175 } |
176 } |
176 |
177 |
|
178 // splitLines is a valid SplitFunc for a bufio.Scanner. It will split lines on CR ('\r'), LF ('\n') or CRLF (any of the three sequences). |
|
179 // If a CR is immediately followed by a LF, it is treated as a CRLF (one single line break). |
|
180 func splitLines(data []byte, atEOF bool) (advance int, token []byte, err error) { |
|
181 if atEOF && len(data) == 0 { |
|
182 return 0, nil, bufio.ErrFinalToken |
|
183 } |
|
184 |
|
185 idx := bytes.IndexAny(data, "\r\n") |
|
186 switch { |
|
187 case atEOF && idx < 0: |
|
188 return len(data), data, bufio.ErrFinalToken |
|
189 |
|
190 case idx < 0: |
|
191 return 0, nil, nil |
|
192 } |
|
193 |
|
194 // consume CR or LF |
|
195 eol := idx + 1 |
|
196 // detect CRLF |
|
197 if len(data) > eol && data[eol-1] == '\r' && data[eol] == '\n' { |
|
198 eol++ |
|
199 } |
|
200 |
|
201 return eol, data[:idx], nil |
|
202 } |
|
203 |
177 func strictParse(r io.Reader, override bool) (Env, error) { |
204 func strictParse(r io.Reader, override bool) (Env, error) { |
178 env := make(Env) |
205 env := make(Env) |
179 scanner := bufio.NewScanner(r) |
206 scanner := bufio.NewScanner(r) |
|
207 scanner.Split(splitLines) |
180 |
208 |
181 firstLine := true |
209 firstLine := true |
182 |
210 |
183 for scanner.Scan() { |
211 for scanner.Scan() { |
184 line := strings.TrimSpace(scanner.Text()) |
212 line := strings.TrimSpace(scanner.Text()) |
281 if !hsq { |
309 if !hsq { |
282 fv := func(s string) string { |
310 fv := func(s string) string { |
283 return varReplacement(s, hsq, env, override) |
311 return varReplacement(s, hsq, env, override) |
284 } |
312 } |
285 val = varRgx.ReplaceAllStringFunc(val, fv) |
313 val = varRgx.ReplaceAllStringFunc(val, fv) |
286 val = parseVal(val, env, hdq, override) |
|
287 } |
314 } |
288 |
315 |
289 env[key] = val |
316 env[key] = val |
290 return nil |
317 return nil |
291 } |
318 } |
350 return err |
377 return err |
351 } |
378 } |
352 |
379 |
353 return fmt.Errorf("line `%s` doesn't match format", s) |
380 return fmt.Errorf("line `%s` doesn't match format", s) |
354 } |
381 } |
355 |
|
356 func parseVal(val string, env Env, ignoreNewlines bool, override bool) string { |
|
357 if strings.Contains(val, "=") && !ignoreNewlines { |
|
358 kv := strings.Split(val, "\r") |
|
359 |
|
360 if len(kv) > 1 { |
|
361 val = kv[0] |
|
362 for _, l := range kv[1:] { |
|
363 _ = parseLine(l, env, override) |
|
364 } |
|
365 } |
|
366 } |
|
367 |
|
368 return val |
|
369 } |
|