vagrant/internal/cli/dynamic.go

150 lines
4 KiB
Go
Raw Normal View History

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
2021-04-06 18:03:30 -04:00
package cli
import (
"context"
"fmt"
2021-04-06 18:03:30 -04:00
2022-01-11 12:44:35 -05:00
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/status"
2021-04-06 18:03:30 -04:00
"github.com/hashicorp/vagrant-plugin-sdk/component"
2021-04-06 18:03:30 -04:00
"github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk"
"github.com/hashicorp/vagrant-plugin-sdk/terminal"
"github.com/hashicorp/vagrant/internal/client"
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
)
type DynamicCommand struct {
*baseCommand
name string
synopsis string
help string
parent *DynamicCommand
flags []*component.CommandFlag
primary bool
2021-04-06 18:03:30 -04:00
}
func (c *DynamicCommand) Run(args []string) int {
if err := c.Init(
WithArgs(args),
WithFlags(c.Flags()),
); err != nil {
return 1
}
2022-09-19 11:43:35 -04:00
var r *vagrant_server.Job_CommandResult
err := c.Do(c.Ctx, func(ctx context.Context, cl *client.Client, modifier client.JobModifier) (err error) {
2022-09-19 11:43:35 -04:00
cmdArgs := &vagrant_plugin_sdk.Command_Arguments{
2022-01-31 18:14:45 -05:00
Args: c.args,
2021-04-06 18:03:30 -04:00
Flags: []*vagrant_plugin_sdk.Command_Arguments_Flag{},
}
for f, v := range c.flagData {
cmdFlag := &vagrant_plugin_sdk.Command_Arguments_Flag{Name: f.LongName}
switch f.Type {
case component.FlagBool:
cmdFlag.Type = vagrant_plugin_sdk.Command_Arguments_Flag_BOOL
cmdFlag.Value = &vagrant_plugin_sdk.Command_Arguments_Flag_Bool{
Bool: v.(bool),
2021-04-06 18:03:30 -04:00
}
case component.FlagString:
cmdFlag.Type = vagrant_plugin_sdk.Command_Arguments_Flag_STRING
cmdFlag.Value = &vagrant_plugin_sdk.Command_Arguments_Flag_String_{
String_: v.(string),
2021-04-06 18:03:30 -04:00
}
}
2022-09-19 11:43:35 -04:00
cmdArgs.Flags = append(cmdArgs.Flags, cmdFlag)
2021-04-06 18:03:30 -04:00
}
2022-01-31 18:14:45 -05:00
c.Log.Debug("collected argument flags",
2022-09-19 11:43:35 -04:00
"flags", cmdArgs.Flags,
2022-01-31 18:14:45 -05:00
"args", args,
"remaining", c.args,
)
2022-09-19 11:43:35 -04:00
cOp := &vagrant_server.Job_CommandOp{
Command: c.name,
Component: &vagrant_server.Component{
Type: vagrant_server.Component_COMMAND,
Name: c.name,
2021-04-06 18:03:30 -04:00
},
2022-09-19 11:43:35 -04:00
CliArgs: cmdArgs,
}
2022-09-19 11:43:35 -04:00
r, err = cl.Command(ctx, cOp, modifier)
2021-04-06 18:03:30 -04:00
// If nothing failed but we didn't get a Result back, something may
// have gone wrong on the far side so we need to interpret the error.
if err == nil && !r.RunResult {
runErrorStatus := status.FromProto(r.RunError)
details := runErrorStatus.Details()
userError := false
for _, msg := range details {
switch m := msg.(type) {
2022-01-11 12:44:35 -05:00
case *errdetails.LocalizedMessage:
// Errors from Ruby with LocalizedMessages are user-facing,
// so can be output directly.
userError = true
cl.UI().Output(m.Message, terminal.WithErrorStyle())
// All user-facing errors from Ruby use a 1 exit code. See
// Vagrant::Errors::VagrantError.
r.ExitCode = 1
}
}
// If there wasn't a user-facing error, just assign the returned
// error (if any) from the response and assign that back out so it
// can be displayed as an unexpected error.
if !userError {
err = runErrorStatus.Err()
}
2021-04-06 18:03:30 -04:00
}
if err != nil {
cl.UI().Output("Running of task "+c.name+" failed unexpectedly\n", terminal.WithErrorStyle())
cl.UI().Output("Error: "+err.Error(), terminal.WithErrorStyle())
}
c.Log.Debug("result from operation", "task", c.name, "result", r)
2021-04-06 18:03:30 -04:00
return err
})
if err != nil {
c.Log.Error("Got error from task, so exiting 255", "error", err)
2021-08-13 16:48:36 -04:00
return int(-1)
2021-04-06 18:03:30 -04:00
}
c.Log.Info("Task did not error, so exiting with provided code", "code", r.ExitCode)
return int(r.ExitCode)
2021-04-06 18:03:30 -04:00
}
func (c *DynamicCommand) Synopsis() string {
return c.synopsis
}
func (c *DynamicCommand) Help() string {
fset := c.generateCliFlags(c.Flags())
return formatHelp(fmt.Sprintf("%s\n%s\n", c.help, fset.Display()))
2021-04-06 18:03:30 -04:00
}
func (c *DynamicCommand) Flags() component.CommandFlags {
return c.flagSet(flagSetOperation, func(opts []*component.CommandFlag) []*component.CommandFlag {
return append(c.flags, opts...)
2021-04-06 18:03:30 -04:00
})
}
func (c *DynamicCommand) Primary() bool {
return c.primary
}
func (c *DynamicCommand) fullName() string {
var v string
if c.parent != nil {
v = c.parent.fullName() + " "
}
return v + c.name
}