Skip to content

Extract templates to stdout #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ Delete a thing with the following command:

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

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

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

Bind a thing to an existing device:

Expand Down Expand Up @@ -198,9 +198,9 @@ Delete a dashboard with the following command:

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

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

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

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.

Expand Down
41 changes: 23 additions & 18 deletions cli/dashboard/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,21 @@ import (
"github.com/arduino/arduino-cloud-cli/command/dashboard"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

var extractFlags struct {
id string
outfile string
format string
id string
}

func initExtractCommand() *cobra.Command {
extractCommand := &cobra.Command{
Use: "extract",
Short: "Extract a template from a dashboard",
Long: "Extract a template from a Arduino IoT Cloud dashboard and save it in a file",
Long: "Extract a template from a Arduino IoT Cloud dashboard",
Run: runExtractCommand,
}
extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Dashboard ID")
extractCommand.Flags().StringVarP(&extractFlags.outfile, "outfile", "o", "", "Template file destination path")
extractCommand.Flags().StringVar(
&extractFlags.format,
"format",
"yaml",
"Format of template file, can be {json|yaml}. Default is 'yaml'",
)

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

params := &dashboard.ExtractParams{
ID: extractFlags.id,
Format: extractFlags.format,
}
if extractFlags.outfile != "" {
params.Outfile = &extractFlags.outfile
ID: extractFlags.id,
}

err := dashboard.Extract(params)
template, err := dashboard.Extract(params)
if err != nil {
feedback.Errorf("Error during template extraction: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

logrus.Info("Template successfully extracted")
feedback.PrintResult(extractResult{template})
}

type extractResult struct {
template map[string]interface{}
}

func (r extractResult) Data() interface{} {
return r.template
}

func (r extractResult) String() string {
t, err := yaml.Marshal(r.template)
if err != nil {
feedback.Errorf("Error during template parsing: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
return string(t)
}
41 changes: 23 additions & 18 deletions cli/thing/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,21 @@ import (
"github.com/arduino/arduino-cloud-cli/command/thing"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

var extractFlags struct {
id string
outfile string
format string
id string
}

func initExtractCommand() *cobra.Command {
extractCommand := &cobra.Command{
Use: "extract",
Short: "Extract a template from a thing",
Long: "Extract a template from a Arduino IoT Cloud thing and save it in a file",
Long: "Extract a template from a Arduino IoT Cloud thing",
Run: runExtractCommand,
}
extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Thing ID")
extractCommand.Flags().StringVarP(&extractFlags.outfile, "outfile", "o", "", "Template file destination path")
extractCommand.Flags().StringVar(
&extractFlags.format,
"format",
"yaml",
"Format of template file, can be {json|yaml}. Default is 'yaml'",
)

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

params := &thing.ExtractParams{
ID: extractFlags.id,
Format: extractFlags.format,
}
if extractFlags.outfile != "" {
params.Outfile = &extractFlags.outfile
ID: extractFlags.id,
}

err := thing.Extract(params)
template, err := thing.Extract(params)
if err != nil {
feedback.Errorf("Error during template extraction: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

logrus.Info("Template successfully extracted")
feedback.PrintResult(extractResult{template})
}

type extractResult struct {
template map[string]interface{}
}

func (r extractResult) Data() interface{} {
return r.template
}

func (r extractResult) String() string {
t, err := yaml.Marshal(r.template)
if err != nil {
feedback.Errorf("Error during template parsing: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
return string(t)
}
42 changes: 7 additions & 35 deletions command/dashboard/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,64 +18,36 @@
package dashboard

import (
"errors"
"fmt"
"strings"

"github.com/arduino/arduino-cloud-cli/internal/config"
"github.com/arduino/arduino-cloud-cli/internal/iot"
"github.com/arduino/arduino-cloud-cli/internal/template"
"github.com/sirupsen/logrus"
)

// ExtractParams contains the parameters needed to
// extract a template dashboard from Arduino IoT Cloud and save it on local storage.
// extract a template dashboard from Arduino IoT Cloud.
type ExtractParams struct {
ID string
Format string // Format determines the file format of the template ("json" or "yaml")
Outfile *string // Destination path of the extracted template
ID string
}

// Extract command is used to extract a dashboard template
// from a dashboard on Arduino IoT Cloud.
func Extract(params *ExtractParams) error {
params.Format = strings.ToLower(params.Format)
if params.Format != "json" && params.Format != "yaml" {
return errors.New("format is not valid: only 'json' and 'yaml' are supported")
}

func Extract(params *ExtractParams) (map[string]interface{}, error) {
conf, err := config.Retrieve()
if err != nil {
return err
return nil, err
}
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
if err != nil {
return err
return nil, err
}

dashboard, err := iotClient.DashboardShow(params.ID)
if err != nil {
err = fmt.Errorf("%s: %w", "cannot extract dashboard: ", err)
return err
}

templ := template.FromDashboard(dashboard)

if params.Outfile == nil {
name, ok := templ["name"].(string)
if name == "" || !ok {
return errors.New("dashboard template does not have a valid name")
}
name = strings.Join(strings.Fields(name), "")
outfile := name + "-dashboard." + params.Format
params.Outfile = &outfile
}

logrus.Infof("Extracting template in file: %s", *params.Outfile)
err = template.ToFile(templ, *params.Outfile, params.Format)
if err != nil {
return fmt.Errorf("saving template: %w", err)
return nil, err
}

return nil
return template.FromDashboard(dashboard), nil
}
42 changes: 7 additions & 35 deletions command/thing/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,64 +18,36 @@
package thing

import (
"errors"
"fmt"
"strings"

"github.com/arduino/arduino-cloud-cli/internal/config"
"github.com/arduino/arduino-cloud-cli/internal/iot"
"github.com/arduino/arduino-cloud-cli/internal/template"
"github.com/sirupsen/logrus"
)

// ExtractParams contains the parameters needed to
// extract a template thing from Arduino IoT Cloud and save it on local storage.
// extract a template thing from Arduino IoT Cloud.
type ExtractParams struct {
ID string
Format string // Format determines the file format of the template ("json" or "yaml")
Outfile *string // Destination path of the extracted template
ID string
}

// Extract command is used to extract a thing template
// from a thing on Arduino IoT Cloud.
func Extract(params *ExtractParams) error {
params.Format = strings.ToLower(params.Format)
if params.Format != "json" && params.Format != "yaml" {
return errors.New("format is not valid: only 'json' and 'yaml' are supported")
}

func Extract(params *ExtractParams) (map[string]interface{}, error) {
conf, err := config.Retrieve()
if err != nil {
return err
return nil, err
}
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
if err != nil {
return err
return nil, err
}

thing, err := iotClient.ThingShow(params.ID)
if err != nil {
err = fmt.Errorf("%s: %w", "cannot extract thing: ", err)
return err
}

templ := template.FromThing(thing)

if params.Outfile == nil {
name, ok := templ["name"].(string)
if name == "" || !ok {
return errors.New("thing template does not have a valid name")
}
name = strings.Join(strings.Fields(name), "")
outfile := name + "-thing." + params.Format
params.Outfile = &outfile
}

logrus.Infof("Extracting template in file: %s", *params.Outfile)
err = template.ToFile(templ, *params.Outfile, params.Format)
if err != nil {
return fmt.Errorf("saving template: %w", err)
return nil, err
}

return nil
return template.FromThing(thing), nil
}