-
Notifications
You must be signed in to change notification settings - Fork 627
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This makes it easier for Debian to package direnv. See #951 Repo: https://github.com/direnv/go-dotenv Commit ID: 872ea3db4cb52bd8f1ae6690593f5d20c221c35b
- Loading branch information
Showing
7 changed files
with
516 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# go-dotenv | ||
|
||
Go parsing library for the dotenv format. | ||
|
||
There is no formal definition of the dotenv format but it has been introduced | ||
by https://github.com/bkeepers/dotenv which is thus canonical. This library is a port of that. | ||
|
||
This library was developed specifically for [direnv](https://direnv.net). | ||
|
||
## Features | ||
|
||
* `k=v` format | ||
* bash `export k=v` format | ||
* yaml `k: v` format | ||
* variable expansion, including default values as in `${FOO:-default}` | ||
* comments | ||
|
||
## Missing | ||
|
||
* probably needs API breakage | ||
|
||
## Alternatives | ||
|
||
Some other good alternatives with various variations. | ||
|
||
* https://github.com/joho/godotenv | ||
* https://github.com/lazureykis/dotenv | ||
* https://github.com/subosito/gotenv | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
// Package dotenv implements the parsing of the .env format. | ||
// | ||
// There is no formal definition of the format but it has been introduced by | ||
// https://github.com/bkeepers/dotenv which is thus canonical. | ||
package dotenv | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"regexp" | ||
"strings" | ||
) | ||
|
||
// LINE is the regexp matching a single line | ||
const LINE = ` | ||
\A | ||
\s* | ||
(?:|#.*| # comment line | ||
(?:export\s+)? # optional export | ||
([\w\.]+) # key | ||
(?:\s*=\s*|:\s+?) # separator | ||
( # optional value begin | ||
'(?:\'|[^'])*' # single quoted value | ||
| # or | ||
"(?:\"|[^"])*" # double quoted value | ||
| # or | ||
[^\s#\n]+ # unquoted value | ||
)? # value end | ||
\s* | ||
(?:\#.*)? # optional comment | ||
) | ||
\z | ||
` | ||
|
||
var linesRe = regexp.MustCompile("[\\r\\n]+") | ||
var lineRe = regexp.MustCompile( | ||
regexp.MustCompile("\\s+").ReplaceAllLiteralString( | ||
regexp.MustCompile("\\s+# .*").ReplaceAllLiteralString(LINE, ""), "")) | ||
|
||
// Parse reads a string in the .env format and returns a map of the extracted key=values. | ||
// | ||
// Ported from https://github.com/bkeepers/dotenv/blob/84f33f48107c492c3a99bd41c1059e7b4c1bb67a/lib/dotenv/parser.rb | ||
func Parse(data string) (map[string]string, error) { | ||
var dotenv = make(map[string]string) | ||
|
||
for _, line := range linesRe.Split(data, -1) { | ||
if !lineRe.MatchString(line) { | ||
return nil, fmt.Errorf("invalid line: %s", line) | ||
} | ||
|
||
match := lineRe.FindStringSubmatch(line) | ||
// commented or empty line | ||
if len(match) == 0 { | ||
continue | ||
} | ||
if len(match[1]) == 0 { | ||
continue | ||
} | ||
|
||
key := match[1] | ||
value := match[2] | ||
|
||
err := parseValue(key, value, dotenv) | ||
|
||
if err != nil { | ||
return nil, fmt.Errorf("unable to parse %s, %s: %s", key, value, err) | ||
} | ||
} | ||
|
||
return dotenv, nil | ||
} | ||
|
||
// MustParse works the same as Parse but panics on error | ||
func MustParse(data string) map[string]string { | ||
env, err := Parse(data) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return env | ||
} | ||
|
||
func parseValue(key string, value string, dotenv map[string]string) error { | ||
if len(value) <= 1 { | ||
dotenv[key] = value | ||
return nil | ||
} | ||
|
||
singleQuoted := false | ||
|
||
if value[0:1] == "'" && value[len(value)-1:] == "'" { | ||
// single-quoted string, do not expand | ||
singleQuoted = true | ||
value = value[1 : len(value)-1] | ||
} else if value[0:1] == `"` && value[len(value)-1:] == `"` { | ||
value = value[1 : len(value)-1] | ||
value = expandNewLines(value) | ||
value = unescapeCharacters(value) | ||
} | ||
|
||
if !singleQuoted { | ||
value = expandEnv(value, dotenv) | ||
} | ||
|
||
dotenv[key] = value | ||
return nil | ||
} | ||
|
||
var escRe = regexp.MustCompile("\\\\([^$])") | ||
|
||
func unescapeCharacters(value string) string { | ||
return escRe.ReplaceAllString(value, "$1") | ||
} | ||
|
||
func expandNewLines(value string) string { | ||
value = strings.Replace(value, "\\n", "\n", -1) | ||
value = strings.Replace(value, "\\r", "\r", -1) | ||
return value | ||
} | ||
|
||
func expandEnv(value string, dotenv map[string]string) string { | ||
expander := func(value string) string { | ||
envKey, defaultValue, hasDefault := splitKeyAndDefault(value, ":-") | ||
expanded, found := lookupDotenv(envKey, dotenv) | ||
|
||
if found { | ||
return expanded | ||
} else { | ||
return getFromEnvOrDefault(envKey, defaultValue, hasDefault) | ||
} | ||
} | ||
|
||
return os.Expand(value, expander) | ||
} | ||
|
||
func splitKeyAndDefault(value string, sep string) (string, string, bool) { | ||
var i = strings.Index(value, sep) | ||
|
||
if i == -1 { | ||
return value, "", false | ||
} else { | ||
return value[0:i], value[i+len(sep):], true | ||
} | ||
} | ||
|
||
func lookupDotenv(value string, dotenv map[string]string) (string, bool) { | ||
retval, ok := dotenv[value] | ||
return retval, ok | ||
} | ||
|
||
func getFromEnvOrDefault(envKey string, defaultValue string, hasDefault bool) string { | ||
var envValue = os.Getenv(envKey) | ||
|
||
if len(envValue) == 0 && hasDefault { | ||
return defaultValue | ||
} else { | ||
return envValue | ||
} | ||
} |
Oops, something went wrong.