Explorar el Código

Display friendly message if unknown command is available in default context

Guillaume Tardif hace 5 años
padre
commit
f939dd4d47
Se han modificado 3 ficheros con 41 adiciones y 2 borrados
  1. 17 1
      cli/dockerclassic/exec.go
  2. 17 1
      cli/main.go
  3. 7 0
      tests/e2e/e2e_test.go

+ 17 - 1
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,7 +25,7 @@ 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
@@ -41,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)

+ 7 - 0
tests/e2e/e2e_test.go

@@ -162,6 +162,13 @@ func (s *E2eSuite) TestLeaveLegacyErrorMessagesUnchanged() {
 	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()