Skip to content

Commit d6be8bb

Browse files
committed
Import implementation and example
1 parent 1e29271 commit d6be8bb

File tree

5 files changed

+316
-0
lines changed

5 files changed

+316
-0
lines changed

cli.go

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// fwuploader-plugin-helper
2+
// Copyright (c) 2023 Arduino LLC. All right reserved.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published
6+
// by the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
package helper
18+
19+
import (
20+
"fmt"
21+
"os"
22+
"path/filepath"
23+
24+
"github.com/arduino/go-paths-helper"
25+
"github.com/spf13/cobra"
26+
)
27+
28+
// RunPlugin runs the given plugin
29+
func RunPlugin(plugin Plugin) {
30+
info := plugin.GetPluginInfo()
31+
32+
var portAddress string
33+
34+
firmwareFlashCmd := &cobra.Command{
35+
Use: "flash",
36+
Short: "Upload a firmware to the board",
37+
Run: func(cmd *cobra.Command, args []string) {
38+
if len(args) != 1 {
39+
fatal("Please specify firmware path", 2)
40+
}
41+
fwPath := paths.New(args[0])
42+
err := plugin.UploadFirmware(
43+
portAddress,
44+
fwPath,
45+
&PluginFeedback{stdOut: os.Stdout, stdErr: os.Stderr},
46+
)
47+
if err != nil {
48+
fatal(err.Error(), 3)
49+
}
50+
},
51+
}
52+
53+
firmwareGetVersionCmd := &cobra.Command{
54+
Use: "get-version",
55+
Short: "Get the version of the currently installed firmware on the board",
56+
Run: func(cmd *cobra.Command, args []string) {
57+
if len(args) > 0 {
58+
fatal("Invalid arguments provided", 4)
59+
}
60+
version, err := plugin.GetFirmwareVersion(
61+
portAddress,
62+
&PluginFeedback{stdOut: os.Stdout, stdErr: os.Stderr},
63+
)
64+
if err != nil {
65+
fatal(err.Error(), 3)
66+
}
67+
fmt.Println("FIRMWARE-VERSION:", version)
68+
},
69+
}
70+
71+
firmwareCmd := &cobra.Command{
72+
Use: "firmware",
73+
Short: "Firmware handling commands",
74+
}
75+
firmwareCmd.AddCommand(firmwareFlashCmd)
76+
firmwareCmd.AddCommand(firmwareGetVersionCmd)
77+
78+
certFlashCmd := &cobra.Command{
79+
Use: "flash",
80+
Short: "Upload a certificate on the board",
81+
Run: func(cmd *cobra.Command, args []string) {
82+
if len(args) != 1 {
83+
fatal("Please specify a certificate path", 2)
84+
}
85+
certPath := paths.New(args[0])
86+
err := plugin.UploadCertificate(
87+
portAddress,
88+
certPath,
89+
&PluginFeedback{stdOut: os.Stdout, stdErr: os.Stderr},
90+
)
91+
if err != nil {
92+
fatal(err.Error(), 3)
93+
}
94+
},
95+
}
96+
97+
certCmd := &cobra.Command{
98+
Use: "cert",
99+
Short: "Certificates handling commands",
100+
}
101+
certCmd.AddCommand(certFlashCmd)
102+
103+
appName := filepath.Base(os.Args[0])
104+
cli := &cobra.Command{
105+
Use: appName,
106+
Short: info.Name + " - This is an Arduino Firmware Uploader plugin.",
107+
}
108+
cli.AddCommand(firmwareCmd)
109+
cli.AddCommand(certCmd)
110+
cli.PersistentFlags().StringVarP(&portAddress, "address", "p", "", "Port address")
111+
112+
if err := cli.Execute(); err != nil {
113+
fatal(err.Error(), 1)
114+
}
115+
}
116+
117+
func fatal(msg string, exitcode int) {
118+
fmt.Fprintf(os.Stderr, "Error: %s\n", msg)
119+
os.Exit(exitcode)
120+
}

dummy-plugin/main.go

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// fwuploader-plugin-helper
2+
// Copyright (c) 2023 Arduino LLC. All right reserved.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published
6+
// by the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
package main
18+
19+
import (
20+
"fmt"
21+
"time"
22+
23+
helper "github.com/arduino/fwuploader-plugin-helper"
24+
"github.com/arduino/go-paths-helper"
25+
semver "go.bug.st/relaxed-semver"
26+
)
27+
28+
type dummyPlugin struct {
29+
}
30+
31+
func main() {
32+
helper.RunPlugin(&dummyPlugin{})
33+
}
34+
35+
// GetPluginInfo returns information about the plugin
36+
func (d *dummyPlugin) GetPluginInfo() *helper.PluginInfo {
37+
return &helper.PluginInfo{
38+
Name: "dummy",
39+
Version: semver.MustParse("1.0.0"),
40+
}
41+
}
42+
43+
// UploadFirmware performs a firmware upload on the board
44+
func (d *dummyPlugin) UploadFirmware(portAddress string, firmwarePath *paths.Path, feedback *helper.PluginFeedback) error {
45+
if portAddress == "" {
46+
fmt.Fprintln(feedback.Err(), "Port address not specified")
47+
return fmt.Errorf("invalid port address")
48+
}
49+
fmt.Fprintf(feedback.Out(), "Uploading %s to %s...\n", firmwarePath, portAddress)
50+
51+
// Fake upload
52+
time.Sleep(5 * time.Second)
53+
54+
fmt.Fprintf(feedback.Out(), "Upload completed!\n")
55+
return nil
56+
}
57+
58+
// UploadCertificate performs a certificate upload on the board
59+
func (d *dummyPlugin) UploadCertificate(portAddress string, certificatePath *paths.Path, feedback *helper.PluginFeedback) error {
60+
if portAddress == "" {
61+
fmt.Fprintln(feedback.Err(), "Port address not specified")
62+
return fmt.Errorf("invalid port address")
63+
}
64+
fmt.Fprintf(feedback.Out(), "Uploading to certificates to %s...\n", portAddress)
65+
66+
// Fake upload
67+
time.Sleep(5 * time.Second)
68+
69+
fmt.Fprintf(feedback.Out(), "Upload completed!\n")
70+
return nil
71+
}
72+
73+
// GetFirmwareVersion retrieve the firmware version installed on the board
74+
func (d *dummyPlugin) GetFirmwareVersion(portAddress string, feedback *helper.PluginFeedback) (*semver.RelaxedVersion, error) {
75+
if portAddress == "" {
76+
fmt.Fprintln(feedback.Err(), "Port address not specified")
77+
return nil, fmt.Errorf("invalid port address")
78+
}
79+
fmt.Fprintf(feedback.Out(), "Getting firmware version from %s...\n", portAddress)
80+
81+
// Fake query
82+
time.Sleep(5 * time.Second)
83+
84+
fmt.Fprintf(feedback.Out(), "Done!\n")
85+
return semver.ParseRelaxed("1.0.0"), nil
86+
}

go.mod

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module github.com/arduino/fwuploader-plugin-helper
2+
3+
go 1.20
4+
5+
require (
6+
github.com/arduino/go-paths-helper v1.9.1
7+
github.com/spf13/cobra v1.7.0
8+
go.bug.st/relaxed-semver v0.10.2
9+
)
10+
11+
require (
12+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
13+
github.com/pkg/errors v0.9.1 // indirect
14+
github.com/spf13/pflag v1.0.5 // indirect
15+
)

go.sum

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
github.com/arduino/go-paths-helper v1.9.1 h1:qpK+zMMjsklSBQa09/P5FZ/uf3LyjVmJK3DLeyiGjCc=
2+
github.com/arduino/go-paths-helper v1.9.1/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4Qyx+RAFKaG9NuvU=
3+
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
4+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6+
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
7+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
8+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
9+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
10+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
11+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
12+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
13+
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
14+
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
15+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
16+
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
17+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
18+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
19+
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
20+
go.bug.st/relaxed-semver v0.10.2 h1:d/ATAG3MByySZgg7rFj+Wj0fhvP4zfx9Z8Dn/NSCoFg=
21+
go.bug.st/relaxed-semver v0.10.2/go.mod h1:lPVGdtzbQ9/2fv6iXqIXWHOj6cMTUJ/l/Lu1w+sgdio=
22+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
23+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
24+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

plugin.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// fwuploader-plugin-helper
2+
// Copyright (c) 2023 Arduino LLC. All right reserved.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published
6+
// by the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
package helper
18+
19+
import (
20+
"io"
21+
22+
"github.com/arduino/go-paths-helper"
23+
semver "go.bug.st/relaxed-semver"
24+
)
25+
26+
// Plugin is the interface that the implementations of the Firmware Uploader plugins
27+
// must follow
28+
type Plugin interface {
29+
// GetPluginInfo returns information about the plugin
30+
GetPluginInfo() *PluginInfo
31+
32+
// UploadFirmware performs a firmware upload on the board
33+
UploadFirmware(portAddress string, firmwarePath *paths.Path, feedback *PluginFeedback) error
34+
35+
// UploadCertificate performs a certificate upload on the board
36+
UploadCertificate(portAddress string, certificatePath *paths.Path, feedback *PluginFeedback) error
37+
38+
// GetFirmwareVersion retrieve the firmware version installed on the board
39+
GetFirmwareVersion(portAddress string, feedback *PluginFeedback) (*semver.RelaxedVersion, error)
40+
}
41+
42+
// PluginInfo is a set of information describing the plugin
43+
type PluginInfo struct {
44+
// Name of the plugin
45+
Name string
46+
47+
// Version of the plugin
48+
Version *semver.Version
49+
}
50+
51+
// PluginFeedback is a struct that provides ways for the plugin to give feedback to
52+
// the user.
53+
type PluginFeedback struct {
54+
stdOut, stdErr io.Writer
55+
}
56+
57+
// Out returns an output stream for console-like feedback
58+
func (f *PluginFeedback) Out() io.Writer {
59+
if f.stdOut == nil {
60+
return io.Discard
61+
}
62+
return f.stdOut
63+
}
64+
65+
// Err returns an error stream for console-like feedback
66+
func (f *PluginFeedback) Err() io.Writer {
67+
if f.stdErr == nil {
68+
return io.Discard
69+
}
70+
return f.stdErr
71+
}

0 commit comments

Comments
 (0)