Update to use component flags and update parsing

This commit is contained in:
Chris Roberts 2022-01-19 10:23:21 -08:00 committed by Paul Hinze
parent 39439cf9fb
commit e00f82fdee
No known key found for this signature in database
GPG Key ID: B69DEDF2D55501C0

View File

@ -6,12 +6,14 @@ import (
"fmt"
"io"
"regexp"
"strconv"
"strings"
"github.com/DavidGamba/go-getoptions"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/vagrant-plugin-sdk/component"
"github.com/hashicorp/vagrant-plugin-sdk/helper/paths"
"github.com/hashicorp/vagrant-plugin-sdk/terminal"
"github.com/hashicorp/vagrant/internal/clicontext"
@ -89,6 +91,9 @@ type baseCommand struct {
// flagConnection contains manual flag-based connection info.
flagConnection clicontext.Config
// flagData contains flag info for command
flagData map[*component.CommandFlag]interface{}
// args that were present after parsing flags
args []string
@ -117,11 +122,12 @@ func (c *baseCommand) Close() (err error) {
return
}
func BaseCommand(ctx context.Context, log hclog.Logger, logOutput io.Writer, opts ...Option) (*baseCommand, error) {
bc := &baseCommand{
func BaseCommand(ctx context.Context, log hclog.Logger, logOutput io.Writer, opts ...Option) (bc *baseCommand, err error) {
bc = &baseCommand{
Ctx: ctx,
Log: log,
LogOutput: logOutput,
flagData: map[*component.CommandFlag]interface{}{},
}
// Get just enough base configuration to
@ -142,9 +148,7 @@ func BaseCommand(ctx context.Context, log hclog.Logger, logOutput io.Writer, opt
c.UI = terminal.ConsoleUI(context.Background())
}
// Allow parser to not fail on unknown arguments
c.Flags.SetUnknownMode(getoptions.Pass)
if _, err := c.Flags.Parse(c.Args); err != nil {
if c.Args, err = bc.Parse(c.Flags, c.Args, true); err != nil {
c.UI.Output(clierrors.Humanize(err), terminal.WithErrorStyle())
return nil, err
}
@ -261,7 +265,7 @@ func BaseCommand(ctx context.Context, log hclog.Logger, logOutput io.Writer, opt
//
// Init should be called FIRST within the Run function implementation. Many
// options will affect behavior of other functions that can be called later.
func (c *baseCommand) Init(opts ...Option) error {
func (c *baseCommand) Init(opts ...Option) (err error) {
baseCfg := baseConfig{
Config: true,
Client: true,
@ -284,12 +288,11 @@ func (c *baseCommand) Init(opts ...Option) error {
c.ui = ui
// Parse flags
remainingArgs, err := baseCfg.Flags.Parse(baseCfg.Args)
if err != nil {
c.Log.Warn("generating flags", "flags", baseCfg.Flags)
if c.args, err = c.Parse(baseCfg.Flags, baseCfg.Args, false); err != nil {
c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle())
return err
}
c.args = remainingArgs
// Reset the UI to plain if that was set
if c.flagPlain {
@ -372,82 +375,137 @@ func (c *baseCommand) logError(log hclog.Logger, prefix string, err error) {
// flagSet creates the flags for this command. The callback should be used
// to configure the set with your own custom options.
func (c *baseCommand) flagSet(bit flagSetBit, f func(*getoptions.GetOpt)) *getoptions.GetOpt {
set := getoptions.New()
set.BoolVar(
&c.flagPlain,
"plain",
false,
set.Description("Plain output: no colors, no animation."),
)
set.StringVar(
&c.flagTarget,
"target",
"",
set.Description("Target to apply. Certain commands require a single target for "+
"Vagrant configurations with multiple apps. If you have a single target, "+
"then this can be ignored."),
)
set.StringVar(
&c.flagBasis,
"basis",
"default",
set.Description("Basis to operate within."),
)
func (c *baseCommand) flagSet(bit flagSetBit, f func([]*component.CommandFlag) []*component.CommandFlag) component.CommandFlags {
set := []*component.CommandFlag{
{
LongName: "plain",
Description: "Plain output: no colors, no animation",
DefaultValue: "false",
Type: component.FlagBool,
},
{
LongName: "basis",
Description: "Basis to operate within",
DefaultValue: "default",
Type: component.FlagString,
},
{
LongName: "target",
Description: "Target to apply command",
Type: component.FlagString,
},
}
if bit&flagSetOperation != 0 {
set.BoolVar(
&c.flagRemote,
"remote",
false,
set.Description("True to use a remote runner to execute. This defaults to false \n"+
"unless 'runner.default' is set in your configuration."),
set = append(set,
&component.CommandFlag{
LongName: "remote",
Description: "Use remote runner to execute",
DefaultValue: "false",
Type: component.FlagBool,
},
&component.CommandFlag{
LongName: "remote-source",
Description: "Override how remote runners source data",
Type: component.FlagString,
},
)
// set.StringMapVar(
// &c.flagRemoteSource,
// "remote-source",
// 1,
// MaxStringMapArgs,
// set.Description("Override configurations for how remote runners source data. "+
// "This is specified to the data source type being used in your configuration. "+
// "This is used for example to set a specific Git ref to run against."),
// )
}
if bit&flagSetConnection != 0 {
set.StringVar(
&c.flagConnection.Server.Address,
"server-addr",
"",
set.Description("Address for the server."),
)
set.BoolVar(
&c.flagConnection.Server.Tls,
"server-tls",
true,
set.Description("True if the server should be connected to via TLS."),
)
set.BoolVar(
&c.flagConnection.Server.TlsSkipVerify,
"server-tls-skip-verify",
false,
set.Description("True to skip verification of the TLS certificate advertised by the server."),
set = append(set,
&component.CommandFlag{
LongName: "server-addr",
Description: "Address for the server",
Type: component.FlagString,
},
&component.CommandFlag{
LongName: "server-tls",
Description: "Connect to server via TLS",
DefaultValue: "true",
Type: component.FlagBool,
},
&component.CommandFlag{
LongName: "server-tls-skip-verify",
Description: "Skip verification of the TLS certificate advertised by the server",
DefaultValue: "false",
Type: component.FlagBool,
},
)
}
if f != nil {
// Configure our values
f(set)
set = f(set)
}
return set
}
func (c *baseCommand) Parse(
flags []*component.CommandFlag,
args []string,
passThrough bool,
) ([]string, error) {
opt := c.generateCliFlags(flags)
if passThrough {
opt.SetUnknownMode(getoptions.Pass)
} else {
opt.SetUnknownMode(getoptions.Fail)
}
c.Log.Warn("parsing arguments with flags", "args", args, "flags", flags)
remainArgs, err := opt.Parse(args)
if err != nil {
return nil, err
}
for _, f := range flags {
if called := opt.Called(f.LongName); !called {
c.Log.Error("flag was not called", "name", f.LongName)
continue
}
c.Log.Warn("flag was called", "name", f.LongName)
if f.Type == component.FlagString {
c.flagData[f] = opt.Value(f.LongName)
continue
}
val := true
if strings.HasPrefix(opt.CalledAs(f.LongName), "no-") {
val = false
}
c.flagData[f] = val
}
return remainArgs, nil
}
func (c *baseCommand) generateCliFlags(set []*component.CommandFlag) *getoptions.GetOpt {
opt := getoptions.New()
opt.SetUnknownMode(getoptions.Pass) // TODO: make this configurable
for _, f := range set {
opts := []getoptions.ModifyFn{}
if f.Description != "" {
opts = append(opts, opt.Description(f.Description))
}
if f.ShortName != "" {
opts = append(opts, opt.Alias(f.ShortName))
}
switch f.Type {
case component.FlagBool:
opts = append(opts, opt.Alias("no-"+f.LongName))
b, _ := strconv.ParseBool(f.DefaultValue)
opt.Bool(f.LongName, b, opts...)
case component.FlagString:
opt.String(f.LongName, f.DefaultValue, opts...)
}
}
return opt
}
// flagSetBit is used with baseCommand.flagSet
type flagSetBit uint