Skip to content

Commit

Permalink
Added upload --upload-field key=value flag to set upload fields val…
Browse files Browse the repository at this point in the history
…ue (#2348)

* Added 'upload' flags to set upload fields value

* Introducing key/value flag type
  • Loading branch information
cmaglie authored Oct 16, 2023
1 parent 331541a commit 98c0480
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 12 deletions.
81 changes: 81 additions & 0 deletions internal/cli/arguments/key_value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// This file is part of arduino-cli.
//
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to
// modify or otherwise use the software for commercial activities involving the
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to license@arduino.cc.

package arguments

import (
"errors"
"fmt"
"strings"

"github.com/spf13/cobra"
)

// AddKeyValuePFlag adds a flag to the command that accepts a (possibly repeated) key=value pair.
func AddKeyValuePFlag(cmd *cobra.Command, field *map[string]string, name, shorthand string, value []string, usage string) {
cmd.Flags().VarP(newKVArrayValue(value, field), name, shorthand, usage)
}

type kvArrayValue struct {
value *map[string]string
changed bool
}

func newKVArrayValue(val []string, p *map[string]string) *kvArrayValue {
ssv := &kvArrayValue{
value: p,
}
for _, v := range val {
ssv.Set(v)
}
ssv.changed = false
return ssv
}

func (s *kvArrayValue) Set(arg string) error {
split := strings.SplitN(arg, "=", 2)
if len(split) != 2 {
return errors.New("required format is 'key=value'")
}
k, v := split[0], split[1]
if k == "" {
return errors.New("key cannot be empty")
}
if !s.changed {
// Remove the default value
*s.value = make(map[string]string)
s.changed = true
}
if _, ok := (*s.value)[k]; ok {
return errors.New("duplicate key: " + k)
}
(*s.value)[k] = v
return nil
}

func (s *kvArrayValue) Type() string {
return "key=value"
}

func (s *kvArrayValue) String() string {
if len(*s.value) == 0 {
return ""
}
res := "["
for k, v := range *s.value {
res += fmt.Sprintf("%s=%s, ", k, v)
}
return res[:len(res)-2] + "]"
}
42 changes: 30 additions & 12 deletions internal/cli/upload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,21 @@ var (

// NewCommand created a new `upload` command
func NewCommand() *cobra.Command {
uploadFields := map[string]string{}
uploadCommand := &cobra.Command{
Use: "upload",
Short: tr("Upload Arduino sketches."),
Long: tr("Upload Arduino sketches. This does NOT compile the sketch prior to upload."),
Example: " " + os.Args[0] + " upload /home/user/Arduino/MySketch",
Args: cobra.MaximumNArgs(1),
Use: "upload",
Short: tr("Upload Arduino sketches."),
Long: tr("Upload Arduino sketches. This does NOT compile the sketch prior to upload."),
Example: "" +
" " + os.Args[0] + " upload /home/user/Arduino/MySketch -p /dev/ttyACM0 -b arduino:avr:uno\n" +
" " + os.Args[0] + " upload -p 192.168.10.1 -b arduino:avr:uno --upload-field password=abc",
Args: cobra.MaximumNArgs(1),
PreRun: func(cmd *cobra.Command, args []string) {
arguments.CheckFlagsConflicts(cmd, "input-file", "input-dir")
},
Run: runUploadCommand,
Run: func(cmd *cobra.Command, args []string) {
runUploadCommand(args, uploadFields)
},
}

fqbnArg.AddToCommand(uploadCommand)
Expand All @@ -73,10 +78,11 @@ func NewCommand() *cobra.Command {
programmer.AddToCommand(uploadCommand)
uploadCommand.Flags().BoolVar(&dryRun, "dry-run", false, tr("Do not perform the actual upload, just log out actions"))
uploadCommand.Flags().MarkHidden("dry-run")
arguments.AddKeyValuePFlag(uploadCommand, &uploadFields, "upload-field", "F", nil, tr("Set a value for a field required to upload."))
return uploadCommand
}

func runUploadCommand(command *cobra.Command, args []string) {
func runUploadCommand(args []string, uploadFieldsArgs map[string]string) {
logrus.Info("Executing `arduino-cli upload`")

path := ""
Expand Down Expand Up @@ -147,12 +153,24 @@ func runUploadCommand(command *cobra.Command, args []string) {

fields := map[string]string{}
if len(userFieldRes.UserFields) > 0 {
feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.Protocol))
if f, err := arguments.AskForUserFields(userFieldRes.UserFields); err != nil {
msg := fmt.Sprintf("%s: %s", tr("Error getting user input"), err)
feedback.Fatal(msg, feedback.ErrGeneric)
if len(uploadFieldsArgs) > 0 {
// If the user has specified some fields via cmd-line, we don't ask for them
for _, field := range userFieldRes.UserFields {
if value, ok := uploadFieldsArgs[field.Name]; ok {
fields[field.Name] = value
} else {
feedback.Fatal(tr("Missing required upload field: %s", field.Name), feedback.ErrBadArgument)
}
}
} else {
fields = f
// Otherwise prompt the user for them
feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.Protocol))
if f, err := arguments.AskForUserFields(userFieldRes.UserFields); err != nil {
msg := fmt.Sprintf("%s: %s", tr("Error getting user input"), err)
feedback.Fatal(msg, feedback.ErrGeneric)
} else {
fields = f
}
}
}

Expand Down

0 comments on commit 98c0480

Please sign in to comment.