Skip to content

Commit

Permalink
Quote environment variables. (#150)
Browse files Browse the repository at this point in the history
* Quote environment variables.

Fixes dotenv export for variables with newlines and other special
characters.

* Add unit tests for dotenv export.
  • Loading branch information
jmcarp authored and nickatsegment committed Sep 28, 2018
1 parent c201404 commit 28b12a8
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
18 changes: 17 additions & 1 deletion cmd/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/spf13/cobra"
)

const doubleQuoteSpecialChars = "\\\n\r\"!$`"

// exportCmd represents the export command
var (
exportFormat string
Expand Down Expand Up @@ -100,7 +102,7 @@ func exportAsEnvFile(params map[string]string, w io.Writer) error {
for _, k := range sortedKeys(params) {
key := strings.ToUpper(k)
key = strings.Replace(key, "-", "_", -1)
w.Write([]byte(fmt.Sprintf("%s=%s\n", key, params[k])))
w.Write([]byte(fmt.Sprintf(`%s="%s"`+"\n", key, doubleQuoteEscape(params[k]))))
}
return nil
}
Expand Down Expand Up @@ -164,3 +166,17 @@ func sortedKeys(params map[string]string) []string {
sort.Strings(keys)
return keys
}

func doubleQuoteEscape(line string) string {
for _, c := range doubleQuoteSpecialChars {
toReplace := "\\" + string(c)
if c == '\n' {
toReplace = `\n`
}
if c == '\r' {
toReplace = `\r`
}
line = strings.Replace(line, string(c), toReplace, -1)
}
return line
}
41 changes: 41 additions & 0 deletions cmd/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cmd

import (
"bytes"
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestExportDotenv(t *testing.T) {
tests := []struct {
name string
params map[string]string
output []string
}{
{
"simple",
map[string]string{"foo": "bar"},
[]string{`FOO="bar"`},
},
{
"escaped dollar",
map[string]string{"foo": "bar", "baz": "$qux"},
[]string{`FOO="bar"`, `BAZ="\$qux"`},
},
{
"escaped quote",
map[string]string{"foo": "bar", "baz": `"qux"`},
[]string{`FOO="bar"`, `BAZ="\"qux\""`},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
buf := &bytes.Buffer{}
err := exportAsEnvFile(test.params, buf)
assert.Nil(t, err)
assert.ElementsMatch(t, test.output, strings.Split(strings.Trim(buf.String(), "\n"), "\n"))
})
}
}

0 comments on commit 28b12a8

Please sign in to comment.