Skip to content

Commit

Permalink
Introducing key/value flag type
Browse files Browse the repository at this point in the history
  • Loading branch information
cmaglie committed Oct 13, 2023
1 parent 47a858e commit e3ce8b5
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 19 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] + "]"
}
29 changes: 10 additions & 19 deletions internal/cli/upload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,29 +51,20 @@ var (

// NewCommand created a new `upload` command
func NewCommand() *cobra.Command {
var uploadFields []string
var parsedUploadFields map[string]string
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")
if len(uploadFields) > 0 {
parsedUploadFields = map[string]string{}
for _, field := range uploadFields {
split := strings.SplitN(field, "=", 2)
if len(split) != 2 {
feedback.Fatal(tr("Invalid upload field: %s", field), feedback.ErrBadArgument)
}
parsedUploadFields[split[0]] = split[1]
}
}
},
Run: func(cmd *cobra.Command, args []string) {
runUploadCommand(args, parsedUploadFields)
runUploadCommand(args, uploadFields)
},
}

Expand All @@ -87,7 +78,7 @@ 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")
uploadCommand.Flags().StringArrayVar(&uploadFields, "upload-field", uploadFields, tr("Set a value for a field required to upload.")+" (field=value)")
arguments.AddKeyValuePFlag(uploadCommand, &uploadFields, "upload-field", "F", nil, tr("Set a value for a field required to upload."))
return uploadCommand
}

Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ func main() {
configuration.Settings = configuration.Init(configuration.FindConfigFileInArgs(os.Args))
i18n.Init(configuration.Settings.GetString("locale"))
arduinoCmd := cli.NewCommand()
arduinoCmd.SilenceUsage = true
arduinoCmd.SilenceErrors = true
if err := arduinoCmd.Execute(); err != nil {
feedback.FatalError(err, feedback.ErrGeneric)
}
Expand Down

0 comments on commit e3ce8b5

Please sign in to comment.