From 6801fccd360c88af728a74f28a6d0f0717ea3e0c Mon Sep 17 00:00:00 2001 From: Luis Davim Date: Sat, 21 May 2022 20:37:03 +0100 Subject: [PATCH] feat: support multi-line values Signed-off-by: Luis Davim --- fixtures/exported.env | 23 +++++++++++++++++++++++ fixtures/quoted.env | 2 ++ gotenv.go | 40 +++++++++++++++++++++++++++++++++++++--- gotenv_test.go | 23 +++++++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) diff --git a/fixtures/exported.env b/fixtures/exported.env index 5821377..c3ef9aa 100644 --- a/fixtures/exported.env +++ b/fixtures/exported.env @@ -1,2 +1,25 @@ export OPTION_A=2 export OPTION_B='\n' +# This is a comment +export OPTION_C='The MIT License (MIT) + +Copyright (c) 2013 Alif Rachmawadi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.' + diff --git a/fixtures/quoted.env b/fixtures/quoted.env index a03ce24..ce77cfb 100644 --- a/fixtures/quoted.env +++ b/fixtures/quoted.env @@ -6,3 +6,5 @@ OPTION_E="1" OPTION_F="2" OPTION_G="" OPTION_H="\n" +OPTION_I="some multi-line text +with \"escaped quotes\" and ${OPTION_A} variable" diff --git a/gotenv.go b/gotenv.go index d53e84f..70f0936 100644 --- a/gotenv.go +++ b/gotenv.go @@ -127,13 +127,48 @@ func StrictParse(r io.Reader) (Env, error) { firstLine := true for scanner.Scan() { - line := scanner.Text() + line := strings.TrimSpace(scanner.Text()) if firstLine { line = strings.TrimPrefix(line, bom) firstLine = false } + if line == "" || line[0] == '#' { + continue + } + + quote := "" + idx := strings.Index(line, "=") + if idx == -1 { + idx = strings.Index(line, ":") + } + if idx > 0 && idx < len(line)-1 { + val := strings.TrimSpace(line[idx+1:]) + if val[0] == '"' || val[0] == '\'' { + quote = val[:1] + idx = strings.LastIndex(strings.TrimSpace(val[1:]), quote) + if idx >= 0 && val[idx] != '\\' { + quote = "" + } + } + } + for quote != "" && scanner.Scan() { + l := scanner.Text() + line += "\n" + l + idx := strings.LastIndex(l, quote) + if idx > 0 && l[idx-1] == '\\' { + continue + } + if idx >= 0 { + quote = "" + } + } + + if quote != "" { + return env, fmt.Errorf("missing quotes") + } + err := parseLine(line, env) if err != nil { return env, err @@ -145,7 +180,6 @@ func StrictParse(r io.Reader) (Env, error) { var ( lineRgx = regexp.MustCompile(linePattern) - quotesRgx = regexp.MustCompile(`\A(['"])(.*)(['"])\z`) unescapeRgx = regexp.MustCompile(`\\([^$])`) varRgx = regexp.MustCompile(variablePattern) ) @@ -170,7 +204,7 @@ func parseLine(s string, env Env) error { val = strings.Trim(val, " ") // remove quotes '' or "" - val = quotesRgx.ReplaceAllString(val, "$2") + val = strings.Trim(val, `'"`) if hdq { val = strings.ReplaceAll(val, `\n`, "\n") diff --git a/gotenv_test.go b/gotenv_test.go index 490e86a..1e71f64 100644 --- a/gotenv_test.go +++ b/gotenv_test.go @@ -153,6 +153,27 @@ var fixtures = []struct { gotenv.Env{ "OPTION_A": "2", "OPTION_B": `\n`, + "OPTION_C": `The MIT License (MIT) + +Copyright (c) 2013 Alif Rachmawadi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.`, }, }, { @@ -176,6 +197,8 @@ var fixtures = []struct { "OPTION_F": "2", "OPTION_G": "", "OPTION_H": "\n", + "OPTION_I": `some multi-line text +with "escaped quotes" and 1 variable`, }, }, {