diff --git a/cli/cmd/context/create.go b/cli/cmd/context/create.go index 802a8a73..6c9b4eab 100644 --- a/cli/cmd/context/create.go +++ b/cli/cmd/context/create.go @@ -70,7 +70,8 @@ $ docker context create my-context --description "some description" --docker "ho Use: "create CONTEXT", Short: "Create new context", RunE: func(cmd *cobra.Command, args []string) error { - return mobycli.ExecCmd(cmd) + mobycli.Exec() + return nil }, Long: longHelp, } diff --git a/cli/cmd/context/inspect.go b/cli/cmd/context/inspect.go index cbc98ab0..bc8af24b 100644 --- a/cli/cmd/context/inspect.go +++ b/cli/cmd/context/inspect.go @@ -27,7 +27,8 @@ func inspectCommand() *cobra.Command { Use: "inspect", Short: "Display detailed information on one or more contexts", RunE: func(cmd *cobra.Command, args []string) error { - return mobycli.ExecCmd(cmd) + mobycli.Exec() + return nil }, } // flags matching delegated command in moby cli diff --git a/cli/cmd/context/ls.go b/cli/cmd/context/ls.go index 20c82ba7..910c371a 100644 --- a/cli/cmd/context/ls.go +++ b/cli/cmd/context/ls.go @@ -69,7 +69,8 @@ func runList(cmd *cobra.Command, opts lsOpts) error { return err } if opts.format != "" { - return mobycli.ExecCmd(cmd) + mobycli.Exec() + return nil } ctx := cmd.Context() diff --git a/cli/cmd/login/login.go b/cli/cmd/login/login.go index 0fee7222..f24ad27f 100644 --- a/cli/cmd/login/login.go +++ b/cli/cmd/login/login.go @@ -56,7 +56,8 @@ func runLogin(cmd *cobra.Command, args []string) error { backend := args[0] return errors.New("unknown backend type for cloud login: " + backend) } - return mobycli.ExecCmd(cmd) + mobycli.Exec() + return nil } func cloudLogin(cmd *cobra.Command, backendType string, params interface{}) error { diff --git a/cli/cmd/logout/logout.go b/cli/cmd/logout/logout.go index 0ea967a4..cfc63ed3 100644 --- a/cli/cmd/logout/logout.go +++ b/cli/cmd/logout/logout.go @@ -21,5 +21,6 @@ func Command() *cobra.Command { } func runLogout(cmd *cobra.Command, args []string) error { - return mobycli.ExecCmd(cmd) + mobycli.Exec() + return nil } diff --git a/cli/cmd/version.go b/cli/cmd/version.go index 3bea2b12..d3cd088d 100644 --- a/cli/cmd/version.go +++ b/cli/cmd/version.go @@ -51,7 +51,8 @@ func runVersion(cmd *cobra.Command, version string) error { // we don't want to fail on error, there is an error if the engine is not available but it displays client version info // Still, technically the [] byte versionResult could be nil, just let the original command display what it has to display if versionResult == nil { - return mobycli.ExecCmd(cmd) + mobycli.Exec() + return nil } var s string = string(versionResult) fmt.Print(strings.Replace(s, "\n Version:", "\n Azure integration "+displayedVersion+"\n Version:", 1)) diff --git a/cli/main.go b/cli/main.go index 0645a7c8..9ef5fd25 100644 --- a/cli/main.go +++ b/cli/main.go @@ -151,7 +151,7 @@ func main() { // --host and --version should immediately be forwarded to the original cli if opts.Host != "" || opts.Version { - mobycli.Exec(ctx) + mobycli.Exec() } if opts.Config == "" { diff --git a/cli/mobycli/exec.go b/cli/mobycli/exec.go index bbb6c4ea..c9cdfb15 100644 --- a/cli/mobycli/exec.go +++ b/cli/mobycli/exec.go @@ -21,10 +21,9 @@ import ( "fmt" "os" "os/exec" + "os/signal" "strings" - "github.com/spf13/cobra" - apicontext "github.com/docker/api/context" "github.com/docker/api/context/store" ) @@ -43,7 +42,7 @@ func ExecIfDefaultCtxType(ctx context.Context) { currentCtx, err := s.Get(currentContext) // Only run original docker command if the current context is not ours. if err != nil || mustDelegateToMoby(currentCtx.Type()) { - Exec(ctx) + Exec() } } @@ -57,12 +56,32 @@ func mustDelegateToMoby(ctxType string) bool { } // Exec delegates to com.docker.cli if on moby context -func Exec(ctx context.Context) { - cmd := exec.CommandContext(ctx, ComDockerCli, os.Args[1:]...) +func Exec() { + cmd := exec.Command(ComDockerCli, os.Args[1:]...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { + + signals := make(chan os.Signal) + childExit := make(chan bool) + signal.Notify(signals) // catch all signals + go func() { + for { + select { + case sig := <-signals: + err := cmd.Process.Signal(sig) + if err != nil { + fmt.Printf("WARNING could not forward signal %s to %s : %s\n", sig.String(), ComDockerCli, err.Error()) + } + case <-childExit: + return + } + } + }() + + err := cmd.Run() + childExit <- true + if err != nil { if exiterr, ok := err.(*exec.ExitError); ok { os.Exit(exiterr.ExitCode()) } @@ -72,14 +91,6 @@ func Exec(ctx context.Context) { os.Exit(0) } -// ExecCmd delegates the cli command to com.docker.cli. The error is never -// returned (process will exit with docker classic exit code), the return type -// is to make it easier to use with cobra commands -func ExecCmd(command *cobra.Command) error { - Exec(command.Context()) - return nil -} - // IsDefaultContextCommand checks if the command exists in the classic cli (issues a shellout --help) func IsDefaultContextCommand(dockerCommand string) bool { cmd := exec.Command(ComDockerCli, dockerCommand, "--help") diff --git a/tests/skip-win-ci-e2e/skip_win_ci_test.go b/tests/skip-win-ci-e2e/skip_win_ci_test.go index b8de4437..0bb5ce31 100644 --- a/tests/skip-win-ci-e2e/skip_win_ci_test.go +++ b/tests/skip-win-ci-e2e/skip_win_ci_test.go @@ -24,6 +24,8 @@ import ( "testing" "time" + "github.com/docker/api/cli/mobycli" + . "github.com/onsi/gomega" "github.com/stretchr/testify/suite" @@ -50,9 +52,10 @@ RUN sleep 100`), 0644)).To(Succeed()) _, err := ctx.Exec() errs <- err }() + mobyBuild := mobycli.ComDockerCli + " build --no-cache -t " + imageName err := WaitFor(time.Second, 10*time.Second, errs, func() bool { out := s.ListProcessesCommand().ExecOrDie() - return strings.Contains(out, imageName) + return strings.Contains(out, mobyBuild) }) Expect(err).NotTo(HaveOccurred()) log.Println("Killing docker process") @@ -60,7 +63,7 @@ RUN sleep 100`), 0644)).To(Succeed()) close(shutdown) err = WaitFor(time.Second, 12*time.Second, nil, func() bool { out := s.ListProcessesCommand().ExecOrDie() - return !strings.Contains(out, imageName) + return !strings.Contains(out, mobyBuild) }) Expect(err).NotTo(HaveOccurred()) })