148 lines
3.6 KiB
Go
148 lines
3.6 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
|
|
"github.com/DavidGamba/go-getoptions"
|
|
"github.com/DavidGamba/go-getoptions/option"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"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
|
|
flags []*option.Option
|
|
flagData map[string]interface{}
|
|
}
|
|
|
|
func (c *DynamicCommand) Run(args []string) int {
|
|
if err := c.Init(
|
|
WithArgs(args),
|
|
WithFlags(c.Flags()),
|
|
); err != nil {
|
|
return 1
|
|
}
|
|
|
|
var r *vagrant_server.Job_RunResult
|
|
err := c.Do(c.Ctx, func(ctx context.Context, cl *client.Client, modifier client.JobModifier) (err error) {
|
|
cl.UI().Output("Running "+c.name+"... ", terminal.WithHeaderStyle())
|
|
taskArgs := &vagrant_plugin_sdk.Command_Arguments{
|
|
Args: args,
|
|
Flags: []*vagrant_plugin_sdk.Command_Arguments_Flag{},
|
|
}
|
|
for k, v := range c.flagData {
|
|
f := &vagrant_plugin_sdk.Command_Arguments_Flag{Name: k}
|
|
switch reflect.Indirect(reflect.ValueOf(v)).Kind() {
|
|
case reflect.String:
|
|
f.Value = &vagrant_plugin_sdk.Command_Arguments_Flag_String_{
|
|
String_: *v.(*string),
|
|
}
|
|
f.Type = vagrant_plugin_sdk.Command_Arguments_Flag_STRING
|
|
case reflect.Bool:
|
|
f.Value = &vagrant_plugin_sdk.Command_Arguments_Flag_Bool{
|
|
Bool: *v.(*bool),
|
|
}
|
|
f.Type = vagrant_plugin_sdk.Command_Arguments_Flag_BOOL
|
|
}
|
|
taskArgs.Flags = append(taskArgs.Flags, f)
|
|
}
|
|
|
|
t := &vagrant_server.Task{
|
|
Task: c.name,
|
|
Component: &vagrant_server.Component{
|
|
Type: vagrant_server.Component_COMMAND,
|
|
Name: c.name,
|
|
},
|
|
CliArgs: taskArgs,
|
|
CommandName: c.name,
|
|
}
|
|
|
|
if c.basis != nil {
|
|
t.Scope = &vagrant_server.Task_Basis{
|
|
Basis: c.basis.Ref(),
|
|
}
|
|
}
|
|
|
|
if c.project != nil {
|
|
t.Scope = &vagrant_server.Task_Project{
|
|
Project: c.project.Ref(),
|
|
}
|
|
}
|
|
|
|
if c.target != nil {
|
|
t.Scope = &vagrant_server.Task_Target{
|
|
Target: c.target.Ref(),
|
|
}
|
|
}
|
|
|
|
r, err = cl.Task(ctx,
|
|
&vagrant_server.Job_RunOp{Task: t},
|
|
modifier,
|
|
)
|
|
|
|
if err != nil {
|
|
cl.UI().Output("Running of task "+c.name+" failed unexpectedly\n", terminal.WithErrorStyle())
|
|
cl.UI().Output("Error: "+err.Error(), terminal.WithErrorStyle())
|
|
} else if !r.RunResult {
|
|
runErrorStatus := status.FromProto(r.RunError)
|
|
details := runErrorStatus.Details()
|
|
// TODO: seach through the details for a localized message if exists
|
|
userMessage := details[0].(*vagrant_plugin_sdk.Errors_LocalizedErrorMessage).Message
|
|
cl.UI().Output("Error: "+userMessage+"\n", terminal.WithErrorStyle())
|
|
runErr := status.FromProto(r.RunError)
|
|
err = fmt.Errorf("execution failed, %w", runErr.Err())
|
|
}
|
|
|
|
c.Log.Debug("result from operation", "task", c.name, "result", r)
|
|
|
|
return err
|
|
})
|
|
|
|
if err != nil {
|
|
return int(-1)
|
|
}
|
|
|
|
return int(r.ExitCode)
|
|
}
|
|
|
|
func (c *DynamicCommand) Synopsis() string {
|
|
return c.synopsis
|
|
}
|
|
|
|
func (c *DynamicCommand) Help() string {
|
|
return c.help
|
|
}
|
|
|
|
func (c *DynamicCommand) Flags() *getoptions.GetOpt {
|
|
return c.flagSet(flagSetOperation, func(opts *getoptions.GetOpt) {
|
|
for _, f := range c.flags {
|
|
switch f.OptType {
|
|
case option.BoolType:
|
|
b, _ := strconv.ParseBool(f.DefaultStr)
|
|
c.flagData[f.Name] = opts.Bool(
|
|
f.Name,
|
|
b,
|
|
opts.Description(f.Description),
|
|
)
|
|
case option.StringType:
|
|
c.flagData[f.Name] = opts.String(
|
|
f.Name,
|
|
f.DefaultStr,
|
|
opts.Description(f.Description),
|
|
)
|
|
}
|
|
}
|
|
})
|
|
}
|