commands: make sure the correct flagset is used

A lot of commands used `c.Meta.flagSet()` to create the initial flagset for the command, while quite a few of them didn’t actually use or support the flags that are then added.

So I updated a few commands to use `flag.NewFlagSet()` instead to only add the flags that are actually needed/supported.

Additionally this prevents a few commands from using locking while they actually don’t need locking (as locking is enabled as a default in `c.Meta.flagSet()`.
This commit is contained in:
Sander van Harmelen 2018-11-21 15:35:27 +01:00
parent 7d5db9522f
commit ef9054562e
34 changed files with 227 additions and 196 deletions

View File

@ -29,7 +29,7 @@ func (c *ZeroTwelveUpgradeCommand) Run(args []string) int {
var skipConfirm, force bool var skipConfirm, force bool
flags := c.Meta.flagSet("0.12upgrade") flags := c.Meta.extendedFlagSet("0.12upgrade")
flags.BoolVar(&skipConfirm, "yes", false, "skip confirmation prompt") flags.BoolVar(&skipConfirm, "yes", false, "skip confirmation prompt")
flags.BoolVar(&force, "force", false, "override duplicate upgrade heuristic") flags.BoolVar(&force, "force", false, "override duplicate upgrade heuristic")
if err := flags.Parse(args); err != nil { if err := flags.Parse(args); err != nil {

View File

@ -38,7 +38,7 @@ func (c *ApplyCommand) Run(args []string) int {
cmdName = "destroy" cmdName = "destroy"
} }
cmdFlags := c.Meta.flagSet(cmdName) cmdFlags := c.Meta.extendedFlagSet(cmdName)
cmdFlags.BoolVar(&autoApprove, "auto-approve", false, "skip interactive approval of plan before applying") cmdFlags.BoolVar(&autoApprove, "auto-approve", false, "skip interactive approval of plan before applying")
if c.Destroy { if c.Destroy {
cmdFlags.BoolVar(&destroyForce, "force", false, "deprecated: same as auto-approve") cmdFlags.BoolVar(&destroyForce, "force", false, "deprecated: same as auto-approve")

View File

@ -25,7 +25,7 @@ func (c *ConsoleCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("console") cmdFlags := c.Meta.defaultFlagSet("console")
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 {
@ -74,6 +74,7 @@ func (c *ConsoleCommand) Run(args []string) int {
c.showDiagnostics(diags) c.showDiagnostics(diags)
return 1 return 1
} }
{ {
var moreDiags tfdiags.Diagnostics var moreDiags tfdiags.Diagnostics
opReq.Variables, moreDiags = c.collectVariableValues() opReq.Variables, moreDiags = c.collectVariableValues()

View File

@ -20,7 +20,7 @@ func (c *DebugJSON2DotCommand) Run(args []string) int {
if err != nil { if err != nil {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("debug json2dot") cmdFlags := c.Meta.extendedFlagSet("debug json2dot")
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return cli.RunResultHelp return cli.RunResultHelp

View File

@ -2,7 +2,6 @@ package command
import ( import (
"bytes" "bytes"
"flag"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -46,14 +45,13 @@ func (c *FmtCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := flag.NewFlagSet("fmt", flag.ContinueOnError) cmdFlags := c.Meta.defaultFlagSet("fmt")
cmdFlags.BoolVar(&c.list, "list", true, "list") cmdFlags.BoolVar(&c.list, "list", true, "list")
cmdFlags.BoolVar(&c.write, "write", true, "write") cmdFlags.BoolVar(&c.write, "write", true, "write")
cmdFlags.BoolVar(&c.diff, "diff", false, "diff") cmdFlags.BoolVar(&c.diff, "diff", false, "diff")
cmdFlags.BoolVar(&c.check, "check", false, "check") cmdFlags.BoolVar(&c.check, "check", false, "check")
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 {
return 1 return 1
} }

View File

@ -1,7 +1,6 @@
package command package command
import ( import (
"flag"
"fmt" "fmt"
"strings" "strings"
@ -22,7 +21,7 @@ func (c *GetCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := flag.NewFlagSet("get", flag.ContinueOnError) cmdFlags := c.Meta.defaultFlagSet("get")
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 {

View File

@ -1,7 +1,6 @@
package command package command
import ( import (
"flag"
"fmt" "fmt"
"strings" "strings"
@ -20,21 +19,21 @@ type GraphCommand struct {
} }
func (c *GraphCommand) Run(args []string) int { func (c *GraphCommand) Run(args []string) int {
var moduleDepth int
var verbose bool
var drawCycles bool var drawCycles bool
var graphTypeStr string var graphTypeStr string
var moduleDepth int
var verbose bool
args, err := c.Meta.process(args, false) args, err := c.Meta.process(args, false)
if err != nil { if err != nil {
return 1 return 1
} }
cmdFlags := flag.NewFlagSet("graph", flag.ContinueOnError) cmdFlags := c.Meta.defaultFlagSet("graph")
cmdFlags.IntVar(&moduleDepth, "module-depth", -1, "module-depth")
cmdFlags.BoolVar(&verbose, "verbose", false, "verbose")
cmdFlags.BoolVar(&drawCycles, "draw-cycles", false, "draw-cycles") cmdFlags.BoolVar(&drawCycles, "draw-cycles", false, "draw-cycles")
cmdFlags.StringVar(&graphTypeStr, "type", "", "type") cmdFlags.StringVar(&graphTypeStr, "type", "", "type")
cmdFlags.IntVar(&moduleDepth, "module-depth", -1, "module-depth")
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 {
return 1 return 1
@ -187,12 +186,9 @@ Options:
-module-depth=n Specifies the depth of modules to show in the output. -module-depth=n Specifies the depth of modules to show in the output.
By default this is -1, which will expand all. By default this is -1, which will expand all.
-no-color If specified, output won't contain any color.
-type=plan Type of graph to output. Can be: plan, plan-destroy, apply, -type=plan Type of graph to output. Can be: plan, plan-destroy, apply,
validate, input, refresh. validate, input, refresh.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }

View File

@ -37,7 +37,7 @@ func (c *ImportCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("import") cmdFlags := c.Meta.extendedFlagSet("import")
cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", 0, "parallelism") cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", 0, "parallelism")
cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path") cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path") cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")

View File

@ -50,7 +50,8 @@ func (c *InitCommand) Run(args []string) int {
if err != nil { if err != nil {
return 1 return 1
} }
cmdFlags := c.flagSet("init")
cmdFlags := c.Meta.extendedFlagSet("init")
cmdFlags.BoolVar(&flagBackend, "backend", true, "") cmdFlags.BoolVar(&flagBackend, "backend", true, "")
cmdFlags.Var(flagConfigExtra, "backend-config", "") cmdFlags.Var(flagConfigExtra, "backend-config", "")
cmdFlags.StringVar(&flagFromModule, "from-module", "", "copy the source of the given module into the directory before init") cmdFlags.StringVar(&flagFromModule, "from-module", "", "copy the source of the given module into the directory before init")
@ -63,7 +64,6 @@ func (c *InitCommand) Run(args []string) int {
cmdFlags.BoolVar(&flagUpgrade, "upgrade", false, "") cmdFlags.BoolVar(&flagUpgrade, "upgrade", false, "")
cmdFlags.Var(&flagPluginPath, "plugin-dir", "plugin directory") cmdFlags.Var(&flagPluginPath, "plugin-dir", "plugin directory")
cmdFlags.BoolVar(&flagVerifyPlugins, "verify-plugins", true, "verify plugins") cmdFlags.BoolVar(&flagVerifyPlugins, "verify-plugins", true, "verify plugins")
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 {
return 1 return 1

View File

@ -136,8 +136,6 @@ type Meta struct {
// parallelism is used to control the number of concurrent operations // parallelism is used to control the number of concurrent operations
// allowed when walking the graph // allowed when walking the graph
// //
// shadow is used to enable/disable the shadow graph
//
// provider is to specify specific resource providers // provider is to specify specific resource providers
// //
// stateLock is set to false to disable state locking // stateLock is set to false to disable state locking
@ -153,7 +151,6 @@ type Meta struct {
stateOutPath string stateOutPath string
backupPath string backupPath string
parallelism int parallelism int
shadow bool
provider string provider string
stateLock bool stateLock bool
stateLockTimeout time.Duration stateLockTimeout time.Duration
@ -350,25 +347,9 @@ func (m *Meta) contextOpts() *terraform.ContextOpts {
return &opts return &opts
} }
// flags adds the meta flags to the given FlagSet. // defaultFlagSet creates a default flag set for commands.
func (m *Meta) flagSet(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.BoolVar(&m.input, "input", true, "input")
f.Var((*FlagTargetSlice)(&m.targets), "target", "resource to target")
if m.variableArgs.items == nil {
m.variableArgs = newRawFlags("-var")
}
varValues := m.variableArgs.Alias("-var")
varFiles := m.variableArgs.Alias("-var-file")
f.Var(varValues, "var", "variables")
f.Var(varFiles, "var-file", "variable file")
// Advanced (don't need documentation, or unlikely to be set)
f.BoolVar(&m.shadow, "shadow", true, "shadow graph")
// Experimental features
experiment.Flag(f)
// Create an io.Writer that writes to our Ui properly for errors. // 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 // This is kind of a hack, but it does the job. Basically: create
@ -393,8 +374,30 @@ func (m *Meta) flagSet(n string) *flag.FlagSet {
// Set the default Usage to empty // Set the default Usage to empty
f.Usage = func() {} f.Usage = func() {}
// command that bypass locking will supply their own flag on this var, but return f
// set the initial meta value to true as a failsafe. }
// extendedFlagSet adds custom flags that are mostly used by commands
// that are used to run an operation like plan or apply.
func (m *Meta) extendedFlagSet(n string) *flag.FlagSet {
f := m.defaultFlagSet(n)
f.BoolVar(&m.input, "input", true, "input")
f.Var((*FlagTargetSlice)(&m.targets), "target", "resource to target")
if m.variableArgs.items == nil {
m.variableArgs = newRawFlags("-var")
}
varValues := m.variableArgs.Alias("-var")
varFiles := m.variableArgs.Alias("-var-file")
f.Var(varValues, "var", "variables")
f.Var(varFiles, "var-file", "variable file")
// Experimental features
experiment.Flag(f)
// commands that bypass locking will supply their own flag on this var,
// but set the initial meta value to true as a failsafe.
m.stateLock = true m.stateLock = true
return f return f

View File

@ -1864,7 +1864,7 @@ func testMetaBackend(t *testing.T, args []string) *Meta {
var m Meta var m Meta
m.Ui = new(cli.MockUi) m.Ui = new(cli.MockUi)
m.process(args, true) m.process(args, true)
f := m.flagSet("test") f := m.extendedFlagSet("test")
if err := f.Parse(args); err != nil { if err := f.Parse(args); err != nil {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)
} }

View File

@ -389,6 +389,9 @@ func (f rawFlags) Empty() bool {
} }
func (f rawFlags) AllItems() []rawFlag { func (f rawFlags) AllItems() []rawFlag {
if f.items == nil {
return nil
}
return *f.items return *f.items
} }

View File

@ -73,7 +73,7 @@ func TestMetaInputMode(t *testing.T) {
m := new(Meta) m := new(Meta)
args := []string{} args := []string{}
fs := m.flagSet("foo") fs := m.extendedFlagSet("foo")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
@ -92,7 +92,7 @@ func TestMetaInputMode_envVar(t *testing.T) {
m := new(Meta) m := new(Meta)
args := []string{} args := []string{}
fs := m.flagSet("foo") fs := m.extendedFlagSet("foo")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
@ -124,7 +124,7 @@ func TestMetaInputMode_disable(t *testing.T) {
m := new(Meta) m := new(Meta)
args := []string{"-input=false"} args := []string{"-input=false"}
fs := m.flagSet("foo") fs := m.extendedFlagSet("foo")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
@ -160,7 +160,7 @@ func TestMetaInputMode_defaultVars(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
fs := m.flagSet("foo") fs := m.extendedFlagSet("foo")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
@ -177,7 +177,7 @@ func TestMetaInputMode_vars(t *testing.T) {
m := new(Meta) m := new(Meta)
args := []string{"-var", "foo=bar"} args := []string{"-var", "foo=bar"}
fs := m.flagSet("foo") fs := m.extendedFlagSet("foo")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }

View File

@ -3,7 +3,6 @@ package command
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"flag"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
@ -31,7 +30,7 @@ func (c *OutputCommand) Run(args []string) int {
var module string var module string
var jsonOutput bool var jsonOutput bool
cmdFlags := flag.NewFlagSet("output", flag.ContinueOnError) cmdFlags := c.Meta.defaultFlagSet("output")
cmdFlags.BoolVar(&jsonOutput, "json", false, "json") cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path") cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
cmdFlags.StringVar(&module, "module", "", "module") cmdFlags.StringVar(&module, "module", "", "module")

View File

@ -25,12 +25,11 @@ func (c *PlanCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("plan") cmdFlags := c.Meta.extendedFlagSet("plan")
cmdFlags.BoolVar(&destroy, "destroy", false, "destroy") cmdFlags.BoolVar(&destroy, "destroy", false, "destroy")
cmdFlags.BoolVar(&refresh, "refresh", true, "refresh") cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
cmdFlags.StringVar(&outPath, "out", "", "path") cmdFlags.StringVar(&outPath, "out", "", "path")
cmdFlags.IntVar( cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism")
&c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism")
cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path") cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
cmdFlags.BoolVar(&detailed, "detailed-exitcode", false, "detailed-exitcode") cmdFlags.BoolVar(&detailed, "detailed-exitcode", false, "detailed-exitcode")
cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state") cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")

View File

@ -29,7 +29,7 @@ func (c *ProvidersCommand) Synopsis() string {
func (c *ProvidersCommand) Run(args []string) int { func (c *ProvidersCommand) Run(args []string) int {
c.Meta.process(args, false) c.Meta.process(args, false)
cmdFlags := c.Meta.flagSet("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 {
return 1 return 1

View File

@ -21,7 +21,7 @@ func (c *RefreshCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("refresh") cmdFlags := c.Meta.extendedFlagSet("refresh")
cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path") cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", 0, "parallelism") cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", 0, "parallelism")
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path") cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
@ -72,13 +72,15 @@ func (c *RefreshCommand) Run(args []string) int {
// Build the operation // Build the operation
opReq := c.Operation(b) opReq := c.Operation(b)
opReq.Type = backend.OperationTypeRefresh
opReq.ConfigDir = configPath opReq.ConfigDir = configPath
opReq.Type = backend.OperationTypeRefresh
opReq.ConfigLoader, err = c.initConfigLoader() opReq.ConfigLoader, err = c.initConfigLoader()
if err != nil { if err != nil {
c.showDiagnostics(err) c.showDiagnostics(err)
return 1 return 1
} }
{ {
var moreDiags tfdiags.Diagnostics var moreDiags tfdiags.Diagnostics
opReq.Variables, moreDiags = c.collectVariableValues() opReq.Variables, moreDiags = c.collectVariableValues()

View File

@ -1,7 +1,6 @@
package command package command
import ( import (
"flag"
"fmt" "fmt"
"os" "os"
"strings" "strings"
@ -28,8 +27,7 @@ func (c *ShowCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := flag.NewFlagSet("show", flag.ContinueOnError) cmdFlags := c.Meta.defaultFlagSet("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 {
return 1 return 1
@ -87,6 +85,7 @@ func (c *ShowCommand) Run(args []string) int {
return 1 return 1
} }
// Get the schemas from the context
schemas := ctx.Schemas() schemas := ctx.Schemas()
env := c.Workspace() env := c.Workspace()

View File

@ -21,7 +21,7 @@ func (c *StateListCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("state list") cmdFlags := c.Meta.defaultFlagSet("state list")
cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path") cmdFlags.StringVar(&c.Meta.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 {

View File

@ -24,11 +24,13 @@ func (c *StateMvCommand) Run(args []string) int {
var backupPathOut, statePathOut string var backupPathOut, statePathOut string
var dryRun bool var dryRun bool
cmdFlags := c.Meta.flagSet("state mv") cmdFlags := c.Meta.defaultFlagSet("state mv")
cmdFlags.BoolVar(&dryRun, "dry-run", false, "dry run") cmdFlags.BoolVar(&dryRun, "dry-run", false, "dry run")
cmdFlags.StringVar(&c.backupPath, "backup", "-", "backup") cmdFlags.StringVar(&c.backupPath, "backup", "-", "backup")
cmdFlags.StringVar(&c.statePath, "state", "", "path")
cmdFlags.StringVar(&backupPathOut, "backup-out", "-", "backup") cmdFlags.StringVar(&backupPathOut, "backup-out", "-", "backup")
cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock states")
cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
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 return cli.RunResultHelp
@ -301,6 +303,10 @@ Options:
to be specified if -state-out is set to a different path to be specified if -state-out is set to a different path
than -state. than -state.
-lock=true Lock the state files when locking is supported.
-lock-timeout=0s Duration to retry a state lock.
-state=PATH Path to the source state file. Defaults to the configured -state=PATH Path to the source state file. Defaults to the configured
backend, or "terraform.tfstate" backend, or "terraform.tfstate"

View File

@ -22,7 +22,7 @@ func (c *StatePullCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("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 return cli.RunResultHelp
} }

View File

@ -26,8 +26,10 @@ func (c *StatePushCommand) Run(args []string) int {
} }
var flagForce bool var flagForce bool
cmdFlags := c.Meta.flagSet("state push") cmdFlags := c.Meta.defaultFlagSet("state push")
cmdFlags.BoolVar(&flagForce, "force", false, "") cmdFlags.BoolVar(&flagForce, "force", false, "")
cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
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 return cli.RunResultHelp
} }
@ -139,6 +141,10 @@ Options:
-force Write the state even if lineages don't match or the -force Write the state even if lineages don't match or the
remote serial is higher. remote serial is higher.
-lock=true Lock the state file when locking is supported.
-lock-timeout=0s Duration to retry a state lock.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }

View File

@ -22,15 +22,17 @@ func (c *StateRmCommand) Run(args []string) int {
} }
var dryRun bool var dryRun bool
cmdFlags := c.Meta.flagSet("state show") cmdFlags := c.Meta.defaultFlagSet("state rm")
cmdFlags.BoolVar(&dryRun, "dry-run", false, "dry run") cmdFlags.BoolVar(&dryRun, "dry-run", false, "dry run")
cmdFlags.StringVar(&c.backupPath, "backup", "-", "backup") cmdFlags.StringVar(&c.backupPath, "backup", "-", "backup")
cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
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 return cli.RunResultHelp
} }
args = cmdFlags.Args()
args = cmdFlags.Args()
if len(args) < 1 { if len(args) < 1 {
c.Ui.Error("At least one address is required.\n") c.Ui.Error("At least one address is required.\n")
return cli.RunResultHelp return cli.RunResultHelp
@ -165,6 +167,10 @@ Options:
will write it to the same path as the statefile with will write it to the same path as the statefile with
a backup extension. a backup extension.
-lock=true Lock the state file when locking is supported.
-lock-timeout=0s Duration to retry a state lock.
-state=PATH Path to the source state file. Defaults to the configured -state=PATH Path to the source state file. Defaults to the configured
backend, or "terraform.tfstate" backend, or "terraform.tfstate"

View File

@ -24,7 +24,7 @@ func (c *StateShowCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("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 return cli.RunResultHelp
@ -66,6 +66,7 @@ func (c *StateShowCommand) Run(args []string) int {
// Build the operation (required to get the schemas) // Build the operation (required to get the schemas)
opReq := c.Operation(b) opReq := c.Operation(b)
opReq.ConfigDir = cwd opReq.ConfigDir = cwd
opReq.ConfigLoader, err = c.initConfigLoader() opReq.ConfigLoader, err = c.initConfigLoader()
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing config loader: %s", err)) c.Ui.Error(fmt.Sprintf("Error initializing config loader: %s", err))
@ -79,14 +80,6 @@ func (c *StateShowCommand) Run(args []string) int {
return 1 return 1
} }
// Make sure to unlock the state
defer func() {
err := opReq.StateLocker.Unlock(nil)
if err != nil {
c.Ui.Error(err.Error())
}
}()
// Get the schemas from the context // Get the schemas from the context
schemas := ctx.Schemas() schemas := ctx.Schemas()

View File

@ -5,10 +5,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/tfdiags"
) )
@ -24,16 +23,16 @@ func (c *TaintCommand) Run(args []string) int {
return 1 return 1
} }
var allowMissing bool
var module string var module string
cmdFlags := c.Meta.flagSet("taint") var allowMissing bool
cmdFlags := c.Meta.defaultFlagSet("taint")
cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "module") cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "module")
cmdFlags.StringVar(&module, "module", "", "module")
cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path") cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
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")
cmdFlags.StringVar(&module, "module", "", "module")
cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "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 {
return 1 return 1
@ -199,8 +198,6 @@ Options:
-lock-timeout=0s Duration to retry a state lock. -lock-timeout=0s Duration to retry a state lock.
-no-color If specified, output won't contain any color.
-state=path Path to read and save state (unless state-out -state=path Path to read and save state (unless state-out
is specified). Defaults to "terraform.tfstate". is specified). Defaults to "terraform.tfstate".

View File

@ -23,8 +23,8 @@ func (c *UnlockCommand) Run(args []string) int {
return 1 return 1
} }
force := false var force bool
cmdFlags := c.Meta.flagSet("force-unlock") cmdFlags := c.Meta.defaultFlagSet("force-unlock")
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 {
@ -68,13 +68,13 @@ func (c *UnlockCommand) Run(args []string) int {
} }
env := c.Workspace() env := c.Workspace()
st, err := b.StateMgr(env) stateMgr, err := b.StateMgr(env)
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err)) c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
return 1 return 1
} }
_, isLocal := st.(*statemgr.Filesystem) _, isLocal := stateMgr.(*statemgr.Filesystem)
if !force { if !force {
// Forcing this doesn't do anything, but doesn't break anything either, // Forcing this doesn't do anything, but doesn't break anything either,
@ -103,7 +103,7 @@ func (c *UnlockCommand) Run(args []string) int {
} }
} }
if err := st.Unlock(lockID); err != nil { if err := stateMgr.Unlock(lockID); err != nil {
c.Ui.Error(fmt.Sprintf("Failed to unlock state: %s", err)) c.Ui.Error(fmt.Sprintf("Failed to unlock state: %s", err))
return 1 return 1
} }

View File

@ -5,12 +5,10 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/tfdiags"
"github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/tfdiags"
) )
// UntaintCommand is a cli.Command implementation that manually untaints // UntaintCommand is a cli.Command implementation that manually untaints
@ -25,16 +23,16 @@ func (c *UntaintCommand) Run(args []string) int {
return 1 return 1
} }
var allowMissing bool
var module string var module string
cmdFlags := c.Meta.flagSet("untaint") var allowMissing bool
cmdFlags := c.Meta.defaultFlagSet("untaint")
cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "module") cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "module")
cmdFlags.StringVar(&module, "module", "", "module")
cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path") cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
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")
cmdFlags.StringVar(&module, "module", "", "module")
cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "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 {
return 1 return 1
@ -202,8 +200,6 @@ Options:
default this will be root. Child modules can be specified default this will be root. Child modules can be specified
by names. Ex. "consul" or "consul.vpc" (nested modules). by names. Ex. "consul" or "consul.vpc" (nested modules).
-no-color If specified, output won't contain any color.
-state=path Path to read and save state (unless state-out -state=path Path to read and save state (unless state-out
is specified). Defaults to "terraform.tfstate". is specified). Defaults to "terraform.tfstate".

View File

@ -25,13 +25,18 @@ func (c *ValidateCommand) Run(args []string) int {
return 1 return 1
} }
var jsonOutput bool if c.Meta.variableArgs.items == nil {
c.Meta.variableArgs = newRawFlags("-var")
cmdFlags := c.Meta.flagSet("validate")
cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output")
cmdFlags.Usage = func() {
c.Ui.Error(c.Help())
} }
varValues := c.Meta.variableArgs.Alias("-var")
varFiles := c.Meta.variableArgs.Alias("-var-file")
var jsonOutput bool
cmdFlags := c.Meta.defaultFlagSet("validate")
cmdFlags.BoolVar(&jsonOutput, "json", false, "produce JSON output")
cmdFlags.Var(varValues, "var", "variables")
cmdFlags.Var(varFiles, "var-file", "variable file")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return 1 return 1
} }
@ -68,49 +73,6 @@ func (c *ValidateCommand) Run(args []string) int {
return c.showResults(diags, jsonOutput) return c.showResults(diags, jsonOutput)
} }
func (c *ValidateCommand) Synopsis() string {
return "Validates the Terraform files"
}
func (c *ValidateCommand) Help() string {
helpText := `
Usage: terraform validate [options] [dir]
Validate the configuration files in a directory, referring only to the
configuration and not accessing any remote services such as remote state,
provider APIs, etc.
Validate runs checks that verify whether a configuration is
internally-consistent, regardless of any provided variables or existing
state. It is thus primarily useful for general verification of reusable
modules, including correctness of attribute names and value types.
To verify configuration in the context of a particular run (a particular
target workspace, operation variables, etc), use the following command
instead:
terraform plan -validate-only
It is safe to run this command automatically, for example as a post-save
check in a text editor or as a test step for a re-usable module in a CI
system.
Validation requires an initialized working directory with any referenced
plugins and modules installed. To initialize a working directory for
validation without accessing any configured remote backend, use:
terraform init -backend=false
If dir is not specified, then the current directory will be used.
Options:
-json Produce output in a machine-readable JSON format, suitable for
use in e.g. text editor integrations.
-no-color If specified, output won't contain any color.
`
return strings.TrimSpace(helpText)
}
func (c *ValidateCommand) validate(dir string) tfdiags.Diagnostics { func (c *ValidateCommand) validate(dir string) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics var diags tfdiags.Diagnostics
@ -254,3 +216,45 @@ func (c *ValidateCommand) showResults(diags tfdiags.Diagnostics, jsonOutput bool
} }
return 0 return 0
} }
func (c *ValidateCommand) Synopsis() string {
return "Validates the Terraform files"
}
func (c *ValidateCommand) Help() string {
helpText := `
Usage: terraform validate [options] [dir]
Validate the configuration files in a directory, referring only to the
configuration and not accessing any remote services such as remote state,
provider APIs, etc.
Validate runs checks that verify whether a configuration is
internally-consistent, regardless of any provided variables or existing
state. It is thus primarily useful for general verification of reusable
modules, including correctness of attribute names and value types.
To verify configuration in the context of a particular run (a particular
target workspace, operation variables, etc), use the following command
instead:
terraform plan -validate-only
It is safe to run this command automatically, for example as a post-save
check in a text editor or as a test step for a re-usable module in a CI
system.
Validation requires an initialized working directory with any referenced
plugins and modules installed. To initialize a working directory for
validation without accessing any configured remote backend, use:
terraform init -backend=false
If dir is not specified, then the current directory will be used.
Options:
-json Produce output in a machine-readable JSON format, suitable for
use in e.g. text editor integrations.
`
return strings.TrimSpace(helpText)
}

View File

@ -22,7 +22,7 @@ func (c *WorkspaceCommand) Run(args []string) int {
envCommandShowWarning(c.Ui, c.LegacyName) envCommandShowWarning(c.Ui, c.LegacyName)
cmdFlags := c.Meta.flagSet("workspace") cmdFlags := c.Meta.extendedFlagSet("workspace")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
c.Ui.Output(c.Help()) c.Ui.Output(c.Help())

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"strings" "strings"
"time"
"github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/tfdiags"
@ -24,23 +25,28 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
envCommandShowWarning(c.Ui, c.LegacyName) envCommandShowWarning(c.Ui, c.LegacyName)
force := false var force bool
cmdFlags := c.Meta.flagSet("workspace") var stateLock bool
var stateLockTimeout time.Duration
cmdFlags := c.Meta.defaultFlagSet("workspace delete")
cmdFlags.BoolVar(&force, "force", false, "force removal of a non-empty workspace") cmdFlags.BoolVar(&force, "force", false, "force removal of a non-empty workspace")
cmdFlags.BoolVar(&stateLock, "lock", true, "lock state")
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 {
return 1 return 1
} }
args = cmdFlags.Args() args = cmdFlags.Args()
if len(args) == 0 { if len(args) == 0 {
c.Ui.Error("expected NAME.\n") c.Ui.Error("expected NAME.\n")
return cli.RunResultHelp return cli.RunResultHelp
} }
delEnv := args[0] workspace := args[0]
if !validWorkspaceName(delEnv) { if !validWorkspaceName(workspace) {
c.Ui.Error(fmt.Sprintf(envInvalidName, delEnv)) c.Ui.Error(fmt.Sprintf(envInvalidName, workspace))
return 1 return 1
} }
@ -69,41 +75,41 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
return 1 return 1
} }
states, err := b.Workspaces() workspaces, err := b.Workspaces()
if err != nil { if err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())
return 1 return 1
} }
exists := false exists := false
for _, s := range states { for _, ws := range workspaces {
if delEnv == s { if workspace == ws {
exists = true exists = true
break break
} }
} }
if !exists { if !exists {
c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envDoesNotExist), delEnv)) c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envDoesNotExist), workspace))
return 1 return 1
} }
if delEnv == c.Workspace() { if workspace == c.Workspace() {
c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envDelCurrent), delEnv)) c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envDelCurrent), workspace))
return 1 return 1
} }
// we need the actual state to see if it's empty // we need the actual state to see if it's empty
sMgr, err := b.StateMgr(delEnv) stateMgr, err := b.StateMgr(workspace)
if err != nil { if err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())
return 1 return 1
} }
var stateLocker clistate.Locker var stateLocker clistate.Locker
if c.stateLock { if stateLock {
stateLocker = clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize()) stateLocker = clistate.NewLocker(context.Background(), stateLockTimeout, c.Ui, c.Colorize())
if err := stateLocker.Lock(sMgr, "workspace_delete"); err != nil { if err := stateLocker.Lock(stateMgr, "workspace_delete"); err != nil {
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err)) c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
return 1 return 1
} }
@ -111,15 +117,15 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
stateLocker = clistate.NewNoopLocker() stateLocker = clistate.NewNoopLocker()
} }
if err := sMgr.RefreshState(); err != nil { if err := stateMgr.RefreshState(); err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())
return 1 return 1
} }
hasResources := sMgr.State().HasResources() hasResources := stateMgr.State().HasResources()
if hasResources && !force { if hasResources && !force {
c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envNotEmpty), delEnv)) c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envNotEmpty), workspace))
return 1 return 1
} }
@ -134,7 +140,7 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
// be delegated from the Backend to the State itself. // be delegated from the Backend to the State itself.
stateLocker.Unlock(nil) stateLocker.Unlock(nil)
err = b.DeleteWorkspace(delEnv) err = b.DeleteWorkspace(workspace)
if err != nil { if err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())
return 1 return 1
@ -142,14 +148,14 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
c.Ui.Output( c.Ui.Output(
c.Colorize().Color( c.Colorize().Color(
fmt.Sprintf(envDeleted, delEnv), fmt.Sprintf(envDeleted, workspace),
), ),
) )
if hasResources { if hasResources {
c.Ui.Output( c.Ui.Output(
c.Colorize().Color( c.Colorize().Color(
fmt.Sprintf(envWarnNotEmpty, delEnv), fmt.Sprintf(envWarnNotEmpty, workspace),
), ),
) )
} }
@ -181,6 +187,11 @@ Usage: terraform workspace delete [OPTIONS] NAME [DIR]
Options: Options:
-force remove a non-empty workspace. -force remove a non-empty workspace.
-lock=true Lock the state file when locking is supported.
-lock-timeout=0s Duration to retry a state lock.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }

View File

@ -21,7 +21,7 @@ func (c *WorkspaceListCommand) Run(args []string) int {
envCommandShowWarning(c.Ui, c.LegacyName) envCommandShowWarning(c.Ui, c.LegacyName)
cmdFlags := c.Meta.flagSet("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 {
return 1 return 1
@ -93,6 +93,7 @@ func (c *WorkspaceListCommand) Help() string {
Usage: terraform workspace list [DIR] Usage: terraform workspace list [DIR]
List Terraform workspaces. List Terraform workspaces.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"strings" "strings"
"time"
"github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/states/statefile" "github.com/hashicorp/terraform/states/statefile"
@ -26,30 +27,34 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
envCommandShowWarning(c.Ui, c.LegacyName) envCommandShowWarning(c.Ui, c.LegacyName)
statePath := "" var stateLock bool
var stateLockTimeout time.Duration
cmdFlags := c.Meta.flagSet("workspace new") var statePath string
cmdFlags := c.Meta.defaultFlagSet("workspace new")
cmdFlags.BoolVar(&stateLock, "lock", true, "lock state")
cmdFlags.DurationVar(&stateLockTimeout, "lock-timeout", 0, "lock timeout")
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 {
return 1 return 1
} }
args = cmdFlags.Args() args = cmdFlags.Args()
if len(args) == 0 { if len(args) == 0 {
c.Ui.Error("Expected a single argument: NAME.\n") c.Ui.Error("Expected a single argument: NAME.\n")
return cli.RunResultHelp return cli.RunResultHelp
} }
newEnv := args[0] workspace := args[0]
if !validWorkspaceName(newEnv) { if !validWorkspaceName(workspace) {
c.Ui.Error(fmt.Sprintf(envInvalidName, newEnv)) c.Ui.Error(fmt.Sprintf(envInvalidName, workspace))
return 1 return 1
} }
// You can't ask to create a workspace when you're overriding the // You can't ask to create a workspace when you're overriding the
// workspace name to be something different. // workspace name to be something different.
if current, isOverridden := c.WorkspaceOverridden(); current != newEnv && isOverridden { if current, isOverridden := c.WorkspaceOverridden(); current != workspace && isOverridden {
c.Ui.Error(envIsOverriddenNewError) c.Ui.Error(envIsOverriddenNewError)
return 1 return 1
} }
@ -79,32 +84,32 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
return 1 return 1
} }
states, err := b.Workspaces() workspaces, err := b.Workspaces()
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to get configured named states: %s", err)) c.Ui.Error(fmt.Sprintf("Failed to get configured named states: %s", err))
return 1 return 1
} }
for _, s := range states { for _, ws := range workspaces {
if newEnv == s { if workspace == ws {
c.Ui.Error(fmt.Sprintf(envExists, newEnv)) c.Ui.Error(fmt.Sprintf(envExists, workspace))
return 1 return 1
} }
} }
_, err = b.StateMgr(newEnv) _, err = b.StateMgr(workspace)
if err != nil { if err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())
return 1 return 1
} }
// now set the current workspace locally // now set the current workspace locally
if err := c.SetWorkspace(newEnv); err != nil { if err := c.SetWorkspace(workspace); err != nil {
c.Ui.Error(fmt.Sprintf("Error selecting new workspace: %s", err)) c.Ui.Error(fmt.Sprintf("Error selecting new workspace: %s", err))
return 1 return 1
} }
c.Ui.Output(c.Colorize().Color(fmt.Sprintf( c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
strings.TrimSpace(envCreated), newEnv))) strings.TrimSpace(envCreated), workspace)))
if statePath == "" { if statePath == "" {
// if we're not loading a state, then we're done // if we're not loading a state, then we're done
@ -112,15 +117,15 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
} }
// load the new Backend state // load the new Backend state
sMgr, err := b.StateMgr(newEnv) stateMgr, err := b.StateMgr(workspace)
if err != nil { if err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())
return 1 return 1
} }
if c.stateLock { if stateLock {
stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize()) stateLocker := clistate.NewLocker(context.Background(), stateLockTimeout, c.Ui, c.Colorize())
if err := stateLocker.Lock(sMgr, "workspace_delete"); err != nil { if err := stateLocker.Lock(stateMgr, "workspace_new"); err != nil {
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err)) c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
return 1 return 1
} }
@ -141,12 +146,12 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
} }
// save the existing state in the new Backend. // save the existing state in the new Backend.
err = sMgr.WriteState(stateFile.State) err = stateMgr.WriteState(stateFile.State)
if err != nil { if err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())
return 1 return 1
} }
err = sMgr.PersistState() err = stateMgr.PersistState()
if err != nil { if err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())
return 1 return 1
@ -178,7 +183,12 @@ Usage: terraform workspace new [OPTIONS] NAME [DIR]
Options: Options:
-lock=true Lock the state file when locking is supported.
-lock-timeout=0s Duration to retry a state lock.
-state=path Copy an existing state file into the new workspace. -state=path Copy an existing state file into the new workspace.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }

View File

@ -22,11 +22,12 @@ func (c *WorkspaceSelectCommand) Run(args []string) int {
envCommandShowWarning(c.Ui, c.LegacyName) envCommandShowWarning(c.Ui, c.LegacyName)
cmdFlags := c.Meta.flagSet("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 {
return 1 return 1
} }
args = cmdFlags.Args() args = cmdFlags.Args()
if len(args) == 0 { if len(args) == 0 {
c.Ui.Error("Expected a single argument: NAME.\n") c.Ui.Error("Expected a single argument: NAME.\n")
@ -131,6 +132,7 @@ func (c *WorkspaceSelectCommand) Help() string {
Usage: terraform workspace select NAME [DIR] Usage: terraform workspace select NAME [DIR]
Select a different Terraform workspace. Select a different Terraform workspace.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }

View File

@ -16,7 +16,7 @@ func (c *WorkspaceShowCommand) Run(args []string) int {
return 1 return 1
} }
cmdFlags := c.Meta.flagSet("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 {
return 1 return 1