mirror of
https://github.com/thegeeklab/drone-yaml.git
synced 2024-11-22 01:50:40 +00:00
attempt to improve string escaping
This commit is contained in:
parent
596b719f96
commit
82ab5cffdd
2
yaml/pretty/testdata/cron.yml
vendored
2
yaml/pretty/testdata/cron.yml
vendored
@ -5,7 +5,7 @@ kind: cron
|
|||||||
spec:
|
spec:
|
||||||
branch: master
|
branch: master
|
||||||
|
|
||||||
schedule: "1 * * * *"
|
schedule: 1 * * * *
|
||||||
|
|
||||||
deployment:
|
deployment:
|
||||||
|
|
||||||
|
2
yaml/pretty/testdata/cron.yml.golden
vendored
2
yaml/pretty/testdata/cron.yml.golden
vendored
@ -3,7 +3,7 @@ version: 1
|
|||||||
kind: cron
|
kind: cron
|
||||||
name: nightly
|
name: nightly
|
||||||
spec:
|
spec:
|
||||||
schedule: "1 * * * *"
|
schedule: 1 * * * *
|
||||||
branch: master
|
branch: master
|
||||||
deployment:
|
deployment:
|
||||||
target: production
|
target: production
|
||||||
|
2
yaml/pretty/testdata/manifest.yml.golden
vendored
2
yaml/pretty/testdata/manifest.yml.golden
vendored
@ -45,7 +45,7 @@ data: >
|
|||||||
kind: cron
|
kind: cron
|
||||||
name: nightly
|
name: nightly
|
||||||
spec:
|
spec:
|
||||||
schedule: "1 * * * *"
|
schedule: 1 * * * *
|
||||||
branch: master
|
branch: master
|
||||||
deployment:
|
deployment:
|
||||||
target: production
|
target: production
|
||||||
|
@ -14,7 +14,11 @@
|
|||||||
|
|
||||||
package pretty
|
package pretty
|
||||||
|
|
||||||
import "github.com/drone/drone-yaml/yaml"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/drone/drone-yaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
func isPrimative(v interface{}) bool {
|
func isPrimative(v interface{}) bool {
|
||||||
switch v.(type) {
|
switch v.(type) {
|
||||||
@ -63,10 +67,8 @@ func isZero(v interface{}) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isQuoted(b rune) bool {
|
func isEscapeCode(b rune) bool {
|
||||||
switch b {
|
switch b {
|
||||||
case '#', ',', '[', ']', '{', '}', '&', '*', '!', '\'', '"', '%', '@', '`':
|
|
||||||
return true
|
|
||||||
case '\a', '\b', '\f', '\n', '\r', '\t', '\v':
|
case '\a', '\b', '\f', '\n', '\r', '\t', '\v':
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
@ -74,6 +76,61 @@ func isQuoted(b rune) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isQuoted(s string) bool {
|
||||||
|
// if the string is empty it should be quoted.
|
||||||
|
if len(s) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0, r1 byte
|
||||||
|
t := strings.TrimSpace(s)
|
||||||
|
|
||||||
|
// if the trimmed string does not match the string, it
|
||||||
|
// has starting or tailing white space and therefore
|
||||||
|
// needs to be quoted to preserve the whitespace
|
||||||
|
if t != s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(t) > 0 {
|
||||||
|
r0 = t[0]
|
||||||
|
}
|
||||||
|
if len(t) > 1 {
|
||||||
|
r1 = t[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r0 {
|
||||||
|
// if the yaml starts with any of these characters
|
||||||
|
// the string should be quoted.
|
||||||
|
case ',', '[', ']', '{', '}', '*', '"', '\'', '%', '@', '`', '|', '>', '#':
|
||||||
|
return true
|
||||||
|
|
||||||
|
case '&', '!', '-', ':', '?':
|
||||||
|
// if the yaml starts with any of these characters,
|
||||||
|
// followed by whitespace, the string should be quoted.
|
||||||
|
if r1 == ' ' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var prev rune
|
||||||
|
for _, b := range s {
|
||||||
|
switch {
|
||||||
|
case isEscapeCode(b):
|
||||||
|
return true
|
||||||
|
case b == ' ' && prev == ':':
|
||||||
|
return true
|
||||||
|
case b == '#' && prev == ' ':
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
prev = b
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the string ends in : it should be quoted otherwise
|
||||||
|
// it is interpreted as an object.
|
||||||
|
return strings.HasSuffix(t, ":")
|
||||||
|
}
|
||||||
|
|
||||||
func chunk(s string, chunkSize int) []string {
|
func chunk(s string, chunkSize int) []string {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return []string{s}
|
return []string{s}
|
||||||
|
@ -21,6 +21,73 @@ import (
|
|||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestQuoted(t *testing.T) {
|
||||||
|
tests := []struct{
|
||||||
|
before, after string
|
||||||
|
}{
|
||||||
|
{"", `""`},
|
||||||
|
{"foo", "foo"},
|
||||||
|
|
||||||
|
// special characters only quoted when followed
|
||||||
|
// by whitespace.
|
||||||
|
{"&foo", "&foo"},
|
||||||
|
{"!foo", "!foo"},
|
||||||
|
{"-foo", "-foo"},
|
||||||
|
{":foo", ":foo"},
|
||||||
|
|
||||||
|
{"& foo", `"& foo"`},
|
||||||
|
{"! foo", `"! foo"`},
|
||||||
|
{"- foo", `"- foo"`},
|
||||||
|
{": foo", `": foo"`},
|
||||||
|
|
||||||
|
{" & foo", `" & foo"`},
|
||||||
|
{" ! foo", `" ! foo"`},
|
||||||
|
{" - foo", `" - foo"`},
|
||||||
|
{" : foo", `" : foo"`},
|
||||||
|
|
||||||
|
// special characters only quoted when it is the
|
||||||
|
// first character in the string.
|
||||||
|
{",foo", `",foo"`},
|
||||||
|
{"[foo", `"[foo"`},
|
||||||
|
{"]foo", `"]foo"`},
|
||||||
|
{"{foo", `"{foo"`},
|
||||||
|
{"}foo", `"}foo"`},
|
||||||
|
{"*foo", `"*foo"`},
|
||||||
|
{`"foo`, `"\"foo"`},
|
||||||
|
{`'foo`, `"'foo"`},
|
||||||
|
{`%foo`, `"%foo"`},
|
||||||
|
{`@foo`, `"@foo"`},
|
||||||
|
{`|foo`, `"|foo"`},
|
||||||
|
{`>foo`, `">foo"`},
|
||||||
|
{`#foo`, `"#foo"`},
|
||||||
|
|
||||||
|
{`foo:bar`, `foo:bar`},
|
||||||
|
{`foo :bar`, `foo :bar`},
|
||||||
|
{`foo: bar`, `"foo: bar"`},
|
||||||
|
{`foo:`, `"foo:"`},
|
||||||
|
{`alpine:3.8`, `alpine:3.8`}, // verify docker image names are ok
|
||||||
|
|
||||||
|
// comments should be escaped. A comment is a pound
|
||||||
|
// sybol preceded by a space.
|
||||||
|
{`foo#bar`, `foo#bar`},
|
||||||
|
{`foo #bar`, `"foo #bar"`},
|
||||||
|
|
||||||
|
// strings with newlines and control characters
|
||||||
|
// should be escaped
|
||||||
|
{"foo\nbar", "\"foo\\nbar\""},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
buf := new(baseWriter)
|
||||||
|
writeEncode(buf, test.before)
|
||||||
|
a := test.after
|
||||||
|
b := buf.String()
|
||||||
|
if b != a {
|
||||||
|
t.Errorf("Want %q, got %q", a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestChunk(t *testing.T) {
|
func TestChunk(t *testing.T) {
|
||||||
s := strings.Join(testChunk, "")
|
s := strings.Join(testChunk, "")
|
||||||
got, want := chunk(s, 64), testChunk
|
got, want := chunk(s, 64), testChunk
|
||||||
|
@ -19,7 +19,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
"github.com/drone/drone-yaml/yaml"
|
||||||
)
|
)
|
||||||
@ -196,28 +195,11 @@ func writeEncode(w writer, v string) {
|
|||||||
w.WriteByte('"')
|
w.WriteByte('"')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
trimmed := strings.TrimSpace(v)
|
if isQuoted(v) {
|
||||||
if strings.HasPrefix(trimmed, "| ") {
|
|
||||||
fmt.Fprintf(w, "%q", v)
|
fmt.Fprintf(w, "%q", v)
|
||||||
return
|
} else {
|
||||||
|
w.WriteString(v)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(trimmed, "> ") {
|
|
||||||
fmt.Fprintf(w, "%q", v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var prev rune
|
|
||||||
for _, b := range v {
|
|
||||||
if isQuoted(b) {
|
|
||||||
fmt.Fprintf(w, "%q", v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if b == ' ' && prev == ':' {
|
|
||||||
fmt.Fprintf(w, "%q", v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
prev = b
|
|
||||||
}
|
|
||||||
w.WriteString(v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeValue(w writer, v interface{}) {
|
func writeValue(w writer, v interface{}) {
|
||||||
|
@ -36,7 +36,9 @@ func TestWriteComplexValue(t *testing.T) {
|
|||||||
got, want := b.String(), strings.TrimSpace(testComplexValue)
|
got, want := b.String(), strings.TrimSpace(testComplexValue)
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("Unexpected block format")
|
t.Errorf("Unexpected block format")
|
||||||
print(got)
|
println(got)
|
||||||
|
println("---")
|
||||||
|
println(want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user