Replace *Escape with *EscapeList

NinjaEscape and ShellEscape operated on lists, which led to
awkward NinjaEscape([]string{s})[0].  Replace NinjaEscape
and ShellEscape with NinjaEscapeList and ShellEscapeList,
and add new NinjaEscape and ShellEscape functions that
operate on a string.

Test: m checkbuild
Change-Id: I283d92cdddc8e0066a300015863a3eab66f77c23
This commit is contained in:
Colin Cross 2018-09-19 16:05:43 -07:00
parent 0799fad550
commit cc1ec0fedc
2 changed files with 42 additions and 21 deletions

View file

@ -16,28 +16,51 @@ package proptools
import "strings"
// NinjaEscape takes a slice of strings that may contain characters that are meaningful to ninja
// NinjaEscapeList takes a slice of strings that may contain characters that are meaningful to ninja
// ($), and escapes each string so they will be passed to bash. It is not necessary on input,
// output, or dependency names, those are handled by ModuleContext.Build. It is generally required
// on strings from properties in Blueprint files that are used as Args to ModuleContext.Build. A
// new slice containing the escaped strings is returned.
func NinjaEscape(slice []string) []string {
func NinjaEscapeList(slice []string) []string {
slice = append([]string(nil), slice...)
for i, s := range slice {
slice[i] = ninjaEscaper.Replace(s)
slice[i] = NinjaEscape(s)
}
return slice
}
// NinjaEscapeList takes a string that may contain characters that are meaningful to ninja
// ($), and escapes it so it will be passed to bash. It is not necessary on input,
// output, or dependency names, those are handled by ModuleContext.Build. It is generally required
// on strings from properties in Blueprint files that are used as Args to ModuleContext.Build. A
// new slice containing the escaped strings is returned.
func NinjaEscape(s string) string {
return ninjaEscaper.Replace(s)
}
var ninjaEscaper = strings.NewReplacer(
"$", "$$")
// ShellEscape takes a slice of strings that may contain characters that are meaningful to bash and
// escapes if necessary by wrapping them in single quotes, and replacing internal single quotes with
// ShellEscapeList takes a slice of strings that may contain characters that are meaningful to bash and
// escapes them if necessary by wrapping them in single quotes, and replacing internal single quotes with
// '\'' (one single quote to end the quoting, a shell-escaped single quote to insert a real single
// quote, and then a single quote to restarting quoting. A new slice containing the escaped strings
// is returned.
func ShellEscape(slice []string) []string {
func ShellEscapeList(slice []string) []string {
slice = append([]string(nil), slice...)
for i, s := range slice {
slice[i] = ShellEscape(s)
}
return slice
}
// ShellEscapeList takes string that may contain characters that are meaningful to bash and
// escapes it if necessary by wrapping it in single quotes, and replacing internal single quotes with
// '\'' (one single quote to end the quoting, a shell-escaped single quote to insert a real single
// quote, and then a single quote to restarting quoting.
func ShellEscape(s string) string {
shellUnsafeChar := func(r rune) bool {
switch {
case 'A' <= r && r <= 'Z',
@ -57,22 +80,20 @@ func ShellEscape(slice []string) []string {
}
}
slice = append([]string(nil), slice...)
for i, s := range slice {
if strings.IndexFunc(s, shellUnsafeChar) == -1 {
// No escaping necessary
continue
}
slice[i] = `'` + singleQuoteReplacer.Replace(s) + `'`
if strings.IndexFunc(s, shellUnsafeChar) == -1 {
// No escaping necessary
return s
}
return slice
return `'` + singleQuoteReplacer.Replace(s) + `'`
}
func NinjaAndShellEscape(slice []string) []string {
return ShellEscape(NinjaEscape(slice))
func NinjaAndShellEscapeList(slice []string) []string {
return ShellEscapeList(NinjaEscapeList(slice))
}
func NinjaAndShellEscape(s string) string {
return ShellEscape(NinjaEscape(s))
}
var singleQuoteReplacer = strings.NewReplacer(`'`, `'\''`)

View file

@ -93,7 +93,7 @@ var shellEscapeTestCase = []escapeTestCase{
func TestNinjaEscaping(t *testing.T) {
for _, testCase := range ninjaEscapeTestCase {
got := NinjaEscape([]string{testCase.in})[0]
got := NinjaEscape(testCase.in)
if got != testCase.out {
t.Errorf("%s: expected `%s` got `%s`", testCase.name, testCase.out, got)
}
@ -102,7 +102,7 @@ func TestNinjaEscaping(t *testing.T) {
func TestShellEscaping(t *testing.T) {
for _, testCase := range shellEscapeTestCase {
got := ShellEscape([]string{testCase.in})[0]
got := ShellEscape(testCase.in)
if got != testCase.out {
t.Errorf("%s: expected `%s` got `%s`", testCase.name, testCase.out, got)
}
@ -114,7 +114,7 @@ func TestExternalShellEscaping(t *testing.T) {
return
}
for _, testCase := range shellEscapeTestCase {
cmd := "echo -n " + ShellEscape([]string{testCase.in})[0]
cmd := "echo -n " + ShellEscape(testCase.in)
got, err := exec.Command("/bin/sh", "-c", cmd).Output()
if err != nil {
t.Error(err)