Skip to content

Commit

Permalink
move all command args from command/init to args/init
Browse files Browse the repository at this point in the history
  • Loading branch information
Uk1288 committed Apr 15, 2024
1 parent 25dd8b4 commit ffabb5e
Show file tree
Hide file tree
Showing 20 changed files with 223 additions and 285 deletions.
4 changes: 2 additions & 2 deletions internal/command/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,12 @@ func (c *ApplyCommand) GatherVariables(opReq *backendrun.Operation, args *argume
// package directly, removing this shim layer.

varArgs := args.All()
items := make([]rawFlag, len(varArgs))
items := make([]arguments.FlagNameValue, len(varArgs))
for i := range varArgs {
items[i].Name = varArgs[i].Name
items[i].Value = varArgs[i].Value
}
c.Meta.variableArgs = rawFlags{items: &items}
c.Meta.variableArgs = arguments.FlagNameValueSlice{Items: &items}
opReq.Variables, diags = c.collectVariableValues()

return diags
Expand Down
12 changes: 6 additions & 6 deletions internal/command/arguments/extended.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,13 @@ func (o *Operation) Parse() tfdiags.Diagnostics {
}

// Vars describes arguments which specify non-default variable values. This
// interfce is unfortunately obscure, because the order of the CLI arguments
// interface is unfortunately obscure, because the order of the CLI arguments
// determines the final value of the gathered variables. In future it might be
// desirable for the arguments package to handle the gathering of variables
// directly, returning a map of variable values.
type Vars struct {
vars *flagNameValueSlice
varFiles *flagNameValueSlice
vars *FlagNameValueSlice
varFiles *FlagNameValueSlice
}

func (v *Vars) All() []FlagNameValue {
Expand Down Expand Up @@ -226,14 +226,14 @@ func extendedFlagSet(name string, state *State, operation *Operation, vars *Vars
f.BoolVar(&operation.Refresh, "refresh", true, "refresh")
f.BoolVar(&operation.destroyRaw, "destroy", false, "destroy")
f.BoolVar(&operation.refreshOnlyRaw, "refresh-only", false, "refresh-only")
f.Var((*flagStringSlice)(&operation.targetsRaw), "target", "target")
f.Var((*flagStringSlice)(&operation.forceReplaceRaw), "replace", "replace")
f.Var((*FlagStringSlice)(&operation.targetsRaw), "target", "target")
f.Var((*FlagStringSlice)(&operation.forceReplaceRaw), "replace", "replace")
}

// Gather all -var and -var-file arguments into one heterogenous structure
// to preserve the overall order.
if vars != nil {
varsFlags := newFlagNameValueSlice("-var")
varsFlags := NewFlagNameValueSlice("-var")
varFilesFlags := varsFlags.Alias("-var-file")
vars.vars = &varsFlags
vars.varFiles = &varFilesFlags
Expand Down
60 changes: 28 additions & 32 deletions internal/command/arguments/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,72 +8,68 @@ import (
"fmt"
)

// flagStringSlice is a flag.Value implementation which allows collecting
// FlagStringSlice is a flag.Value implementation which allows collecting
// multiple instances of a single flag into a slice. This is used for flags
// such as -target=aws_instance.foo and -var x=y.
type flagStringSlice []string
type FlagStringSlice []string

var _ flag.Value = (*flagStringSlice)(nil)
var _ flag.Value = (*FlagStringSlice)(nil)

func (v *flagStringSlice) String() string {
func (v *FlagStringSlice) String() string {
return ""
}
func (v *flagStringSlice) Set(raw string) error {
func (v *FlagStringSlice) Set(raw string) error {
*v = append(*v, raw)

return nil
}

// flagNameValueSlice is a flag.Value implementation that appends raw flag
// FlagNameValueSlice is a flag.Value implementation that appends raw flag
// names and values to a slice. This is used to collect a sequence of flags
// with possibly different names, preserving the overall order.
//
// FIXME: this is a copy of rawFlags from command/meta_config.go, with the
// eventual aim of replacing it altogether by gathering variables in the
// arguments package.
type flagNameValueSlice struct {
flagName string
items *[]FlagNameValue
type FlagNameValueSlice struct {
FlagName string
Items *[]FlagNameValue
}

var _ flag.Value = flagNameValueSlice{}
var _ flag.Value = FlagNameValueSlice{}

func newFlagNameValueSlice(flagName string) flagNameValueSlice {
func NewFlagNameValueSlice(flagName string) FlagNameValueSlice {
var items []FlagNameValue
return flagNameValueSlice{
flagName: flagName,
items: &items,
return FlagNameValueSlice{
FlagName: flagName,
Items: &items,
}
}

func (f flagNameValueSlice) Empty() bool {
if f.items == nil {
func (f FlagNameValueSlice) Empty() bool {
if f.Items == nil {
return true
}
return len(*f.items) == 0
return len(*f.Items) == 0
}

func (f flagNameValueSlice) AllItems() []FlagNameValue {
if f.items == nil {
func (f FlagNameValueSlice) AllItems() []FlagNameValue {
if f.Items == nil {
return nil
}
return *f.items
return *f.Items
}

func (f flagNameValueSlice) Alias(flagName string) flagNameValueSlice {
return flagNameValueSlice{
flagName: flagName,
items: f.items,
func (f FlagNameValueSlice) Alias(flagName string) FlagNameValueSlice {
return FlagNameValueSlice{
FlagName: flagName,
Items: f.Items,
}
}

func (f flagNameValueSlice) String() string {
func (f FlagNameValueSlice) String() string {
return ""
}

func (f flagNameValueSlice) Set(str string) error {
*f.items = append(*f.items, FlagNameValue{
Name: f.flagName,
func (f FlagNameValueSlice) Set(str string) error {
*f.Items = append(*f.Items, FlagNameValue{
Name: f.FlagName,
Value: str,
})
return nil
Expand Down
49 changes: 46 additions & 3 deletions internal/command/arguments/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package arguments

import (
"flag"
"time"

"github.com/hashicorp/terraform/internal/tfdiags"
Expand Down Expand Up @@ -58,15 +57,39 @@ type Init struct {

// IgnoreRemoteVersion specifies whether to ignore remote and local Terraform versions compatibility
IgnoreRemoteVersion bool

BackendConfig FlagNameValueSlice

Vars *Vars

// InputEnabled is used to disable interactive input for unspecified
// variable and backend config values. Default is true.
InputEnabled bool

TargetFlags []string

CompactWarnings bool

PluginPath FlagStringSlice

Args []string
}

// ParseInit processes CLI arguments, returning an Init value and errors.
// If errors are encountered, an Init value is still returned representing
// the best effort interpretation of the arguments.
func ParseInit(args []string, cmdFlags *flag.FlagSet) (*Init, tfdiags.Diagnostics) {
func ParseInit(args []string) (*Init, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
init := &Init{}
init := &Init{
Vars: &Vars{},
}
init.BackendConfig = NewFlagNameValueSlice("-backend-config")

cmdFlags := extendedFlagSet("init", nil, nil, init.Vars)

cmdFlags.Var((*FlagStringSlice)(&init.TargetFlags), "target", "resource to target")
cmdFlags.BoolVar(&init.InputEnabled, "input", true, "input")
cmdFlags.BoolVar(&init.CompactWarnings, "compact-warnings", false, "use compact warnings")
cmdFlags.BoolVar(&init.Backend, "backend", true, "")
cmdFlags.BoolVar(&init.Cloud, "cloud", true, "")
cmdFlags.StringVar(&init.FromModule, "from-module", "", "copy the source of the given module into the directory before init")
Expand All @@ -81,6 +104,8 @@ func ParseInit(args []string, cmdFlags *flag.FlagSet) (*Init, tfdiags.Diagnostic
cmdFlags.BoolVar(&init.IgnoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
cmdFlags.StringVar(&init.TestsDirectory, "test-directory", "tests", "test-directory")
cmdFlags.BoolVar(&init.Json, "json", false, "json")
cmdFlags.Var(&init.BackendConfig, "backend-config", "")
cmdFlags.Var(&init.PluginPath, "plugin-dir", "plugin directory")

if err := cmdFlags.Parse(args); err != nil {
diags = diags.Append(tfdiags.Sourceless(
Expand All @@ -90,6 +115,24 @@ func ParseInit(args []string, cmdFlags *flag.FlagSet) (*Init, tfdiags.Diagnostic
))
}

if init.MigrateState && init.Json {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"The -migrate-state and -json options are mutually-exclusive",
"Terraform cannot ask for interactive approval when -json is set. To use the -migrate-state option, disable the -json option.",
))
}

if init.MigrateState && init.Reconfigure {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid init options",
"The -migrate-state and -reconfigure options are mutually-exclusive.",
))
}

init.Args = cmdFlags.Args()

backendFlagSet := FlagIsSet(cmdFlags, "backend")
cloudFlagSet := FlagIsSet(cmdFlags, "cloud")

Expand Down
12 changes: 2 additions & 10 deletions internal/command/arguments/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
package arguments

import (
"flag"
"io"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -86,10 +84,7 @@ func TestParseInit_basicValid(t *testing.T) {

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
cmdFlags := flag.NewFlagSet("init", flag.ContinueOnError)
cmdFlags.SetOutput(io.Discard)

got, diags := ParseInit(tc.args, cmdFlags)
got, diags := ParseInit(tc.args)
if len(diags) > 0 {
t.Fatalf("unexpected diags: %v", diags)
}
Expand Down Expand Up @@ -118,10 +113,7 @@ func TestParseInit_invalid(t *testing.T) {

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
cmdFlags := flag.NewFlagSet("init", flag.ContinueOnError)
cmdFlags.SetOutput(io.Discard)

got, diags := ParseInit(tc.args, cmdFlags)
got, diags := ParseInit(tc.args)
if len(diags) == 0 {
t.Fatal("expected diags but got none")
}
Expand Down
2 changes: 1 addition & 1 deletion internal/command/arguments/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func ParseTest(args []string) (*Test, tfdiags.Diagnostics) {

var jsonOutput bool
cmdFlags := extendedFlagSet("test", nil, nil, test.Vars)
cmdFlags.Var((*flagStringSlice)(&test.Filter), "filter", "filter")
cmdFlags.Var((*FlagStringSlice)(&test.Filter), "filter", "filter")
cmdFlags.StringVar(&test.TestDirectory, "test-directory", configs.DefaultTestDirectory, "test-directory")
cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
cmdFlags.StringVar(&test.JUnitXMLFile, "junit-xml", "", "junit-xml")
Expand Down
13 changes: 0 additions & 13 deletions internal/command/flag_kv.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,3 @@ func (v *FlagStringKV) Set(raw string) error {
(*v)[key] = value
return nil
}

// FlagStringSlice is a flag.Value implementation for parsing targets from the
// command line, e.g. -target=aws_instance.foo -target=aws_vpc.bar
type FlagStringSlice []string

func (v *FlagStringSlice) String() string {
return ""
}
func (v *FlagStringSlice) Set(raw string) error {
*v = append(*v, raw)

return nil
}
Loading

0 comments on commit ffabb5e

Please sign in to comment.