command: discard output from flags package and return errs directly (#22373)

Any command using meta.defaultFlagSet *might* occasionally exit before
the flag package's output got written. This caused flag error messages
to get lost. This PR discards the flag package output in favor of
directly returning the error to the end user.
This commit is contained in:
Kristin Laemmert 2019-08-16 08:31:21 -04:00 committed by GitHub
parent 7938b2994e
commit c9d62bb2f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 33 additions and 28 deletions

View File

@ -2,6 +2,7 @@ package command
import ( import (
"bufio" "bufio"
"fmt"
"strings" "strings"
"github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/addrs"
@ -29,6 +30,7 @@ func (c *ConsoleCommand) Run(args []string) int {
cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path") cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -54,6 +54,7 @@ func (c *FmtCommand) Run(args []string) int {
cmdFlags.BoolVar(&c.recursive, "recursive", false, "recursive") cmdFlags.BoolVar(&c.recursive, "recursive", false, "recursive")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -1,6 +1,7 @@
package command package command
import ( import (
"fmt"
"strings" "strings"
"github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/tfdiags"
@ -24,6 +25,7 @@ func (c *GetCommand) Run(args []string) int {
cmdFlags.BoolVar(&update, "update", false, "update") cmdFlags.BoolVar(&update, "update", false, "update")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -36,6 +36,7 @@ func (c *GraphCommand) Run(args []string) int {
cmdFlags.BoolVar(&verbose, "verbose", false, "verbose") cmdFlags.BoolVar(&verbose, "verbose", false, "verbose")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -1,13 +1,11 @@
package command package command
import ( import (
"bufio"
"bytes" "bytes"
"context" "context"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
@ -353,26 +351,7 @@ func (m *Meta) contextOpts() *terraform.ContextOpts {
// defaultFlagSet creates a default flag set for commands. // defaultFlagSet creates a default flag set for commands.
func (m *Meta) defaultFlagSet(n string) *flag.FlagSet { func (m *Meta) defaultFlagSet(n string) *flag.FlagSet {
f := flag.NewFlagSet(n, flag.ContinueOnError) f := flag.NewFlagSet(n, flag.ContinueOnError)
f.SetOutput(ioutil.Discard)
// Create an io.Writer that writes to our Ui properly for errors.
// This is kind of a hack, but it does the job. Basically: create
// a pipe, use a scanner to break it into lines, and output each line
// to the UI. Do this forever.
errR, errW := io.Pipe()
errScanner := bufio.NewScanner(errR)
go func() {
// This only needs to be alive long enough to write the help info if
// there is a flag error. Kill the scanner after a short duriation to
// prevent these from accumulating during tests, and cluttering up the
// stack traces.
time.AfterFunc(2*time.Second, func() {
errW.Close()
})
for errScanner.Scan() {
m.Ui.Error(errScanner.Text())
}
}()
f.SetOutput(errW)
// Set the default Usage to empty // Set the default Usage to empty
f.Usage = func() {} f.Usage = func() {}

View File

@ -36,6 +36,7 @@ func (c *OutputCommand) Run(args []string) int {
cmdFlags.StringVar(&module, "module", "", "module") cmdFlags.StringVar(&module, "module", "", "module")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -35,6 +35,7 @@ func (c *ProvidersCommand) Run(args []string) int {
cmdFlags := c.Meta.defaultFlagSet("providers") cmdFlags := c.Meta.defaultFlagSet("providers")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -35,6 +35,7 @@ func (c *ProvidersSchemaCommand) Run(args []string) int {
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -33,6 +33,7 @@ func (c *ShowCommand) Run(args []string) int {
cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output") cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -28,6 +28,7 @@ func (c *StateListCommand) Run(args []string) int {
cmdFlags.StringVar(&statePath, "state", "", "path") cmdFlags.StringVar(&statePath, "state", "", "path")
lookupId := cmdFlags.String("id", "", "Restrict output to paths with a resource having the specified ID.") lookupId := cmdFlags.String("id", "", "Restrict output to paths with a resource having the specified ID.")
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return cli.RunResultHelp return cli.RunResultHelp
} }
args = cmdFlags.Args() args = cmdFlags.Args()

View File

@ -36,7 +36,8 @@ func (c *StateMvCommand) Run(args []string) int {
cmdFlags.StringVar(&c.statePath, "state", "", "path") cmdFlags.StringVar(&c.statePath, "state", "", "path")
cmdFlags.StringVar(&statePathOut, "state-out", "", "path") cmdFlags.StringVar(&statePathOut, "state-out", "", "path")
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return cli.RunResultHelp c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1
} }
args = cmdFlags.Args() args = cmdFlags.Args()
if len(args) != 2 { if len(args) != 2 {

View File

@ -7,7 +7,6 @@ import (
"github.com/hashicorp/terraform/states/statefile" "github.com/hashicorp/terraform/states/statefile"
"github.com/hashicorp/terraform/states/statemgr" "github.com/hashicorp/terraform/states/statemgr"
"github.com/mitchellh/cli"
) )
// StatePullCommand is a Command implementation that shows a single resource. // StatePullCommand is a Command implementation that shows a single resource.
@ -24,7 +23,8 @@ func (c *StatePullCommand) Run(args []string) int {
cmdFlags := c.Meta.defaultFlagSet("state pull") cmdFlags := c.Meta.defaultFlagSet("state pull")
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return cli.RunResultHelp c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1
} }
args = cmdFlags.Args() args = cmdFlags.Args()

View File

@ -31,7 +31,8 @@ func (c *StatePushCommand) Run(args []string) int {
cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state") cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout") cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return cli.RunResultHelp c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1
} }
args = cmdFlags.Args() args = cmdFlags.Args()

View File

@ -30,7 +30,8 @@ func (c *StateRmCommand) Run(args []string) int {
cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout") cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
cmdFlags.StringVar(&c.statePath, "state", "", "path") cmdFlags.StringVar(&c.statePath, "state", "", "path")
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return cli.RunResultHelp c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1
} }
args = cmdFlags.Args() args = cmdFlags.Args()

View File

@ -27,7 +27,8 @@ func (c *StateShowCommand) Run(args []string) int {
cmdFlags := c.Meta.defaultFlagSet("state show") cmdFlags := c.Meta.defaultFlagSet("state show")
cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path") cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return cli.RunResultHelp c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1
} }
args = cmdFlags.Args() args = cmdFlags.Args()
if len(args) != 1 { if len(args) != 1 {

View File

@ -35,6 +35,7 @@ func (c *TaintCommand) Run(args []string) int {
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path") cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -29,6 +29,7 @@ func (c *UnlockCommand) Run(args []string) int {
cmdFlags.BoolVar(&force, "force", false, "force") cmdFlags.BoolVar(&force, "force", false, "force")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -35,6 +35,7 @@ func (c *UntaintCommand) Run(args []string) int {
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path") cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -38,6 +38,7 @@ func (c *ValidateCommand) Run(args []string) int {
cmdFlags.Var(varFiles, "var-file", "variable file") cmdFlags.Var(varFiles, "var-file", "variable file")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -34,6 +34,7 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
cmdFlags.DurationVar(&stateLockTimeout, "lock-timeout", 0, "lock timeout") cmdFlags.DurationVar(&stateLockTimeout, "lock-timeout", 0, "lock timeout")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -2,6 +2,7 @@ package command
import ( import (
"bytes" "bytes"
"fmt"
"strings" "strings"
"github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/tfdiags"
@ -24,6 +25,7 @@ func (c *WorkspaceListCommand) Run(args []string) int {
cmdFlags := c.Meta.defaultFlagSet("workspace list") cmdFlags := c.Meta.defaultFlagSet("workspace list")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -36,6 +36,7 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
cmdFlags.StringVar(&statePath, "state", "", "terraform state file") cmdFlags.StringVar(&statePath, "state", "", "terraform state file")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -25,6 +25,7 @@ func (c *WorkspaceSelectCommand) Run(args []string) int {
cmdFlags := c.Meta.defaultFlagSet("workspace select") cmdFlags := c.Meta.defaultFlagSet("workspace select")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }

View File

@ -1,6 +1,7 @@
package command package command
import ( import (
"fmt"
"strings" "strings"
"github.com/posener/complete" "github.com/posener/complete"
@ -19,6 +20,7 @@ func (c *WorkspaceShowCommand) Run(args []string) int {
cmdFlags := c.Meta.extendedFlagSet("workspace show") cmdFlags := c.Meta.extendedFlagSet("workspace show")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1 return 1
} }