From f152f83a6e3aba0eb7d5ce2f0c73463ac307ec55 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 31 Jul 2018 14:37:43 -0400 Subject: [PATCH] cmd/go/internal/modfetch/codehost: quote arguments to commands printed from -x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the arguments — particularly format strings passed to git commands — may contain spaces, and it's useful to be able to paste commands from 'go get -x foo' directly into a shell to reproduce their output. Change-Id: I4f0c0b4e05db8b5232458e9a271f2ccbb665e85a Reviewed-on: https://go-review.googlesource.com/126955 Run-TryBot: Bryan C. Mills Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- .../go/internal/modfetch/codehost/codehost.go | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go index 9c07b96957..4103ddc717 100644 --- a/src/cmd/go/internal/modfetch/codehost/codehost.go +++ b/src/cmd/go/internal/modfetch/codehost/codehost.go @@ -201,6 +201,10 @@ func Run(dir string, cmdline ...interface{}) ([]byte, error) { return RunWithStdin(dir, nil, cmdline...) } +// bashQuoter escapes characters that have special meaning in double-quoted strings in the bash shell. +// See https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html. +var bashQuoter = strings.NewReplacer(`"`, `\"`, `$`, `\$`, "`", "\\`", `\`, `\\`) + func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte, error) { if dir != "" { muIface, ok := dirLock.Load(dir) @@ -214,11 +218,31 @@ func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte, cmd := str.StringList(cmdline...) if cfg.BuildX { - var text string + text := new(strings.Builder) if dir != "" { - text = "cd " + dir + "; " + text.WriteString("cd ") + text.WriteString(dir) + text.WriteString("; ") + } + for i, arg := range cmd { + if i > 0 { + text.WriteByte(' ') + } + switch { + case strings.ContainsAny(arg, "'"): + // Quote args that could be mistaken for quoted args. + text.WriteByte('"') + text.WriteString(bashQuoter.Replace(arg)) + text.WriteByte('"') + case strings.ContainsAny(arg, "$`\\*?[\"\t\n\v\f\r \u0085\u00a0"): + // Quote args that contain special characters, glob patterns, or spaces. + text.WriteByte('\'') + text.WriteString(arg) + text.WriteByte('\'') + default: + text.WriteString(arg) + } } - text += strings.Join(cmd, " ") fmt.Fprintf(os.Stderr, "%s\n", text) start := time.Now() defer func() {