mirror of https://github.com/joho/godotenv.git
Merge pull request #47 from sachaos/feature-expand-variables-on-value
Support variable substitution in dotenv filespull/53/head
commit
6bb0851667
|
@ -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}
|
15
godotenv.go
15
godotenv.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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\"")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue