From c772bf0182532c9bfd2960ed8f02d313a08b988f Mon Sep 17 00:00:00 2001 From: Sander Blue Date: Tue, 27 Jun 2023 15:27:32 -0500 Subject: [PATCH] feat: [wip] prototype to support yaml file as input for command flags --- internal/utils/command_do.go | 90 ++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/internal/utils/command_do.go b/internal/utils/command_do.go index 99240385d..7210e098e 100644 --- a/internal/utils/command_do.go +++ b/internal/utils/command_do.go @@ -1,45 +1,99 @@ package utils import ( + "encoding/json" "fmt" - "path/filepath" + "io/ioutil" + "reflect" + "strconv" "github.com/spf13/cobra" + "gopkg.in/yaml.v3" ) var ( - stringFlag string - intFlag int - flags string // the json file path + inputFile string // yaml/json file path + guid string + otherFlag int ) +type commandInputs struct { + Flags map[string]interface{} `yaml:"flags"` +} + var cmdDo = &cobra.Command{ Use: "do", Short: "Provide json file as cmd args", Long: `Testing json file as arguments to a command`, Example: `newrelic do --file=./path/to/file`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("testing") + PreRunE: func(cmd *cobra.Command, args []string) error { - fileType := filepath.Ext(flags) + // TODO + // If command flags are provided inline as well as an input file for flags, + // the inline flags will take precendence and the input file flags will be ignored. + // Provide a warning message, but return nil and continue command execution in Run(). - // if jsonFile { - // handle json - // } + inputFile, err := ioutil.ReadFile(inputFile) + if err != nil { + return fmt.Errorf("YAML err %+v ", err) + } - // if yamlFile { - // handle yaml - // } + cmdInputs := commandInputs{} + err = yaml.Unmarshal(inputFile, &cmdInputs) + if err != nil { + err = json.Unmarshal(inputFile, &cmdInputs) + if err != nil { + return fmt.Errorf("error parsing input file %+v ", err) + } + } - fmt.Println("Content Type of file is: " + fileType) + // Validate flags + err = setFlagsFromFile(cmd, cmdInputs.Flags) + if err != nil { + return err + } + + return nil + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("\n Command - flag from file (guid): %+v", guid) + fmt.Printf("\n Command - flag from file (other): %+v \n\n", otherFlag) }, } +// setFlagsFromFile sets the command flag values based on the provided input file contents. +// If also ensures the provided flags from an input file match the expected flags and their respective types. +// Nonexistent flags will result in an error. Incorrect types will result in an error. +func setFlagsFromFile(cmd *cobra.Command, flagsFromFile map[string]interface{}) error { + flagSet := cmd.Flags() + for k, v := range flagsFromFile { + // Ensure flag exists for the command + flag := flagSet.Lookup(k) + if flag == nil { + return fmt.Errorf("error: Invalid flag `%s` provided for command `%s` ", k, cmd.Name()) + } + + // Ensure correct type + flagType := flag.Value.Type() + if reflect.TypeOf(v).String() != flag.Value.Type() { + return fmt.Errorf("error: Invalid value `%v` for flag `%s` provided for command `%s`. Must be of type %s", v, k, cmd.Name(), flagType) + } + + switch t := flag.Value.Type(); t { + case "string": + flagSet.Set(k, v.(string)) + case "int": + flagSet.Set(k, strconv.Itoa(v.(int))) + } + } + + return nil +} + func init() { Command.AddCommand(cmdDo) - cmdDo.Flags().StringVarP(&flags, "flags", "f", "", "a file that contains the flags for the command") - - cmdDo.Flags().StringVar(&stringFlag, "stringFlag", "", "A flag with a string value") - cmdDo.Flags().IntVar(&intFlag, "intFlag", 0, "A flag with an integer value") + cmdDo.Flags().StringVarP(&inputFile, "inputFile", "f", "", "a file that contains the flags for the command") + cmdDo.Flags().StringVar(&guid, "guid", "", "A flag with a string value") + cmdDo.Flags().IntVar(&otherFlag, "otherFlag", 0, "A flag with an integer value") }