Skip to content

Commit d708cb9

Browse files
Paolo Calaopolldo
Paolo Calao
authored andcommitted
Extract templates to stdout (#89)
Use stdout as primary output outlet of extract commands to allow piping the results for whatever reason
1 parent bb975a8 commit d708cb9

File tree

5 files changed

+64
-110
lines changed

5 files changed

+64
-110
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ Delete a thing with the following command:
154154

155155
`$ arduino-cloud-cli thing delete --id <thingID>`
156156

157-
Extract a template from an existing thing. The template can be saved in two formats: json or yaml. The default format is yaml:
157+
Extract a template from an existing thing. The template is printed to stdout and its format depends on the global `--format` flag:
158158

159-
`$ arduino-cloud-cli thing extract --id <thingID> --outfile <templateFile> --format <yaml|json>`
159+
`$ arduino-cloud-cli thing extract --id <thingID> --format <json|yaml>`
160160

161161
Bind a thing to an existing device:
162162

@@ -198,9 +198,9 @@ Delete a dashboard with the following command:
198198

199199
`$ arduino-cloud-cli dashboard delete --id <dashboardID>`
200200

201-
Extract a template from an existing dashboard. The template can be saved in two formats: json or yaml. The default format is yaml:
201+
Extract a template from an existing dashboard. The template is printed to stdout and its format depends on the global `--format` flag:
202202

203-
`$ arduino-cloud-cli dashboard extract --id <dashboardID> --outfile <templateFile> --format <yaml|json>`
203+
`$ arduino-cloud-cli dashboard extract --id <dashboardID> --format <json|yaml>`
204204

205205
Create a dashboard: dashboards can be created only starting from a template. Supported dashboard template formats are JSON and YAML. The name parameter is optional. If it is provided then it overrides the name retrieved from the template. The `override` flag can be used to override the template `thing_id` placeholder with the actual ID of the thing to be used.
206206

cli/dashboard/extract.go

+23-18
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,21 @@ import (
2525
"github.com/arduino/arduino-cloud-cli/command/dashboard"
2626
"github.com/sirupsen/logrus"
2727
"github.com/spf13/cobra"
28+
"gopkg.in/yaml.v3"
2829
)
2930

3031
var extractFlags struct {
31-
id string
32-
outfile string
33-
format string
32+
id string
3433
}
3534

3635
func initExtractCommand() *cobra.Command {
3736
extractCommand := &cobra.Command{
3837
Use: "extract",
3938
Short: "Extract a template from a dashboard",
40-
Long: "Extract a template from a Arduino IoT Cloud dashboard and save it in a file",
39+
Long: "Extract a template from a Arduino IoT Cloud dashboard",
4140
Run: runExtractCommand,
4241
}
4342
extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Dashboard ID")
44-
extractCommand.Flags().StringVarP(&extractFlags.outfile, "outfile", "o", "", "Template file destination path")
45-
extractCommand.Flags().StringVar(
46-
&extractFlags.format,
47-
"format",
48-
"yaml",
49-
"Format of template file, can be {json|yaml}. Default is 'yaml'",
50-
)
5143

5244
extractCommand.MarkFlagRequired("id")
5345
return extractCommand
@@ -57,18 +49,31 @@ func runExtractCommand(cmd *cobra.Command, args []string) {
5749
logrus.Infof("Extracting template from dashboard %s", extractFlags.id)
5850

5951
params := &dashboard.ExtractParams{
60-
ID: extractFlags.id,
61-
Format: extractFlags.format,
62-
}
63-
if extractFlags.outfile != "" {
64-
params.Outfile = &extractFlags.outfile
52+
ID: extractFlags.id,
6553
}
6654

67-
err := dashboard.Extract(params)
55+
template, err := dashboard.Extract(params)
6856
if err != nil {
6957
feedback.Errorf("Error during template extraction: %v", err)
7058
os.Exit(errorcodes.ErrGeneric)
7159
}
7260

73-
logrus.Info("Template successfully extracted")
61+
feedback.PrintResult(extractResult{template})
62+
}
63+
64+
type extractResult struct {
65+
template map[string]interface{}
66+
}
67+
68+
func (r extractResult) Data() interface{} {
69+
return r.template
70+
}
71+
72+
func (r extractResult) String() string {
73+
t, err := yaml.Marshal(r.template)
74+
if err != nil {
75+
feedback.Errorf("Error during template parsing: %v", err)
76+
os.Exit(errorcodes.ErrGeneric)
77+
}
78+
return string(t)
7479
}

cli/thing/extract.go

+23-18
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,21 @@ import (
2525
"github.com/arduino/arduino-cloud-cli/command/thing"
2626
"github.com/sirupsen/logrus"
2727
"github.com/spf13/cobra"
28+
"gopkg.in/yaml.v3"
2829
)
2930

3031
var extractFlags struct {
31-
id string
32-
outfile string
33-
format string
32+
id string
3433
}
3534

3635
func initExtractCommand() *cobra.Command {
3736
extractCommand := &cobra.Command{
3837
Use: "extract",
3938
Short: "Extract a template from a thing",
40-
Long: "Extract a template from a Arduino IoT Cloud thing and save it in a file",
39+
Long: "Extract a template from a Arduino IoT Cloud thing",
4140
Run: runExtractCommand,
4241
}
4342
extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Thing ID")
44-
extractCommand.Flags().StringVarP(&extractFlags.outfile, "outfile", "o", "", "Template file destination path")
45-
extractCommand.Flags().StringVar(
46-
&extractFlags.format,
47-
"format",
48-
"yaml",
49-
"Format of template file, can be {json|yaml}. Default is 'yaml'",
50-
)
5143

5244
extractCommand.MarkFlagRequired("id")
5345
return extractCommand
@@ -57,18 +49,31 @@ func runExtractCommand(cmd *cobra.Command, args []string) {
5749
logrus.Infof("Extracting template from thing %s", extractFlags.id)
5850

5951
params := &thing.ExtractParams{
60-
ID: extractFlags.id,
61-
Format: extractFlags.format,
62-
}
63-
if extractFlags.outfile != "" {
64-
params.Outfile = &extractFlags.outfile
52+
ID: extractFlags.id,
6553
}
6654

67-
err := thing.Extract(params)
55+
template, err := thing.Extract(params)
6856
if err != nil {
6957
feedback.Errorf("Error during template extraction: %v", err)
7058
os.Exit(errorcodes.ErrGeneric)
7159
}
7260

73-
logrus.Info("Template successfully extracted")
61+
feedback.PrintResult(extractResult{template})
62+
}
63+
64+
type extractResult struct {
65+
template map[string]interface{}
66+
}
67+
68+
func (r extractResult) Data() interface{} {
69+
return r.template
70+
}
71+
72+
func (r extractResult) String() string {
73+
t, err := yaml.Marshal(r.template)
74+
if err != nil {
75+
feedback.Errorf("Error during template parsing: %v", err)
76+
os.Exit(errorcodes.ErrGeneric)
77+
}
78+
return string(t)
7479
}

command/dashboard/extract.go

+7-35
Original file line numberDiff line numberDiff line change
@@ -18,64 +18,36 @@
1818
package dashboard
1919

2020
import (
21-
"errors"
2221
"fmt"
23-
"strings"
2422

2523
"github.com/arduino/arduino-cloud-cli/internal/config"
2624
"github.com/arduino/arduino-cloud-cli/internal/iot"
2725
"github.com/arduino/arduino-cloud-cli/internal/template"
28-
"github.com/sirupsen/logrus"
2926
)
3027

3128
// ExtractParams contains the parameters needed to
32-
// extract a template dashboard from Arduino IoT Cloud and save it on local storage.
29+
// extract a template dashboard from Arduino IoT Cloud.
3330
type ExtractParams struct {
34-
ID string
35-
Format string // Format determines the file format of the template ("json" or "yaml")
36-
Outfile *string // Destination path of the extracted template
31+
ID string
3732
}
3833

3934
// Extract command is used to extract a dashboard template
4035
// from a dashboard on Arduino IoT Cloud.
41-
func Extract(params *ExtractParams) error {
42-
params.Format = strings.ToLower(params.Format)
43-
if params.Format != "json" && params.Format != "yaml" {
44-
return errors.New("format is not valid: only 'json' and 'yaml' are supported")
45-
}
46-
36+
func Extract(params *ExtractParams) (map[string]interface{}, error) {
4737
conf, err := config.Retrieve()
4838
if err != nil {
49-
return err
39+
return nil, err
5040
}
5141
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
5242
if err != nil {
53-
return err
43+
return nil, err
5444
}
5545

5646
dashboard, err := iotClient.DashboardShow(params.ID)
5747
if err != nil {
5848
err = fmt.Errorf("%s: %w", "cannot extract dashboard: ", err)
59-
return err
60-
}
61-
62-
templ := template.FromDashboard(dashboard)
63-
64-
if params.Outfile == nil {
65-
name, ok := templ["name"].(string)
66-
if name == "" || !ok {
67-
return errors.New("dashboard template does not have a valid name")
68-
}
69-
name = strings.Join(strings.Fields(name), "")
70-
outfile := name + "-dashboard." + params.Format
71-
params.Outfile = &outfile
72-
}
73-
74-
logrus.Infof("Extracting template in file: %s", *params.Outfile)
75-
err = template.ToFile(templ, *params.Outfile, params.Format)
76-
if err != nil {
77-
return fmt.Errorf("saving template: %w", err)
49+
return nil, err
7850
}
7951

80-
return nil
52+
return template.FromDashboard(dashboard), nil
8153
}

command/thing/extract.go

+7-35
Original file line numberDiff line numberDiff line change
@@ -18,64 +18,36 @@
1818
package thing
1919

2020
import (
21-
"errors"
2221
"fmt"
23-
"strings"
2422

2523
"github.com/arduino/arduino-cloud-cli/internal/config"
2624
"github.com/arduino/arduino-cloud-cli/internal/iot"
2725
"github.com/arduino/arduino-cloud-cli/internal/template"
28-
"github.com/sirupsen/logrus"
2926
)
3027

3128
// ExtractParams contains the parameters needed to
32-
// extract a template thing from Arduino IoT Cloud and save it on local storage.
29+
// extract a template thing from Arduino IoT Cloud.
3330
type ExtractParams struct {
34-
ID string
35-
Format string // Format determines the file format of the template ("json" or "yaml")
36-
Outfile *string // Destination path of the extracted template
31+
ID string
3732
}
3833

3934
// Extract command is used to extract a thing template
4035
// from a thing on Arduino IoT Cloud.
41-
func Extract(params *ExtractParams) error {
42-
params.Format = strings.ToLower(params.Format)
43-
if params.Format != "json" && params.Format != "yaml" {
44-
return errors.New("format is not valid: only 'json' and 'yaml' are supported")
45-
}
46-
36+
func Extract(params *ExtractParams) (map[string]interface{}, error) {
4737
conf, err := config.Retrieve()
4838
if err != nil {
49-
return err
39+
return nil, err
5040
}
5141
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
5242
if err != nil {
53-
return err
43+
return nil, err
5444
}
5545

5646
thing, err := iotClient.ThingShow(params.ID)
5747
if err != nil {
5848
err = fmt.Errorf("%s: %w", "cannot extract thing: ", err)
59-
return err
60-
}
61-
62-
templ := template.FromThing(thing)
63-
64-
if params.Outfile == nil {
65-
name, ok := templ["name"].(string)
66-
if name == "" || !ok {
67-
return errors.New("thing template does not have a valid name")
68-
}
69-
name = strings.Join(strings.Fields(name), "")
70-
outfile := name + "-thing." + params.Format
71-
params.Outfile = &outfile
72-
}
73-
74-
logrus.Infof("Extracting template in file: %s", *params.Outfile)
75-
err = template.ToFile(templ, *params.Outfile, params.Format)
76-
if err != nil {
77-
return fmt.Errorf("saving template: %w", err)
49+
return nil, err
7850
}
7951

80-
return nil
52+
return template.FromThing(thing), nil
8153
}

0 commit comments

Comments
 (0)