Upstream twpayne/chezmoi state of the touched files before 41a618c046

This commit is contained in:
upstream committed 2026-10-10 12:28:07 +02:00
1 parent 4e184024be
commit 740f357900
2 files changed
+127

No files matched your search

+67
View File
@@ -0,0 +1,67 @@
package cmd
import (
"regexp"
"strings"
)
// nonShellLiteralRx is a regular expression that matches anything that is not a
// shell literal.
var nonShellLiteralRx = regexp.MustCompile(`[^+\-./0-9=A-Z_a-z]`)
// shellQuote returns s quoted as a shell argument, if necessary.
func shellQuote(s string) string {
const (
backslash = '\\'
singleQuote = '\''
)
switch {
case s == "":
return "''"
case nonShellLiteralRx.MatchString(s):
result := make([]byte, 0, 2+len(s))
inSingleQuotes := false
for _, b := range []byte(s) {
switch b {
case backslash:
if !inSingleQuotes {
result = append(result, singleQuote)
inSingleQuotes = true
}
result = append(result, backslash, backslash)
case singleQuote:
if inSingleQuotes {
result = append(result, singleQuote)
inSingleQuotes = false
}
result = append(result, '\\', singleQuote)
default:
if !inSingleQuotes {
result = append(result, singleQuote)
inSingleQuotes = true
}
result = append(result, b)
}
}
if inSingleQuotes {
result = append(result, singleQuote)
}
return string(result)
default:
return s
}
}
// shellQuoteCommand returns a string containing command and args shell quoted.
func shellQuoteCommand(command string, args []string) string {
if len(args) == 0 {
return shellQuote(command)
}
elems := make([]string, 1+len(args))
elems[0] = shellQuote(command)
for i, arg := range args {
elems[i+1] = shellQuote(arg)
}
return strings.Join(elems, " ")
}
+60
View File
@@ -0,0 +1,60 @@
package cmd
import (
"maps"
"slices"
"testing"
"github.com/alecthomas/assert/v2"
)
func TestShellQuote(t *testing.T) {
tcs := map[string]string{
``: `''`,
`'`: `\'`,
`''`: `\'\'`,
`'a'`: `\''a'\'`,
`\`: `'\\'`,
`\a`: `'\\a'`,
`$a`: `'$a'`,
`a`: `a`,
`a/b`: `a/b`,
`a b`: `'a b'`,
`--arg`: `--arg`,
`--arg=value`: `--arg=value`,
`it's`: `'it'\''s'`,
`$(echo foo)`: `'$(echo foo)'`,
}
for _, s := range slices.Sorted(maps.Keys(tcs)) {
assert.Equal(t, tcs[s], shellQuote(s), "quoting %q", s)
}
}
func TestShellQuoteCommand(t *testing.T) {
for _, tc := range []struct {
command string
args []string
expected string
}{
{
command: "command",
expected: "command",
},
{
command: "command with spaces",
expected: "'command with spaces'",
},
{
command: "command",
args: []string{"arg1"},
expected: "command arg1",
},
{
command: "command",
args: []string{"arg1", "arg 2 with spaces"},
expected: "command arg1 'arg 2 with spaces'",
},
} {
assert.Equal(t, tc.expected, shellQuoteCommand(tc.command, tc.args))
}
}