8000 file: quote keys using the write delimiter by team-humaki · Pull Request #397 · go-ini/ini · GitHub
[go: up one dir, main page]

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,25 @@ func (f *File) Append(source interface{}, others ...interface{}) error {
return f.Reload()
}

// quoteKeyNameOnWrite surrounds a key if writing it raw would be ambiguous
// given the write-side delimiter. Parse-time extra delimiters (':' in the
// default "=:" set) must not force quoting — keys like Samba's
// "fruit:metadata" are valid when the write delimiter is "=".
func (f *File) quoteKeyNameOnWrite(kname string) string {
writeDelim := f.options.KeyValueDelimiterOnWrite
if writeDelim == "" {
writeDelim = "="
}
switch {
case strings.Contains(kname, `"`) || strings.ContainsAny(kname, writeDelim):
return "`" + kname + "`"
case strings.Contains(kname, "`"):
return `"""` + kname + `"""`
default:
return kname
}
}

func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
equalSign := DefaultFormatLeft + f.options.KeyValueDelimiterOnWrite + DefaultFormatRight

Expand Down Expand Up @@ -392,14 +411,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
alignLength := 0
if PrettyFormat {
for _, kname := range sec.keyList {
keyLength := len(kname)
// First case will surround key by ` and second by """
if strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters) {
keyLength += 2
} else if strings.Contains(kname, "`") {
keyLength += 6
}

keyLength := len(f.quoteKeyNameOnWrite(kname))
if keyLength > alignLength {
alignLength = keyLength
}
Expand Down Expand Up @@ -437,10 +449,8 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
switch {
case key.isAutoIncrement:
kname = "-"
case strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters):
kname = "`" + kname + "`"
case strings.Contains(kname, "`"):
kname = `"""` + kname + `"""`
default:
kname = f.quoteKeyNameOnWrite(kname)
}

writeKeyValue := func(val string) (bool, error) {
Expand Down
20 changes: 20 additions & 0 deletions file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,26 @@ Note -> Hello world!
assert.Equal(t, expected, actual.Bytes())
}

func TestFile_WriteKeyWithColonInName(t *testing.T) {
f := Empty()
sec, err := f.NewSection("global")
require.NoError(t, err)
_, err = sec.NewKey("vfs objects", "catia fruit streams_xattr")
require.NoError(t, err)
_, err = sec.NewKey("fruit:metadata", "stream")
require.NoError(t, err)
_, err = sec.NewKey("a=b", "quoted-because-write-delim")
require.NoError(t, err)

var buf bytes.Buffer
_, err = f.WriteTo(&buf)
require.NoError(t, err)
out := buf.String()
assert.Contains(t, out, "fruit:metadata")
assert.NotContains(t, out, "`fruit:metadata`")
assert.Contains(t, out, "`a=b`")
}

// Inspired by https://github.com/go-ini/ini/issues/207
func TestReloadAfterShadowLoad(t *testing.T) {
f, err := ShadowLoad([]byte(`
Expand Down
0