From b9324c6f3c8a1a1c1d8e8fe4601654fe1e137963 Mon Sep 17 00:00:00 2001 From: Alex Quick Date: Sat, 6 May 2017 00:50:30 -0400 Subject: [PATCH 1/4] handle escaping more comprehensively --- godotenv.go | 27 ++++++++++++++++++++------- godotenv_test.go | 5 +++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/godotenv.go b/godotenv.go index 0d9066c..cd10cab 100644 --- a/godotenv.go +++ b/godotenv.go @@ -18,6 +18,7 @@ import ( "errors" "os" "os/exec" + "regexp" "strings" ) @@ -218,7 +219,11 @@ func parseLine(line string) (key string, value string, err error) { key = strings.Trim(key, " ") // Parse the value - value = splitString[1] + value = parseValue(splitString[1]) + return +} + +func parseValue(value string) string { // trim value = strings.Trim(value, " ") @@ -230,15 +235,23 @@ func parseLine(line string) (key string, value string, err error) { if first == last && strings.ContainsAny(first, `"'`) { // pull the quotes off the edges value = strings.Trim(value, `"'`) - - // expand quotes - value = strings.Replace(value, `\"`, `"`, -1) - // expand newlines - value = strings.Replace(value, `\n`, "\n", -1) + // handle escapes + escapeRegex := regexp.MustCompile(`\\.`) + value = escapeRegex.ReplaceAllStringFunc(value, func(match string) string { + c := strings.TrimPrefix(match, `\`) + switch c { + case "n": + return "\n" + case "r": + return "\r" + default: + return c + } + }) } } - return + return value } func isIgnoredLine(line string) bool { diff --git a/godotenv_test.go b/godotenv_test.go index a62bf87..bd4b7cb 100644 --- a/godotenv_test.go +++ b/godotenv_test.go @@ -238,6 +238,11 @@ func TestParsing(t *testing.T) { parseAndCompare(t, `FOO="ba#r"`, "FOO", "ba#r") parseAndCompare(t, "FOO='ba#r'", "FOO", "ba#r") + //newlines and backslashes should be escaped + parseAndCompare(t, `FOO="bar\n\ b\az"`, "FOO", "bar\n baz") + parseAndCompare(t, `FOO="bar\\\n\ b\az"`, "FOO", "bar\\\n baz") + parseAndCompare(t, `FOO="bar\\r\ b\az"`, "FOO", "bar\\r baz") + // it 'throws an error if line format is incorrect' do // expect{env('lol$wut')}.to raise_error(Dotenv::FormatError) badlyFormattedLine := "lol$wut" From 84bf91f40e510881ffdf73bb6bfbd3af68d60917 Mon Sep 17 00:00:00 2001 From: Alex Quick Date: Sat, 20 May 2017 14:50:15 -0400 Subject: [PATCH 2/4] rudimentry support for nested quotes --- godotenv.go | 2 +- godotenv_test.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/godotenv.go b/godotenv.go index cd10cab..7cc4d06 100644 --- a/godotenv.go +++ b/godotenv.go @@ -234,7 +234,7 @@ func parseValue(value string) string { last := string(value[len(value)-1:]) if first == last && strings.ContainsAny(first, `"'`) { // pull the quotes off the edges - value = strings.Trim(value, `"'`) + value = value[1 : len(value)-1] // handle escapes escapeRegex := regexp.MustCompile(`\\.`) value = escapeRegex.ReplaceAllStringFunc(value, func(match string) string { diff --git a/godotenv_test.go b/godotenv_test.go index bd4b7cb..9d7d884 100644 --- a/godotenv_test.go +++ b/godotenv_test.go @@ -199,6 +199,9 @@ func TestParsing(t *testing.T) { // parses escaped double quotes parseAndCompare(t, `FOO="escaped\"bar"`, "FOO", `escaped"bar`) + // parses single quotes inside double quotes + parseAndCompare(t, `FOO="'d'"`, "FOO", `'d'`) + // parses yaml style options parseAndCompare(t, "OPTION_A: 1", "OPTION_A", "1") From 6f30f0c011721a03e416dd262d35b2f5eee54820 Mon Sep 17 00:00:00 2001 From: Alex Quick Date: Sat, 20 May 2017 15:06:01 -0400 Subject: [PATCH 3/4] support for equals in yaml-style lines --- godotenv.go | 8 ++++---- godotenv_test.go | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/godotenv.go b/godotenv.go index 7cc4d06..172c4f5 100644 --- a/godotenv.go +++ b/godotenv.go @@ -198,11 +198,11 @@ func parseLine(line string) (key string, value string, err error) { line = strings.Join(segmentsToKeep, "#") } - // now split key from value + firstEquals := strings.Index(line, "=") + firstColon := strings.Index(line, ":") splitString := strings.SplitN(line, "=", 2) - - if len(splitString) != 2 { - // try yaml mode! + if firstColon != -1 && (firstColon < firstEquals || firstEquals == -1) { + //this is a yaml-style line splitString = strings.SplitN(line, ":", 2) } diff --git a/godotenv_test.go b/godotenv_test.go index 9d7d884..4099201 100644 --- a/godotenv_test.go +++ b/godotenv_test.go @@ -205,6 +205,12 @@ func TestParsing(t *testing.T) { // parses yaml style options parseAndCompare(t, "OPTION_A: 1", "OPTION_A", "1") + //parses yaml values with equal signs + parseAndCompare(t, "OPTION_A: Foo=bar", "OPTION_A", "Foo=bar") + + // parses non-yaml options with colons + parseAndCompare(t, "OPTION_A=1:B", "OPTION_A", "1:B") + // parses export keyword parseAndCompare(t, "export OPTION_A=2", "OPTION_A", "2") parseAndCompare(t, `export OPTION_B='\n'`, "OPTION_B", "\n") From a905e995777b9f09a2234ffd7d5f0bf721cecee2 Mon Sep 17 00:00:00 2001 From: Alex Quick Date: Sun, 16 Jul 2017 18:43:49 -0400 Subject: [PATCH 4/4] fix panic with `"` as the value --- godotenv.go | 4 ++-- godotenv_test.go | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/godotenv.go b/godotenv.go index 172c4f5..8c6ff37 100644 --- a/godotenv.go +++ b/godotenv.go @@ -228,8 +228,8 @@ func parseValue(value string) string { // trim value = strings.Trim(value, " ") - // check if we've got quoted values - if value != "" { + // check if we've got quoted values or possible escapes + if len(value) > 1 { first := string(value[0:1]) last := string(value[len(value)-1:]) if first == last && strings.ContainsAny(first, `"'`) { diff --git a/godotenv_test.go b/godotenv_test.go index 4099201..d8f5890 100644 --- a/godotenv_test.go +++ b/godotenv_test.go @@ -252,6 +252,10 @@ func TestParsing(t *testing.T) { parseAndCompare(t, `FOO="bar\\\n\ b\az"`, "FOO", "bar\\\n baz") parseAndCompare(t, `FOO="bar\\r\ b\az"`, "FOO", "bar\\r baz") + parseAndCompare(t, `="value"`, "", "value") + parseAndCompare(t, `KEY="`, "KEY", "\"") + parseAndCompare(t, `KEY="value`, "KEY", "\"value") + // it 'throws an error if line format is incorrect' do // expect{env('lol$wut')}.to raise_error(Dotenv::FormatError) badlyFormattedLine := "lol$wut"