From 9952a1262574f15a3bb24de1314a092c4e10785e Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Tue, 31 Jan 2023 15:04:20 +0000 Subject: [PATCH] monitor: add shell escape feature Debuggers like GDB support prefixing a command with an exclamation mark "!" to pass the rest of the command to the shell. We can mimic this functionality. Additionally, we can enable shlex parsing easily by using the google/shlex utility. Signed-off-by: Justin Chadwell --- monitor/monitor.go | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/monitor/monitor.go b/monitor/monitor.go index 41491fee..689a7613 100644 --- a/monitor/monitor.go +++ b/monitor/monitor.go @@ -2,8 +2,11 @@ package monitor import ( "context" + "errors" "fmt" "io" + "os/exec" + "runtime" "sort" "strings" "sync" @@ -12,6 +15,7 @@ import ( "github.com/containerd/console" controllerapi "github.com/docker/buildx/commands/controller/pb" "github.com/docker/buildx/util/ioset" + "github.com/google/shlex" "github.com/sirupsen/logrus" "golang.org/x/term" ) @@ -116,13 +120,30 @@ func RunMonitor(ctx context.Context, curRef string, options controllerapi.BuildO } return } - args := strings.Fields(l) // TODO: use shlex + + if strings.HasPrefix(l, "!") { + raw := defaultShell(runtime.GOOS) + raw = append(raw, l[1:]) + cmd := exec.Command(raw[0], raw[1:]...) + + // cmd.Stdin = stdin // TODO: support stdin + cmd.Stdout = stdout + cmd.Stderr = stderr + if err := cmd.Run(); err != nil && !errors.Is(err, &exec.ExitError{}) { + fmt.Fprintf(stdout, "command failed: %v\n", err) + } + continue + } + + args, err := shlex.Split(l) + if err != nil { + fmt.Fprintf(stdout, "failed to parse command: %v", err) + continue + } if len(args) == 0 { continue } switch args[0] { - case "": - // nop case "reload": if curRef != "" { if err := c.Disconnect(ctx, curRef); err != nil { @@ -255,3 +276,10 @@ type nopCloser struct { } func (c nopCloser) Close() error { return nil } + +func defaultShell(os string) []string { + if os == "windows" { + return []string{"cmd", "/S", "/C"} + } + return []string{"/bin/sh", "-c"} +}