Merge pull request #180 from docker/unknown_comand_error

Display friendly message if unknown command is available in default context
This commit is contained in:
Guillaume Tardif 2020-06-08 09:25:18 +02:00 committed by GitHub
commit 4700364667
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 3 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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()

View File

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