Skip to content

Commit 98c0480

Browse files
authored
Added upload --upload-field key=value flag to set upload fields value (#2348)
* Added 'upload' flags to set upload fields value * Introducing key/value flag type
1 parent 331541a commit 98c0480

File tree

2 files changed

+111
-12
lines changed

2 files changed

+111
-12
lines changed

Diff for: internal/cli/arguments/key_value.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package arguments
17+
18+
import (
19+
"errors"
20+
"fmt"
21+
"strings"
22+
23+
"github.com/spf13/cobra"
24+
)
25+
26+
// AddKeyValuePFlag adds a flag to the command that accepts a (possibly repeated) key=value pair.
27+
func AddKeyValuePFlag(cmd *cobra.Command, field *map[string]string, name, shorthand string, value []string, usage string) {
28+
cmd.Flags().VarP(newKVArrayValue(value, field), name, shorthand, usage)
29+
}
30+
31+
type kvArrayValue struct {
32+
value *map[string]string
33+
changed bool
34+
}
35+
36+
func newKVArrayValue(val []string, p *map[string]string) *kvArrayValue {
37+
ssv := &kvArrayValue{
38+
value: p,
39+
}
40+
for _, v := range val {
41+
ssv.Set(v)
42+
}
43+
ssv.changed = false
44+
return ssv
45+
}
46+
47+
func (s *kvArrayValue) Set(arg string) error {
48+
split := strings.SplitN(arg, "=", 2)
49+
if len(split) != 2 {
50+
return errors.New("required format is 'key=value'")
51+
}
52+
k, v := split[0], split[1]
53+
if k == "" {
54+
return errors.New("key cannot be empty")
55+
}
56+
if !s.changed {
57+
// Remove the default value
58+
*s.value = make(map[string]string)
59+
s.changed = true
60+
}
61+
if _, ok := (*s.value)[k]; ok {
62+
return errors.New("duplicate key: " + k)
63+
}
64+
(*s.value)[k] = v
65+
return nil
66+
}
67+
68+
func (s *kvArrayValue) Type() string {
69+
return "key=value"
70+
}
71+
72+
func (s *kvArrayValue) String() string {
73+
if len(*s.value) == 0 {
74+
return ""
75+
}
76+
res := "["
77+
for k, v := range *s.value {
78+
res += fmt.Sprintf("%s=%s, ", k, v)
79+
}
80+
return res[:len(res)-2] + "]"
81+
}

Diff for: internal/cli/upload/upload.go

+30-12
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,21 @@ var (
5151

5252
// NewCommand created a new `upload` command
5353
func NewCommand() *cobra.Command {
54+
uploadFields := map[string]string{}
5455
uploadCommand := &cobra.Command{
55-
Use: "upload",
56-
Short: tr("Upload Arduino sketches."),
57-
Long: tr("Upload Arduino sketches. This does NOT compile the sketch prior to upload."),
58-
Example: " " + os.Args[0] + " upload /home/user/Arduino/MySketch",
59-
Args: cobra.MaximumNArgs(1),
56+
Use: "upload",
57+
Short: tr("Upload Arduino sketches."),
58+
Long: tr("Upload Arduino sketches. This does NOT compile the sketch prior to upload."),
59+
Example: "" +
60+
" " + os.Args[0] + " upload /home/user/Arduino/MySketch -p /dev/ttyACM0 -b arduino:avr:uno\n" +
61+
" " + os.Args[0] + " upload -p 192.168.10.1 -b arduino:avr:uno --upload-field password=abc",
62+
Args: cobra.MaximumNArgs(1),
6063
PreRun: func(cmd *cobra.Command, args []string) {
6164
arguments.CheckFlagsConflicts(cmd, "input-file", "input-dir")
6265
},
63-
Run: runUploadCommand,
66+
Run: func(cmd *cobra.Command, args []string) {
67+
runUploadCommand(args, uploadFields)
68+
},
6469
}
6570

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

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

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

148154
fields := map[string]string{}
149155
if len(userFieldRes.UserFields) > 0 {
150-
feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.Protocol))
151-
if f, err := arguments.AskForUserFields(userFieldRes.UserFields); err != nil {
152-
msg := fmt.Sprintf("%s: %s", tr("Error getting user input"), err)
153-
feedback.Fatal(msg, feedback.ErrGeneric)
156+
if len(uploadFieldsArgs) > 0 {
157+
// If the user has specified some fields via cmd-line, we don't ask for them
158+
for _, field := range userFieldRes.UserFields {
159+
if value, ok := uploadFieldsArgs[field.Name]; ok {
160+
fields[field.Name] = value
161+
} else {
162+
feedback.Fatal(tr("Missing required upload field: %s", field.Name), feedback.ErrBadArgument)
163+
}
164+
}
154165
} else {
155-
fields = f
166+
// Otherwise prompt the user for them
167+
feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.Protocol))
168+
if f, err := arguments.AskForUserFields(userFieldRes.UserFields); err != nil {
169+
msg := fmt.Sprintf("%s: %s", tr("Error getting user input"), err)
170+
feedback.Fatal(msg, feedback.ErrGeneric)
171+
} else {
172+
fields = f
173+
}
156174
}
157175
}
158176

0 commit comments

Comments
 (0)