Merge pull request #47 from sachaos/feature-expand-variables-on-value

Support variable substitution in dotenv files
pull/53/head
John Barton 2018-01-15 13:49:21 +11:00 committed by GitHub
commit 6bb0851667
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 7 deletions

View File

@ -0,0 +1,5 @@
OPTION_A=1
OPTION_B=${OPTION_A}
OPTION_C=$OPTION_B
OPTION_D=${OPTION_A}${OPTION_B}
OPTION_E=${OPTION_NOT_DEFINED}

View File

@ -112,7 +112,7 @@ func Parse(r io.Reader) (envMap map[string]string, err error) {
for _, fullLine := range lines { for _, fullLine := range lines {
if !isIgnoredLine(fullLine) { if !isIgnoredLine(fullLine) {
var key, value string var key, value string
key, value, err = parseLine(fullLine) key, value, err = parseLine(fullLine, envMap)
if err != nil { if err != nil {
return return
@ -209,7 +209,7 @@ func readFile(filename string) (envMap map[string]string, err error) {
return Parse(file) return Parse(file)
} }
func parseLine(line string) (key string, value string, err error) { func parseLine(line string, envMap map[string]string) (key string, value string, err error) {
if len(line) == 0 { if len(line) == 0 {
err = errors.New("zero length string") err = errors.New("zero length string")
return return
@ -259,11 +259,11 @@ func parseLine(line string) (key string, value string, err error) {
key = strings.Trim(key, " ") key = strings.Trim(key, " ")
// Parse the value // Parse the value
value = parseValue(splitString[1]) value = parseValue(splitString[1], envMap)
return return
} }
func parseValue(value string) string { func parseValue(value string, envMap map[string]string) string {
// trim // trim
value = strings.Trim(value, " ") value = strings.Trim(value, " ")
@ -291,6 +291,13 @@ func parseValue(value string) string {
} }
} }
// expand variables
value = os.Expand(value, func(key string) string {
if val, ok := envMap[key]; ok {
return val
}
return ""
})
return value return value
} }

View File

@ -11,7 +11,7 @@ import (
var noopPresets = make(map[string]string) var noopPresets = make(map[string]string)
func parseAndCompare(t *testing.T, rawEnvLine string, expectedKey string, expectedValue string) { func parseAndCompare(t *testing.T, rawEnvLine string, expectedKey string, expectedValue string) {
key, value, _ := parseLine(rawEnvLine) key, value, _ := parseLine(rawEnvLine, noopPresets)
if key != expectedKey || value != expectedValue { if key != expectedKey || value != expectedValue {
t.Errorf("Expected '%v' to parse as '%v' => '%v', got '%v' => '%v' instead", rawEnvLine, expectedKey, expectedValue, key, value) t.Errorf("Expected '%v' to parse as '%v' => '%v', got '%v' => '%v' instead", rawEnvLine, expectedKey, expectedValue, key, value)
} }
@ -193,6 +193,19 @@ func TestLoadQuotedEnv(t *testing.T) {
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets) loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
} }
func TestSubstituitions(t *testing.T) {
envFileName := "fixtures/substitutions.env"
expectedValues := map[string]string{
"OPTION_A": "1",
"OPTION_B": "1",
"OPTION_C": "1",
"OPTION_D": "11",
"OPTION_E": "",
}
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
}
func TestActualEnvVarsAreLeftAlone(t *testing.T) { func TestActualEnvVarsAreLeftAlone(t *testing.T) {
os.Clearenv() os.Clearenv()
os.Setenv("OPTION_A", "actualenv") os.Setenv("OPTION_A", "actualenv")
@ -280,7 +293,7 @@ func TestParsing(t *testing.T) {
// it 'throws an error if line format is incorrect' do // it 'throws an error if line format is incorrect' do
// expect{env('lol$wut')}.to raise_error(Dotenv::FormatError) // expect{env('lol$wut')}.to raise_error(Dotenv::FormatError)
badlyFormattedLine := "lol$wut" badlyFormattedLine := "lol$wut"
_, _, err := parseLine(badlyFormattedLine) _, _, err := parseLine(badlyFormattedLine, noopPresets)
if err == nil { if err == nil {
t.Errorf("Expected \"%v\" to return error, but it didn't", badlyFormattedLine) t.Errorf("Expected \"%v\" to return error, but it didn't", badlyFormattedLine)
} }
@ -348,7 +361,7 @@ func TestWrite(t *testing.T) {
//but single quotes are left alone //but single quotes are left alone
writeAndCompare(`key=va'lu'e`, `key="va'lu'e"`) writeAndCompare(`key=va'lu'e`, `key="va'lu'e"`)
// newlines, backslashes, and some other special chars are escaped // newlines, backslashes, and some other special chars are escaped
writeAndCompare(`foo="$ba\n\r\\r!"`, `foo="\$ba\n\r\\r\!"`) writeAndCompare(`foo="\n\r\\r!"`, `foo="\n\r\\r\!"`)
// lines should be sorted // lines should be sorted
writeAndCompare("foo=bar\nbaz=buzz", "baz=\"buzz\"\nfoo=\"bar\"") writeAndCompare("foo=bar\nbaz=buzz", "baz=\"buzz\"\nfoo=\"bar\"")