diff --git a/command/thing/create.go b/command/thing/create.go
index 6467e4d5..4be2bac7 100644
--- a/command/thing/create.go
+++ b/command/thing/create.go
@@ -18,16 +18,11 @@
package thing
import (
- "encoding/json"
"errors"
- "fmt"
- "io/ioutil"
- "os"
"github.com/arduino/arduino-cloud-cli/internal/config"
"github.com/arduino/arduino-cloud-cli/internal/iot"
- iotclient "github.com/arduino/iot-client-go"
- "gopkg.in/yaml.v3"
+ "github.com/arduino/arduino-cloud-cli/internal/template"
)
// CreateParams contains the parameters needed to create a new thing.
@@ -47,7 +42,7 @@ func Create(params *CreateParams) (*ThingInfo, error) {
return nil, err
}
- thing, err := loadTemplate(params.Template)
+ thing, err := template.LoadThing(params.Template)
if err != nil {
return nil, err
}
@@ -69,45 +64,3 @@ func Create(params *CreateParams) (*ThingInfo, error) {
return getThingInfo(newThing), nil
}
-
-func loadTemplate(file string) (*iotclient.Thing, error) {
- templateFile, err := os.Open(file)
- if err != nil {
- return nil, err
- }
- defer templateFile.Close()
-
- templateBytes, err := ioutil.ReadAll(templateFile)
- if err != nil {
- return nil, err
- }
-
- template := make(map[string]interface{})
-
- // Extract template trying all the supported formats: json and yaml
- if err = json.Unmarshal([]byte(templateBytes), &template); err != nil {
- if err = yaml.Unmarshal([]byte(templateBytes), &template); err != nil {
- return nil, errors.New("reading template file: template format is not valid")
- }
- }
-
- // Adapt thing template to thing structure
- delete(template, "id")
- template["properties"] = template["variables"]
- delete(template, "variables")
-
- // Convert template into thing structure exploiting json marshalling/unmarshalling
- thing := &iotclient.Thing{}
-
- t, err := json.Marshal(template)
- if err != nil {
- return nil, fmt.Errorf("%s: %w", "extracting template", err)
- }
-
- err = json.Unmarshal(t, &thing)
- if err != nil {
- return nil, fmt.Errorf("%s: %w", "creating thing structure from template", err)
- }
-
- return thing, nil
-}
diff --git a/command/thing/extract.go b/command/thing/extract.go
index eb1b9770..dfeb47f4 100644
--- a/command/thing/extract.go
+++ b/command/thing/extract.go
@@ -18,17 +18,13 @@
package thing
import (
- "encoding/json"
"errors"
"fmt"
- "io/ioutil"
- "os"
"strings"
"github.com/arduino/arduino-cloud-cli/internal/config"
"github.com/arduino/arduino-cloud-cli/internal/iot"
- iotclient "github.com/arduino/iot-client-go"
- "gopkg.in/yaml.v3"
+ "github.com/arduino/arduino-cloud-cli/internal/template"
)
// ExtractParams contains the parameters needed to
@@ -62,62 +58,13 @@ func Extract(params *ExtractParams) error {
return err
}
- template, err := templateFromThing(thing)
+ templ, err := template.FromThing(thing)
if err != nil {
return err
}
- err = templateToFile(template, params)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func templateFromThing(thing *iotclient.ArduinoThing) (map[string]interface{}, error) {
- template := make(map[string]interface{})
- template["name"] = thing.Name
-
- // Extract template from thing structure
- var props []map[string]interface{}
- for _, p := range thing.Properties {
- prop := make(map[string]interface{})
- prop["name"] = p.Name
- prop["permission"] = p.Permission
- prop["type"] = p.Type
- prop["update_parameter"] = p.UpdateParameter
- prop["update_strategy"] = p.UpdateStrategy
- prop["variable_name"] = p.VariableName
- props = append(props, prop)
- }
- template["variables"] = props
-
- return template, nil
-}
-
-func templateToFile(template map[string]interface{}, params *ExtractParams) error {
- var file []byte
- var err error
-
- if params.Format == "json" {
- file, err = json.MarshalIndent(template, "", " ")
- if err != nil {
- return fmt.Errorf("%s: %w", "thing marshal failure: ", err)
- }
-
- } else if params.Format == "yaml" {
- file, err = yaml.Marshal(template)
- if err != nil {
- return fmt.Errorf("%s: %w", "thing marshal failure: ", err)
- }
-
- } else {
- return errors.New("format is not valid: only 'json' and 'yaml' are supported")
- }
-
if params.Outfile == nil {
- name, ok := template["name"].(string)
+ name, ok := templ["name"].(string)
if name == "" || !ok {
return errors.New("thing template does not have a valid name")
}
@@ -125,9 +72,9 @@ func templateToFile(template map[string]interface{}, params *ExtractParams) erro
params.Outfile = &outfile
}
- err = ioutil.WriteFile(*params.Outfile, file, os.FileMode(0644))
+ err = template.ToFile(templ, *params.Outfile, params.Format)
if err != nil {
- return fmt.Errorf("%s: %w", "cannot write outfile: ", err)
+ return fmt.Errorf("saving template: %w", err)
}
return nil
diff --git a/internal/template/extract.go b/internal/template/extract.go
new file mode 100644
index 00000000..b9790561
--- /dev/null
+++ b/internal/template/extract.go
@@ -0,0 +1,81 @@
+// This file is part of arduino-cloud-cli.
+//
+// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package template
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ iotclient "github.com/arduino/iot-client-go"
+ "gopkg.in/yaml.v3"
+)
+
+// FromThing extracts a template of type map[string]interface{} from a thing.
+func FromThing(thing *iotclient.ArduinoThing) (map[string]interface{}, error) {
+ template := make(map[string]interface{})
+ template["name"] = thing.Name
+
+ // Extract template from thing structure
+ var props []map[string]interface{}
+ for _, p := range thing.Properties {
+ prop := make(map[string]interface{})
+ prop["name"] = p.Name
+ prop["permission"] = p.Permission
+ prop["type"] = p.Type
+ prop["update_parameter"] = p.UpdateParameter
+ prop["update_strategy"] = p.UpdateStrategy
+ prop["variable_name"] = p.VariableName
+ props = append(props, prop)
+ }
+ template["variables"] = props
+
+ return template, nil
+}
+
+// ToFile takes a generic template and saves it into a file,
+// in the specified format (yaml or json).
+func ToFile(template map[string]interface{}, outfile string, format string) error {
+ var file []byte
+ var err error
+
+ if format == "json" {
+ file, err = json.MarshalIndent(template, "", " ")
+ if err != nil {
+ return fmt.Errorf("%s: %w", "template marshal failure: ", err)
+ }
+
+ } else if format == "yaml" {
+ file, err = yaml.Marshal(template)
+ if err != nil {
+ return fmt.Errorf("%s: %w", "template marshal failure: ", err)
+ }
+
+ } else {
+ return errors.New("format is not valid: only 'json' and 'yaml' are supported")
+ }
+
+ err = ioutil.WriteFile(outfile, file, os.FileMode(0644))
+ if err != nil {
+ return fmt.Errorf("%s: %w", "cannot write outfile: ", err)
+ }
+
+ return nil
+}
diff --git a/internal/template/load.go b/internal/template/load.go
new file mode 100644
index 00000000..b6a27df4
--- /dev/null
+++ b/internal/template/load.go
@@ -0,0 +1,84 @@
+// This file is part of arduino-cloud-cli.
+//
+// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package template
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ iotclient "github.com/arduino/iot-client-go"
+ "gopkg.in/yaml.v3"
+)
+
+// loadTemplate loads a template file and puts it into a generic template
+// of type map[string]interface{}.
+// The input template should be in json or yaml format.
+func loadTemplate(file string) (map[string]interface{}, error) {
+ templateFile, err := os.Open(file)
+ if err != nil {
+ return nil, err
+ }
+ defer templateFile.Close()
+
+ templateBytes, err := ioutil.ReadAll(templateFile)
+ if err != nil {
+ return nil, err
+ }
+
+ template := make(map[string]interface{})
+
+ // Extract template trying all the supported formats: json and yaml
+ if err = json.Unmarshal([]byte(templateBytes), &template); err != nil {
+ if err = yaml.Unmarshal([]byte(templateBytes), &template); err != nil {
+ return nil, errors.New("reading template file: template format is not valid")
+ }
+ }
+
+ return template, nil
+}
+
+// LoadThing loads a thing from a thing template file.
+func LoadThing(file string) (*iotclient.Thing, error) {
+ template, err := loadTemplate(file)
+ if err != nil {
+ return nil, err
+ }
+
+ // Adapt thing template to thing structure
+ delete(template, "id")
+ template["properties"] = template["variables"]
+ delete(template, "variables")
+
+ // Convert template into thing structure exploiting json marshalling/unmarshalling
+ thing := &iotclient.Thing{}
+
+ t, err := json.Marshal(template)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", "extracting template", err)
+ }
+
+ err = json.Unmarshal(t, &thing)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", "creating thing structure from template", err)
+ }
+
+ return thing, nil
+}