[config] support for old export-style config files

This commit is contained in:
Alex Quick
2017-05-01 01:48:02 -04:00
parent e7e01ee838
commit 133fdc1f0a
2 changed files with 19 additions and 8 deletions

View File

@@ -13,11 +13,16 @@ func TestExportfileRoundtrip(t *testing.T) {
Expect(env.Map()).To(Equal(pairs("Baz", "BOFF", "Foo", "Bar", "HI", "ho")))
Expect(env.String()).To(Equal("Baz='BOFF'\nFoo='Bar'\nHI='ho'"))
env, err = NewFromString("\n export HI='h\\\no\\'\n")
env, err = NewFromString("\n export HI='h\\\no\\' \n")
Expect(err).NotTo(HaveOccurred())
Expect(env.Map()).To(Equal(pairs("HI", "h\\\no\\")))
Expect(env.String()).To(Equal("HI='h\\\no\\'"))
env, err = NewFromString("\n export HI=ho\n")
Expect(err).NotTo(HaveOccurred())
Expect(env.Map()).To(Equal(pairs("HI", "ho")))
Expect(env.String()).To(Equal("HI='ho'"))
env, err = NewFromString("HI='ho'\nFOO=''\\''\nBAR='\\'''\\'''")
Expect(err).NotTo(HaveOccurred())
Expect(env.Map()).To(Equal(pairs("HI", "ho", "FOO", "'\nBAR=''")))
@@ -31,10 +36,8 @@ func TestExportfileRoundtrip(t *testing.T) {
func TestExportfileErrors(t *testing.T) {
RegisterTestingT(t)
_, err := NewFromString("FOO=bar") //values must be quoted
Expect(err).To(HaveOccurred())
_, err = NewFromString("FOO='bar\\''") //single quotes are not escaped this way
_, err := NewFromString("FOO='bar\\''") //single quotes are not escaped this way
Expect(err).To(HaveOccurred())
_, err = NewFromString("F\nOO='bar'") //keys cannot have embedded newlines

View File

@@ -6,6 +6,7 @@ import (
"errors"
"io"
"os"
"strings"
)
func parseEnv(name string, filename string) (*Env, error) {
@@ -24,7 +25,7 @@ func parseEnv(name string, filename string) (*Env, error) {
}
func parseEnvFromReader(name string, filename string, reader io.Reader) (*Env, error) {
//The file format looks like: `KEY='VALUE'`. Eait pair is terminated with a newline.
//The file format looks like: `KEY='VALUE'`. Each pair is terminated with a newline.
//All characters are valid for VALUE without escaping but one: the single quote.
//A single quote literal is represented by ending the quoting
//emitting a \' and resuming the quoting. So for VALUE to be "don't care":
@@ -40,6 +41,7 @@ func parseEnvFromReader(name string, filename string, reader io.Reader) (*Env, e
var buffer bytes.Buffer
var state = StateKey
var quoted = false
var exportStyle = false
var escaped = false
var key = ""
for char, _, err := buffered.ReadRune(); err == nil; char, _, err = buffered.ReadRune() {
@@ -48,6 +50,7 @@ func parseEnvFromReader(name string, filename string, reader io.Reader) (*Env, e
switch char {
case ' ':
if buffer.String() == "export" {
exportStyle = true
buffer.Truncate(0) //so we can read exportfiles as well as envfiles
} else if buffer.Len() == 0 {
continue //leading spaced are allowed but not encouraged
@@ -79,11 +82,16 @@ func parseEnvFromReader(name string, filename string, reader io.Reader) (*Env, e
buffer.WriteRune(char)
} else {
state = StateKey
env.Set(key, buffer.String())
value := buffer.String()
if exportStyle {
value = strings.TrimSpace(value)
}
env.Set(key, value)
buffer.Truncate(0)
key = ""
escaped = false
quoted = false
exportStyle = false
}
case '\\':
if quoted {
@@ -93,8 +101,8 @@ func parseEnvFromReader(name string, filename string, reader io.Reader) (*Env, e
escaped = true
}
default:
if !quoted {
return nil, errors.New("unquoted or unbalanced value for " + key)
if !quoted && !exportStyle {
return nil, errors.New("trailing content for value of " + key)
}
if escaped {
return nil, errors.New("invalid escape for " + key)