From 28d2cb55fd91cca64df4aa0ee4730476a3e15252 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Wed, 18 Nov 2020 10:50:34 -0800 Subject: [PATCH] main: Special error message for invalid top-level command Previously Terraform would react to an invalid top-level command the same way as for typing no command at all: just printing out the long top-level help directory. If someone's tried to type a command, it's more helpful to respond to that request by explaining directly that the command is invalid, rather than leaving the user to puzzle that out themselves by referring to the help text. As a bonus, this also allows us to use our "didyoumean" package to suggest possible alternatives if it seems like the user made a typo. --- main.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/main.go b/main.go index 183698408..2d26bb508 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/terraform/command/cliconfig" "github.com/hashicorp/terraform/command/format" "github.com/hashicorp/terraform/httpclient" + "github.com/hashicorp/terraform/internal/didyoumean" "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/version" "github.com/mattn/go-shellwords" @@ -282,6 +283,32 @@ func wrappedMain() int { AutocompleteUninstall: "uninstall-autocomplete", } + // Before we continue we'll check whether the requested command is + // actually known. If not, we might be able to suggest an alternative + // if it seems like the user made a typo. + // (This bypasses the built-in help handling in cli.CLI for the situation + // where a command isn't found, because it's likely more helpful to + // mention what specifically went wrong, rather than just printing out + // a big block of usage information.) + if cmd := cliRunner.Subcommand(); cmd != "" { + // Due to the design of cli.CLI, this special error message only works + // for typos of top-level commands. For a subcommand typo, like + // "terraform state posh", cmd would be "state" here and thus would + // be considered to exist, and it would print out its own usage message. + if _, exists := Commands[cmd]; !exists { + suggestions := make([]string, 0, len(Commands)) + for name := range Commands { + suggestions = append(suggestions, name) + } + suggestion := didyoumean.NameSuggestion(cmd, suggestions) + if suggestion != "" { + suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) + } + fmt.Fprintf(os.Stderr, "Terraform has no command named %q.%s\n\nTo see all of Terraform's top-level commands, run:\n terraform -help\n\n", cmd, suggestion) + return 1 + } + } + exitCode, err := cliRunner.Run() if err != nil { Ui.Error(fmt.Sprintf("Error executing CLI: %s", err.Error()))