فهرست منبع

Merge pull request #180 from docker/unknown_comand_error

Display friendly message if unknown command is available in default context
Guillaume Tardif 5 سال پیش
والد
کامیت
4700364667
4فایلهای تغییر یافته به همراه49 افزوده شده و 3 حذف شده
  1. 17 2
      cli/dockerclassic/exec.go
  2. 17 1
      cli/main.go
  3. 13 0
      tests/e2e/e2e_test.go
  4. 2 0
      tests/e2e/testdata/unknown-foo-command.golden

+ 17 - 2
cli/dockerclassic/exec.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"os"
 	"os/exec"
+	"strings"
 
 	"github.com/spf13/cobra"
 
@@ -12,6 +13,9 @@ import (
 	"github.com/docker/api/context/store"
 )
 
+// ClassicCliName name of the classic cli binary
+const ClassicCliName = "docker-classic"
+
 // Exec delegates to docker-classic
 func Exec(ctx context.Context) {
 	currentContext := apicontext.CurrentContext(ctx)
@@ -21,13 +25,12 @@ func Exec(ctx context.Context) {
 	// Only run original docker command if the current context is not
 	// ours.
 	if err != nil {
-		cmd := exec.CommandContext(ctx, "docker-classic", os.Args[1:]...)
+		cmd := exec.CommandContext(ctx, ClassicCliName, os.Args[1:]...)
 		cmd.Stdin = os.Stdin
 		cmd.Stdout = os.Stdout
 		cmd.Stderr = os.Stderr
 		if err := cmd.Run(); err != nil {
 			if exiterr, ok := err.(*exec.ExitError); ok {
-				fmt.Fprintln(os.Stderr, exiterr.Error())
 				os.Exit(exiterr.ExitCode())
 			}
 			fmt.Fprintln(os.Stderr, err)
@@ -42,3 +45,15 @@ 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(ClassicCliName, dockerCommand, "--help")
+	b, e := cmd.CombinedOutput()
+	if e != nil {
+		fmt.Println(e)
+	}
+	output := string(b)
+	contains := strings.Contains(output, "Usage:\tdocker "+dockerCommand)
+	return contains
+}

+ 17 - 1
cli/main.go

@@ -34,6 +34,7 @@ import (
 	"os"
 	"os/signal"
 	"path/filepath"
+	"regexp"
 	"syscall"
 	"time"
 
@@ -171,11 +172,26 @@ func main() {
 			os.Exit(1)
 		}
 		dockerclassic.Exec(ctx)
-		fmt.Println(err)
+
+		checkIfUnknownCommandExistInDefaultContext(err, currentContext)
+		fmt.Fprintln(os.Stderr, err)
 		os.Exit(1)
 	}
 }
 
+func checkIfUnknownCommandExistInDefaultContext(err error, currentContext string) {
+	re := regexp.MustCompile(`unknown command "([^"]*)"`)
+	submatch := re.FindSubmatch([]byte(err.Error()))
+	if len(submatch) == 2 {
+		dockerCommand := string(submatch[1])
+
+		if dockerclassic.IsDefaultContextCommand(dockerCommand) {
+			fmt.Fprintf(os.Stderr, "Command \"%s\" not available in current context (%s), you can use the \"default\" context to run this command\n", dockerCommand, currentContext)
+			os.Exit(1)
+		}
+	}
+}
+
 func newSigContext() (context.Context, func()) {
 	ctx, cancel := context.WithCancel(context.Background())
 	s := make(chan os.Signal)

+ 13 - 0
tests/e2e/e2e_test.go

@@ -156,6 +156,19 @@ func (s *E2eSuite) TestLegacy() {
 	})
 }
 
+func (s *E2eSuite) TestLeaveLegacyErrorMessagesUnchanged() {
+	output, err := s.NewDockerCommand("foo").Exec()
+	golden.Assert(s.T(), output, "unknown-foo-command.golden")
+	Expect(err).NotTo(BeNil())
+}
+
+func (s *E2eSuite) TestDisplayFriendlyErrorMessageForLegacyCommands() {
+	s.NewDockerCommand("context", "create", "test-example", "example").ExecOrDie()
+	output, err := s.NewDockerCommand("--context", "test-example", "images").Exec()
+	Expect(output).To(Equal("Command \"images\" not available in current context (test-example), you can use the \"default\" context to run this command\n"))
+	Expect(err).NotTo(BeNil())
+}
+
 func (s *E2eSuite) TestMockBackend() {
 	It("creates a new test context to hardcoded example backend", func() {
 		s.NewDockerCommand("context", "create", "test-example", "example").ExecOrDie()

+ 2 - 0
tests/e2e/testdata/unknown-foo-command.golden

@@ -0,0 +1,2 @@
+docker: 'foo' is not a docker command.
+See 'docker --help'