Skip to content

Refactor cli package #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 22 additions & 17 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,29 @@ import (
"github.com/spf13/cobra"
)

var cliFlags struct {
type cliFlags struct {
verbose bool
outputFormat string
}

func Execute() {
flags := &cliFlags{}
cli := &cobra.Command{
Use: "arduino-cloud-cli",
Short: "Arduino Cloud CLI.",
Long: "Arduino Cloud Command Line Interface (arduino-cloud-cli).",
PersistentPreRun: preRun,
Use: "arduino-cloud-cli",
Short: "Arduino Cloud CLI.",
Long: "Arduino Cloud Command Line Interface (arduino-cloud-cli).",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if err := preRun(flags); err != nil {
feedback.Error(err)
os.Exit(errorcodes.ErrBadCall)
}
},
}
cli.PersistentFlags().BoolVarP(&flags.verbose, "verbose", "v", false, "Print the logs on the standard output.")
validOutputFormats := []string{"text", "json", "jsonmini", "yaml"}
cli.PersistentFlags().StringVar(&flags.outputFormat, "format", "text",
fmt.Sprintf("The output format, can be: %s", strings.Join(validOutputFormats, ", ")),
)

cli.AddCommand(version.NewCommand())
cli.AddCommand(credentials.NewCommand())
Expand All @@ -55,12 +66,6 @@ func Execute() {
cli.AddCommand(dashboard.NewCommand())
cli.AddCommand(ota.NewCommand())

cli.PersistentFlags().BoolVarP(&cliFlags.verbose, "verbose", "v", false, "Print the logs on the standard output.")
validOutputFormats := []string{"text", "json", "jsonmini", "yaml"}
cli.PersistentFlags().StringVar(&cliFlags.outputFormat, "format", "text",
fmt.Sprintf("The output format, can be: %s", strings.Join(validOutputFormats, ", ")),
)

if err := cli.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
Expand All @@ -77,22 +82,22 @@ func parseFormatString(arg string) (feedback.OutputFormat, bool) {
return f, found
}

func preRun(cmd *cobra.Command, args []string) {
func preRun(flags *cliFlags) error {
logrus.SetOutput(ioutil.Discard)
// enable log only if verbose flag is passed
if cliFlags.verbose {
if flags.verbose {
logrus.SetLevel(logrus.InfoLevel)
logrus.SetOutput(os.Stdout)
}

// normalize the format strings
cliFlags.outputFormat = strings.ToLower(cliFlags.outputFormat)
flags.outputFormat = strings.ToLower(flags.outputFormat)
// check the right output format was passed
format, found := parseFormatString(cliFlags.outputFormat)
format, found := parseFormatString(flags.outputFormat)
if !found {
feedback.Error("Invalid output format: " + cliFlags.outputFormat)
os.Exit(errorcodes.ErrBadCall)
return fmt.Errorf("invalid output format: %s", flags.outputFormat)
}
// use the output format to configure the Feedback
feedback.SetFormat(format)
return nil
}
13 changes: 9 additions & 4 deletions cli/credentials/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,25 @@ func initFindCommand() *cobra.Command {
Use: "find",
Short: "Find the credentials that would be used in your current directory",
Long: "Find the credentials to access Arduino IoT Cloud that would be used in your current directory",
Run: runFindCommand,
Run: func(cmd *cobra.Command, args []string) {
if err := runFindCommand(); err != nil {
feedback.Errorf("Error during credentials find: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
},
}

return findCommand
}

func runFindCommand(cmd *cobra.Command, args []string) {
func runFindCommand() error {
logrus.Info("Looking for credentials")

src, err := config.FindCredentials()
if err != nil {
feedback.Errorf("Error during credentials find: %v", err)
os.Exit(errorcodes.ErrGeneric)
return err
}

feedback.Printf("Using credentials in: %s", src)
return nil
}
58 changes: 28 additions & 30 deletions cli/credentials/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,77 +34,75 @@ import (
"github.com/spf13/viper"
)

var initFlags struct {
type initFlags struct {
destDir string
overwrite bool
format string
}

func initInitCommand() *cobra.Command {
flags := &initFlags{}
initCommand := &cobra.Command{
Use: "init",
Short: "Initialize a credentials file",
Long: "Initialize an Arduino IoT Cloud CLI credentials file",
Run: runInitCommand,
Run: func(cmd *cobra.Command, args []string) {
if err := runInitCommand(flags); err != nil {
feedback.Errorf("Error during credentials init: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
},
}

initCommand.Flags().StringVar(&initFlags.destDir, "dest-dir", "", "Sets where to save the credentials file")
initCommand.Flags().BoolVar(&initFlags.overwrite, "overwrite", false, "Overwrite existing credentials file")
initCommand.Flags().StringVar(&initFlags.format, "file-format", "yaml", "Format of the credentials file, can be {yaml|json}")
initCommand.Flags().StringVar(&flags.destDir, "dest-dir", "", "Sets where to save the credentials file")
initCommand.Flags().BoolVar(&flags.overwrite, "overwrite", false, "Overwrite existing credentials file")
initCommand.Flags().StringVar(&flags.format, "file-format", "yaml", "Format of the credentials file, can be {yaml|json}")

return initCommand
}

func runInitCommand(cmd *cobra.Command, args []string) {
func runInitCommand(flags *initFlags) error {
logrus.Info("Initializing credentials file")

// Get default destination directory if it's not passed
if initFlags.destDir == "" {
if flags.destDir == "" {
credPath, err := arduino.DataDir()
if err != nil {
feedback.Errorf("Error during credentials init: cannot retrieve arduino default directory: %v", err)
os.Exit(errorcodes.ErrGeneric)
return fmt.Errorf("cannot retrieve arduino default directory: %w", err)
}
// Create arduino default directory if it does not exist
if credPath.NotExist() {
if err = credPath.MkdirAll(); err != nil {
feedback.Errorf("Error during credentials init: cannot create arduino default directory %s: %v", credPath, err)
os.Exit(errorcodes.ErrGeneric)
return fmt.Errorf("cannot create arduino default directory %s: %w", credPath, err)
}
}
initFlags.destDir = credPath.String()
flags.destDir = credPath.String()
}

// Validate format flag
initFlags.format = strings.ToLower(initFlags.format)
if initFlags.format != "json" && initFlags.format != "yaml" {
feedback.Error("Error during credentials init: format is not valid, provide 'json' or 'yaml'")
os.Exit(errorcodes.ErrGeneric)
flags.format = strings.ToLower(flags.format)
if flags.format != "json" && flags.format != "yaml" {
return fmt.Errorf("format is not valid, provide 'json' or 'yaml'")
}

// Check that the destination directory is valid and build the credentials file path
credPath, err := paths.New(initFlags.destDir).Abs()
credPath, err := paths.New(flags.destDir).Abs()
if err != nil {
feedback.Errorf("Error during credentials init: cannot retrieve absolute path of %s: %v", initFlags.destDir, err)
os.Exit(errorcodes.ErrGeneric)
return fmt.Errorf("cannot retrieve absolute path of %s: %w", flags.destDir, err)
}
if !credPath.IsDir() {
feedback.Errorf("Error during credentials init: %s is not a valid directory", credPath)
os.Exit(errorcodes.ErrGeneric)
return fmt.Errorf("%s is not a valid directory", credPath)
}
credFile := credPath.Join(config.CredentialsFilename + "." + initFlags.format)
if !initFlags.overwrite && credFile.Exist() {
feedback.Errorf("Error during credentials init: %s already exists, use '--overwrite' to overwrite it",
credFile)
os.Exit(errorcodes.ErrGeneric)
credFile := credPath.Join(config.CredentialsFilename + "." + flags.format)
if !flags.overwrite && credFile.Exist() {
return fmt.Errorf("%s already exists, use '--overwrite' to overwrite it", credFile)
}

// Take needed credentials starting an interactive mode
feedback.Print("To obtain your API credentials visit https://create.arduino.cc/iot/integrations")
id, key, err := paramsPrompt()
if err != nil {
feedback.Errorf("Error during credentials init: cannot take credentials params: %v", err)
os.Exit(errorcodes.ErrGeneric)
return fmt.Errorf("cannot take credentials params: %w", err)
}

// Write the credentials file
Expand All @@ -113,11 +111,11 @@ func runInitCommand(cmd *cobra.Command, args []string) {
newSettings.Set("client", id)
newSettings.Set("secret", key)
if err := newSettings.WriteConfigAs(credFile.String()); err != nil {
feedback.Errorf("Error during credentials init: cannot write credentials file: %v", err)
os.Exit(errorcodes.ErrGeneric)
return fmt.Errorf("cannot write credentials file: %w", err)
}

feedback.Printf("Credentials file successfully initialized at: %s", credFile)
return nil
}

func paramsPrompt() (id, key string, err error) {
Expand Down
35 changes: 20 additions & 15 deletions cli/dashboard/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,54 +30,59 @@ import (
"github.com/spf13/cobra"
)

var createFlags struct {
type createFlags struct {
name string
template string
override map[string]string
}

func initCreateCommand() *cobra.Command {
flags := &createFlags{}
createCommand := &cobra.Command{
Use: "create",
Short: "Create a dashboard from a template",
Long: "Create a dashboard from a template for Arduino IoT Cloud",
Run: runCreateCommand,
Run: func(cmd *cobra.Command, args []string) {
if err := runCreateCommand(flags); err != nil {
feedback.Errorf("Error during dashboard create: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
},
}
createCommand.Flags().StringVarP(&createFlags.name, "name", "n", "", "Dashboard name")
createCommand.Flags().StringVarP(&createFlags.template, "template", "t", "",
createCommand.Flags().StringVarP(&flags.name, "name", "n", "", "Dashboard name")
createCommand.Flags().StringVarP(&flags.template, "template", "t", "",
"File containing a dashboard template, JSON and YAML format are supported",
)
createCommand.Flags().StringToStringVarP(&createFlags.override, "override", "o", nil,
createCommand.Flags().StringToStringVarP(&flags.override, "override", "o", nil,
"Map stating the items to be overridden. Ex: 'thing-0=xxxxxxxx,thing-1=yyyyyyyy'")

createCommand.MarkFlagRequired("template")
return createCommand
}

func runCreateCommand(cmd *cobra.Command, args []string) {
logrus.Infof("Creating dashboard from template %s", createFlags.template)
func runCreateCommand(flags *createFlags) error {
logrus.Infof("Creating dashboard from template %s", flags.template)

cred, err := config.RetrieveCredentials()
if err != nil {
feedback.Errorf("Error during dashboard create: retrieving credentials: %v", err)
os.Exit(errorcodes.ErrGeneric)
return fmt.Errorf("retrieving credentials: %w", err)
}

params := &dashboard.CreateParams{
Template: createFlags.template,
Override: createFlags.override,
Template: flags.template,
Override: flags.override,
}
if createFlags.name != "" {
params.Name = &createFlags.name
if flags.name != "" {
params.Name = &flags.name
}

dashboard, err := dashboard.Create(params, cred)
if err != nil {
feedback.Errorf("Error during dashboard create: %v", err)
os.Exit(errorcodes.ErrGeneric)
return err
}

feedback.PrintResult(createResult{dashboard})
return nil
}

type createResult struct {
Expand Down
26 changes: 16 additions & 10 deletions cli/dashboard/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package dashboard

import (
"fmt"
"os"

"github.com/arduino/arduino-cli/cli/errorcodes"
Expand All @@ -28,37 +29,42 @@ import (
"github.com/spf13/cobra"
)

var deleteFlags struct {
type deleteFlags struct {
id string
}

func initDeleteCommand() *cobra.Command {
flags := &deleteFlags{}
deleteCommand := &cobra.Command{
Use: "delete",
Short: "Delete a dashboard",
Long: "Delete a dashboard from Arduino IoT Cloud",
Run: runDeleteCommand,
Run: func(cmd *cobra.Command, args []string) {
if err := runDeleteCommand(flags); err != nil {
feedback.Errorf("Error during dashboard delete: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
},
}
deleteCommand.Flags().StringVarP(&deleteFlags.id, "id", "i", "", "Dashboard ID")
deleteCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Dashboard ID")
deleteCommand.MarkFlagRequired("id")
return deleteCommand
}

func runDeleteCommand(cmd *cobra.Command, args []string) {
logrus.Infof("Deleting dashboard %s", deleteFlags.id)
func runDeleteCommand(flags *deleteFlags) error {
logrus.Infof("Deleting dashboard %s", flags.id)

cred, err := config.RetrieveCredentials()
if err != nil {
feedback.Errorf("Error during dashboard delete: retrieving credentials: %v", err)
os.Exit(errorcodes.ErrGeneric)
return fmt.Errorf("retrieving credentials: %w", err)
}

params := &dashboard.DeleteParams{ID: deleteFlags.id}
params := &dashboard.DeleteParams{ID: flags.id}
err = dashboard.Delete(params, cred)
if err != nil {
feedback.Errorf("Error during dashboard delete: %v", err)
os.Exit(errorcodes.ErrGeneric)
return err
}

logrus.Info("Dashboard successfully deleted")
return nil
}
Loading