Skip to content

Commit 4d7a0d2

Browse files
authoredJun 10, 2021
Firmware list command (#51)
* Show help if user doesn't specify any parameter * Renamed variable * Added 'firmware list' command stubs * Fixed json directive * Added Index.GetBoard method and factored out API in Index and BoardIndex * 'firmware list' first implementation
1 parent a99436b commit 4d7a0d2

File tree

6 files changed

+205
-54
lines changed

6 files changed

+205
-54
lines changed
 

‎cli/cli.go

+22-19
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"strings"
2929
"time"
3030

31+
"github.com/arduino/FirmwareUploader/cli/firmware"
3132
"github.com/arduino/FirmwareUploader/cli/version"
3233
"github.com/arduino/FirmwareUploader/modules/nina"
3334
"github.com/arduino/FirmwareUploader/modules/sara"
@@ -55,7 +56,7 @@ var (
5556

5657
func NewCommand() *cobra.Command {
5758
// FirmwareUploader is the root command
58-
firmwareUploaderCli := &cobra.Command{
59+
rootCmd := &cobra.Command{
5960
Use: "FirmwareUploader",
6061
Short: "FirmwareUploader.",
6162
Long: "FirmwareUploader (FirmwareUploader).",
@@ -65,28 +66,30 @@ func NewCommand() *cobra.Command {
6566
PersistentPreRun: preRun,
6667
}
6768

68-
firmwareUploaderCli.AddCommand(version.NewCommand())
69+
rootCmd.AddCommand(version.NewCommand())
6970

70-
firmwareUploaderCli.Flags().StringVar(&ctx.PortName, "port", "", "serial port to use for flashing")
71-
firmwareUploaderCli.Flags().StringVar(&ctx.RootCertDir, "certs", "", "root certificate directory")
72-
firmwareUploaderCli.Flags().StringSliceVar(&ctx.Addresses, "address", []string{}, "address (host:port) to fetch and flash root certificate for, multiple values allowed")
73-
firmwareUploaderCli.Flags().StringVar(&ctx.FirmwareFile, "firmware", "", "firmware file to flash")
74-
firmwareUploaderCli.Flags().BoolVar(&ctx.ReadAll, "read", false, "read all firmware and output to stdout")
75-
firmwareUploaderCli.Flags().StringVar(&ctx.FWUploaderBinary, "flasher", "", "firmware upload binary (precompiled for the right target)")
76-
firmwareUploaderCli.Flags().StringVar(&ctx.BinaryToRestore, "restore_binary", "", "binary to restore after the firmware upload (precompiled for the right target)")
77-
firmwareUploaderCli.Flags().StringVar(&ctx.ProgrammerPath, "programmer", "", "path of programmer in use (avrdude/bossac)")
78-
firmwareUploaderCli.Flags().StringVar(&ctx.Model, "model", "", "module model (winc, nina or sara)")
79-
firmwareUploaderCli.Flags().StringVar(&ctx.BoardName, "get_available_for", "", "Ask for available firmwares matching a given board")
80-
firmwareUploaderCli.Flags().IntVar(&ctx.Retries, "retries", 9, "Number of retries in case of upload failure")
71+
rootCmd.AddCommand(firmware.NewCommand())
8172

82-
firmwareUploaderCli.PersistentFlags().StringVar(&outputFormat, "format", "text", "The output format, can be {text|json}.")
73+
rootCmd.Flags().StringVar(&ctx.PortName, "port", "", "serial port to use for flashing")
74+
rootCmd.Flags().StringVar(&ctx.RootCertDir, "certs", "", "root certificate directory")
75+
rootCmd.Flags().StringSliceVar(&ctx.Addresses, "address", []string{}, "address (host:port) to fetch and flash root certificate for, multiple values allowed")
76+
rootCmd.Flags().StringVar(&ctx.FirmwareFile, "firmware", "", "firmware file to flash")
77+
rootCmd.Flags().BoolVar(&ctx.ReadAll, "read", false, "read all firmware and output to stdout")
78+
rootCmd.Flags().StringVar(&ctx.FWUploaderBinary, "flasher", "", "firmware upload binary (precompiled for the right target)")
79+
rootCmd.Flags().StringVar(&ctx.BinaryToRestore, "restore_binary", "", "binary to restore after the firmware upload (precompiled for the right target)")
80+
rootCmd.Flags().StringVar(&ctx.ProgrammerPath, "programmer", "", "path of programmer in use (avrdude/bossac)")
81+
rootCmd.Flags().StringVar(&ctx.Model, "model", "", "module model (winc, nina or sara)")
82+
rootCmd.Flags().StringVar(&ctx.BoardName, "get_available_for", "", "Ask for available firmwares matching a given board")
83+
rootCmd.Flags().IntVar(&ctx.Retries, "retries", 9, "Number of retries in case of upload failure")
8384

84-
firmwareUploaderCli.PersistentFlags().StringVar(&logFile, "log-file", "", "Path to the file where logs will be written")
85-
firmwareUploaderCli.PersistentFlags().StringVar(&logFormat, "log-format", "", "The output format for the logs, can be {text|json}.")
86-
firmwareUploaderCli.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Messages with this level and above will be logged. Valid levels are: trace, debug, info, warn, error, fatal, panic")
87-
firmwareUploaderCli.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the logs on the standard output.")
85+
rootCmd.PersistentFlags().StringVar(&outputFormat, "format", "text", "The output format, can be {text|json}.")
8886

89-
return firmwareUploaderCli
87+
rootCmd.PersistentFlags().StringVar(&logFile, "log-file", "", "Path to the file where logs will be written")
88+
rootCmd.PersistentFlags().StringVar(&logFormat, "log-format", "", "The output format for the logs, can be {text|json}.")
89+
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Messages with this level and above will be logged. Valid levels are: trace, debug, info, warn, error, fatal, panic")
90+
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the logs on the standard output.")
91+
92+
return rootCmd
9093
}
9194

9295
func run(cmd *cobra.Command, args []string) {

‎cli/firmware/firmware.go

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
FirmwareUploader
3+
Copyright (c) 2021 Arduino LLC. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package firmware
21+
22+
import (
23+
"os"
24+
25+
"github.com/spf13/cobra"
26+
)
27+
28+
func NewCommand() *cobra.Command {
29+
firmwareCmd := &cobra.Command{
30+
Use: "firmware",
31+
Short: "Commands to operate on firmwares.",
32+
Long: "A subset of commands to perform various firmware operations.",
33+
Example: " " + os.Args[0] + " firmware ...",
34+
}
35+
36+
firmwareCmd.AddCommand(newListCommand())
37+
return firmwareCmd
38+
}

‎cli/firmware/list.go

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
FirmwareUploader
3+
Copyright (c) 2021 Arduino LLC. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package firmware
21+
22+
import (
23+
"os"
24+
25+
"github.com/arduino/FirmwareUploader/indexes"
26+
"github.com/arduino/arduino-cli/cli/feedback"
27+
"github.com/arduino/arduino-cli/table"
28+
"github.com/spf13/cobra"
29+
)
30+
31+
func newListCommand() *cobra.Command {
32+
var fqbn *string
33+
34+
listCmd := &cobra.Command{
35+
Use: "list",
36+
Short: "List available firmwares",
37+
Long: "Displays the availale firmwares, is it possible to filter results for a specific board.",
38+
Example: " " + os.Args[0] + " firmware list -b arduino:samd:mkr1000",
39+
Args: cobra.NoArgs,
40+
Run: func(cmd *cobra.Command, args []string) {
41+
list(*fqbn)
42+
},
43+
}
44+
fqbn = listCmd.Flags().StringP("fqbn", "b", "", "Filter result for the specified board FQBN")
45+
return listCmd
46+
}
47+
48+
type FirmwareResult struct {
49+
BoardName string `json:"board_name"`
50+
BoardFQBN string `json:"board_fqbn"`
51+
Module string `json:"module"`
52+
FirmwareVersion string `json:"firmware_version"`
53+
Latest bool
54+
}
55+
56+
type FirmwareListResult []*FirmwareResult
57+
58+
func list(fqbn string) {
59+
firmwareIndex, err := indexes.GetFirmwareIndex()
60+
if err != nil {
61+
feedback.Error(err)
62+
}
63+
64+
res := FirmwareListResult{}
65+
for _, board := range firmwareIndex.Boards {
66+
if fqbn == "" || board.Fqbn == fqbn {
67+
for _, firmware := range board.Firmwares {
68+
res = append(res, &FirmwareResult{
69+
BoardName: board.Name,
70+
BoardFQBN: board.Fqbn,
71+
Module: board.Module,
72+
FirmwareVersion: firmware.Version,
73+
})
74+
}
75+
}
76+
}
77+
78+
feedback.PrintResult(res)
79+
}
80+
81+
func (f FirmwareListResult) String() string {
82+
if len(f) == 0 {
83+
return "No firmwares available."
84+
}
85+
t := table.New()
86+
t.SetHeader("Board", "FQBN", "Module", "Version")
87+
for _, fw := range f {
88+
t.AddRow(fw.BoardName, fw.BoardFQBN, fw.Module, fw.FirmwareVersion)
89+
}
90+
return t.Render()
91+
}
92+
93+
func (f FirmwareListResult) Data() interface{} {
94+
return f
95+
}

‎go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
7777
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
7878
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
7979
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
80+
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
8081
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
8182
github.com/fluxio/iohelpers v0.0.0-20160419043813-3a4dd67a94d2/go.mod h1:c7sGIpDbBo0JZZ1tKyC1p5smWf8QcUjK4bFtZjHAecg=
8283
github.com/fluxio/multierror v0.0.0-20160419044231-9c68d39025e5/go.mod h1:BEUDl7FG1cc76sM0J0x8dqr6RhiL4uqvk6oFkwuNyuM=

‎indexes/firmwareindex/firmwareindex.go

+44-35
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ type IndexFirmware struct {
6262
URL string `json:"url,required"`
6363
Checksum string `json:"checksum,required"`
6464
Size json.Number `json:"size,required"`
65-
Module string `json:module,required`
65+
Module string `json:"module,required"`
6666
}
6767

6868
// IndexLoaderSketch represents the sketch used to upload the new firmware on a board.
@@ -129,54 +129,63 @@ func LoadIndexNoSign(jsonIndexFile *paths.Path) (*Index, error) {
129129
// GetLatestFirmwareURL takes the fqbn as parameter and returns the URL of the latest available firmware.
130130
// Not currently implemented for SARA, as the version for it's firmware is a bit strange
131131
func (i *Index) GetLatestFirmwareURL(fqbn string) (string, error) {
132-
for _, board := range i.Boards {
133-
var latestVersion *semver.RelaxedVersion
134-
var latestFirmwareURL string
135-
if board.Fqbn == fqbn && board.Module != "SARA" { // TODO togliere sara, lo assumo giá nel comando
136-
for _, firmware := range board.Firmwares {
137-
version := semver.ParseRelaxed(firmware.Version)
138-
if latestVersion == nil || version.GreaterThan(latestVersion) { // TODO check the condition
139-
latestVersion = version
140-
latestFirmwareURL = firmware.URL
141-
}
142-
}
143-
if latestVersion != nil {
144-
return latestFirmwareURL, nil
145-
} else {
146-
return "", fmt.Errorf("cannot find latest version")
147-
}
148-
} else if board.Fqbn == fqbn { // SARA
149-
// TODO implement?? by defualt you have to specify the version
150-
return "", fmt.Errorf("not implemented for SARA module")
132+
board := i.GetBoard(fqbn)
133+
if board == nil {
134+
return "", fmt.Errorf("invalid FQBN: %s", fqbn)
135+
}
136+
if board.Module == "SARA" { // TODO togliere sara, lo assumo giá nel comando
137+
// TODO implement?? by defualt you have to specify the version
138+
return "", fmt.Errorf("not implemented for SARA module")
139+
}
140+
141+
var latestVersion *semver.RelaxedVersion
142+
var latestFirmwareURL string
143+
for _, firmware := range board.Firmwares {
144+
version := semver.ParseRelaxed(firmware.Version)
145+
if latestVersion == nil || version.GreaterThan(latestVersion) { // TODO check the condition
146+
latestVersion = version
147+
latestFirmwareURL = firmware.URL
151148
}
152149
}
153-
return "", fmt.Errorf("invalid FQBN: %s", fqbn)
150+
if latestVersion != nil {
151+
return latestFirmwareURL, nil
152+
} else {
153+
return "", fmt.Errorf("cannot find latest version")
154+
}
154155
}
155156

156157
// GetFirmwareURL will take the fqbn of the required board and the version of the firmware as parameters.
157-
// It will return the URL of the required firmware
158+
// It will return the URL of the required firmware
158159
func (i *Index) GetFirmwareURL(fqbn, version string) (string, error) {
159-
for _, board := range i.Boards {
160-
if board.Fqbn == fqbn {
161-
for _, firmware := range board.Firmwares {
162-
if firmware.Version == version {
163-
return firmware.URL, nil
164-
}
165-
}
166-
return "", fmt.Errorf("invalid version: %s", version)
160+
board := i.GetBoard(fqbn)
161+
if board == nil {
162+
return "", fmt.Errorf("invalid FQBN: %s", fqbn)
163+
}
164+
for _, firmware := range board.Firmwares {
165+
if firmware.Version == version {
166+
return firmware.URL, nil
167167
}
168168
}
169-
return "", fmt.Errorf("invalid FQBN: %s", fqbn)
169+
return "", fmt.Errorf("invalid version: %s", version)
170170
}
171171

172172
// GetLoaderSketchURL will take the board's fqbn and return the url of the loader sketch
173173
func (i *Index) GetLoaderSketchURL(fqbn string) (string, error) {
174-
for _, board := range i.Boards {
175-
if board.Fqbn == fqbn {
176-
return board.LoaderSketch.URL, nil
174+
board := i.GetBoard(fqbn)
175+
if board == nil {
176+
return "", fmt.Errorf("invalid FQBN: %s", fqbn)
177+
}
178+
return board.LoaderSketch.URL, nil
179+
}
180+
181+
// GetBoard returns the IndexBoard for the given FQBN
182+
func (i *Index) GetBoard(fqbn string) *IndexBoard {
183+
for _, b := range i.Boards {
184+
if b.Fqbn == fqbn {
185+
return b
177186
}
178187
}
179-
return "", fmt.Errorf("invalid FQBN: %s", fqbn)
188+
return nil
180189
}
181190

182191
func (b *IndexBoard) GetUploaderCommand() string {

‎main.go

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ import (
2727

2828
func main() {
2929
uploaderCmd := cli.NewCommand()
30+
if len(os.Args) == 1 {
31+
// Show help if user doesn't specify any parameter
32+
uploaderCmd.Help()
33+
os.Exit(1)
34+
}
3035
if err := uploaderCmd.Execute(); err != nil {
3136
os.Exit(1)
3237
}

0 commit comments

Comments
 (0)
Please sign in to comment.