cmd/go: look at runes, not bytes, when printing env vars

For #58508
Fixes #71863

Change-Id: Ib1ebaf751bcc6900da6ffd01a9462dd237e2c89a
Reviewed-on: https://go-review.googlesource.com/c/go/+/651295
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
Ian Lance Taylor 2025-02-20 22:20:38 -08:00 committed by Gopher Robot
parent e15d14873f
commit f062d7b10b

View file

@ -522,51 +522,56 @@ func PrintEnv(w io.Writer, env []cfg.EnvVar, onlyChanged bool) {
} }
} }
func hasNonGraphic(s string) bool { // isWindowsUnquotableRune reports whether r can't be quoted in a
for _, c := range []byte(s) { // Windows "set" command.
if c == '\r' || c == '\n' || (!unicode.IsGraphic(rune(c)) && !unicode.IsSpace(rune(c))) { // These runes will be replaced by the Unicode replacement character.
func isWindowsUnquotableRune(r rune) bool {
if r == '\r' || r == '\n' {
return true return true
} }
} return !unicode.IsGraphic(r) && !unicode.IsSpace(r)
return false }
func hasNonGraphic(s string) bool {
return strings.ContainsFunc(s, isWindowsUnquotableRune)
} }
func shellQuote(s string) string { func shellQuote(s string) string {
var b bytes.Buffer var sb strings.Builder
b.WriteByte('\'') sb.WriteByte('\'')
for _, x := range []byte(s) { for _, r := range s {
if x == '\'' { if r == '\'' {
// Close the single quoted string, add an escaped single quote, // Close the single quoted string, add an escaped single quote,
// and start another single quoted string. // and start another single quoted string.
b.WriteString(`'\''`) sb.WriteString(`'\''`)
} else { } else {
b.WriteByte(x) sb.WriteRune(r)
} }
} }
b.WriteByte('\'') sb.WriteByte('\'')
return b.String() return sb.String()
} }
func batchEscape(s string) string { func batchEscape(s string) string {
var b bytes.Buffer var sb strings.Builder
for _, x := range []byte(s) { for _, r := range s {
if x == '\r' || x == '\n' || (!unicode.IsGraphic(rune(x)) && !unicode.IsSpace(rune(x))) { if isWindowsUnquotableRune(r) {
b.WriteRune(unicode.ReplacementChar) sb.WriteRune(unicode.ReplacementChar)
continue continue
} }
switch x { switch r {
case '%': case '%':
b.WriteString("%%") sb.WriteString("%%")
case '<', '>', '|', '&', '^': case '<', '>', '|', '&', '^':
// These are special characters that need to be escaped with ^. See // These are special characters that need to be escaped with ^. See
// https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/set_1. // https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/set_1.
b.WriteByte('^') sb.WriteByte('^')
b.WriteByte(x) sb.WriteRune(r)
default: default:
b.WriteByte(x) sb.WriteRune(r)
} }
} }
return b.String() return sb.String()
} }
func printEnvAsJSON(env []cfg.EnvVar, onlyChanged bool) { func printEnvAsJSON(env []cfg.EnvVar, onlyChanged bool) {