cli: Add global view arguments parser
Rather than modifying and relying on the existing Meta.process argument extractor, we can more clearly handle global CLI flags using a separate parser step. This allows us to explicitly configure the view in the command.
This commit is contained in:
parent
c5a6aa31d3
commit
57879bfb71
|
@ -0,0 +1,43 @@
|
||||||
|
package arguments
|
||||||
|
|
||||||
|
// View represents the global command-line arguments which configure the view.
|
||||||
|
type View struct {
|
||||||
|
// NoColor is used to disable the use of terminal color codes in all
|
||||||
|
// output.
|
||||||
|
NoColor bool
|
||||||
|
|
||||||
|
// CompactWarnings is used to coalesce duplicate warnings, to reduce the
|
||||||
|
// level of noise when multiple instances of the same warning are raised
|
||||||
|
// for a configuration.
|
||||||
|
CompactWarnings bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseView processes CLI arguments, returning a View value and a
|
||||||
|
// possibly-modified slice of arguments. If any of the supported flags are
|
||||||
|
// found, they will be removed from the slice.
|
||||||
|
func ParseView(args []string) (*View, []string) {
|
||||||
|
common := &View{}
|
||||||
|
|
||||||
|
// Keep track of the length of the returned slice. When we find an
|
||||||
|
// argument we support, i will not be incremented.
|
||||||
|
i := 0
|
||||||
|
for _, v := range args {
|
||||||
|
switch v {
|
||||||
|
case "-no-color":
|
||||||
|
common.NoColor = true
|
||||||
|
case "-compact-warnings":
|
||||||
|
common.CompactWarnings = true
|
||||||
|
default:
|
||||||
|
// Unsupported argument: move left to the current position, and
|
||||||
|
// increment the index.
|
||||||
|
args[i] = v
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce the slice to the number of unsupported arguments. Any remaining
|
||||||
|
// to the right of i have already been moved left.
|
||||||
|
args = args[:i]
|
||||||
|
|
||||||
|
return common, args
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package arguments
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseView(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
args []string
|
||||||
|
want *View
|
||||||
|
wantArgs []string
|
||||||
|
}{
|
||||||
|
"nil": {
|
||||||
|
nil,
|
||||||
|
&View{NoColor: false, CompactWarnings: false},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
[]string{},
|
||||||
|
&View{NoColor: false, CompactWarnings: false},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
"none matching": {
|
||||||
|
[]string{"-foo", "bar", "-baz"},
|
||||||
|
&View{NoColor: false, CompactWarnings: false},
|
||||||
|
[]string{"-foo", "bar", "-baz"},
|
||||||
|
},
|
||||||
|
"no-color": {
|
||||||
|
[]string{"-foo", "-no-color", "-baz"},
|
||||||
|
&View{NoColor: true, CompactWarnings: false},
|
||||||
|
[]string{"-foo", "-baz"},
|
||||||
|
},
|
||||||
|
"compact-warnings": {
|
||||||
|
[]string{"-foo", "-compact-warnings", "-baz"},
|
||||||
|
&View{NoColor: false, CompactWarnings: true},
|
||||||
|
[]string{"-foo", "-baz"},
|
||||||
|
},
|
||||||
|
"both": {
|
||||||
|
[]string{"-foo", "-no-color", "-compact-warnings", "-baz"},
|
||||||
|
&View{NoColor: true, CompactWarnings: true},
|
||||||
|
[]string{"-foo", "-baz"},
|
||||||
|
},
|
||||||
|
"both, resulting in empty args": {
|
||||||
|
[]string{"-no-color", "-compact-warnings"},
|
||||||
|
&View{NoColor: true, CompactWarnings: true},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
got, gotArgs := ParseView(tc.args)
|
||||||
|
if *got != *tc.want {
|
||||||
|
t.Errorf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||||
|
}
|
||||||
|
if !cmp.Equal(gotArgs, tc.wantArgs) {
|
||||||
|
t.Errorf("unexpected args\n got: %#v\nwant: %#v", gotArgs, tc.wantArgs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -621,10 +621,6 @@ func (m *Meta) process(args []string) []string {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.View != nil {
|
|
||||||
m.View.EnableColor(m.Color)
|
|
||||||
}
|
|
||||||
|
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ type OutputCommand struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OutputCommand) Run(rawArgs []string) int {
|
func (c *OutputCommand) Run(rawArgs []string) int {
|
||||||
rawArgs = c.Meta.process(rawArgs)
|
// Parse and apply global view arguments
|
||||||
|
common, rawArgs := arguments.ParseView(rawArgs)
|
||||||
|
c.View.Configure(common)
|
||||||
|
|
||||||
// Parse and validate flags
|
// Parse and validate flags
|
||||||
args, diags := arguments.ParseOutput(rawArgs)
|
args, diags := arguments.ParseOutput(rawArgs)
|
||||||
|
|
|
@ -149,6 +149,7 @@ func TestOutput_emptyOutputs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
|
"-no-color",
|
||||||
"-state", statePath,
|
"-state", statePath,
|
||||||
}
|
}
|
||||||
code := c.Run(args)
|
code := c.Run(args)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package views
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/command/arguments"
|
||||||
"github.com/hashicorp/terraform/command/format"
|
"github.com/hashicorp/terraform/command/format"
|
||||||
"github.com/hashicorp/terraform/internal/terminal"
|
"github.com/hashicorp/terraform/internal/terminal"
|
||||||
"github.com/hashicorp/terraform/tfdiags"
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
|
@ -41,11 +42,10 @@ func NewView(streams *terminal.Streams) *View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableColor controls the colorize implementation used by this view (and any
|
// Configure applies the global view configuration flags.
|
||||||
// other views which depend on it). This is called by the code which processes
|
func (v *View) Configure(view *arguments.View) {
|
||||||
// the global -no-color CLI flag, which happens after the view is initialized.
|
v.colorize.Disable = view.NoColor
|
||||||
func (v *View) EnableColor(color bool) {
|
v.compactWarnings = view.CompactWarnings
|
||||||
v.colorize.Disable = !color
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfigSources overrides the default no-op callback with a new function
|
// SetConfigSources overrides the default no-op callback with a new function
|
||||||
|
|
Loading…
Reference in New Issue