Skip to content

Commit a38df97

Browse files
Paolo Calaopolldo
Paolo Calao
authored andcommitted
Encapsulate template methods in package (#44)
* Encapsulate load template in template pkg * Encapsulate template extraction methods
1 parent c890e0e commit a38df97

File tree

4 files changed

+172
-107
lines changed

4 files changed

+172
-107
lines changed

Diff for: command/thing/create.go

+2-49
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,11 @@
1818
package thing
1919

2020
import (
21-
"encoding/json"
2221
"errors"
23-
"fmt"
24-
"io/ioutil"
25-
"os"
2622

2723
"github.com/arduino/arduino-cloud-cli/internal/config"
2824
"github.com/arduino/arduino-cloud-cli/internal/iot"
29-
iotclient "github.com/arduino/iot-client-go"
30-
"gopkg.in/yaml.v3"
25+
"github.com/arduino/arduino-cloud-cli/internal/template"
3126
)
3227

3328
// CreateParams contains the parameters needed to create a new thing.
@@ -47,7 +42,7 @@ func Create(params *CreateParams) (*ThingInfo, error) {
4742
return nil, err
4843
}
4944

50-
thing, err := loadTemplate(params.Template)
45+
thing, err := template.LoadThing(params.Template)
5146
if err != nil {
5247
return nil, err
5348
}
@@ -69,45 +64,3 @@ func Create(params *CreateParams) (*ThingInfo, error) {
6964

7065
return getThingInfo(newThing), nil
7166
}
72-
73-
func loadTemplate(file string) (*iotclient.Thing, error) {
74-
templateFile, err := os.Open(file)
75-
if err != nil {
76-
return nil, err
77-
}
78-
defer templateFile.Close()
79-
80-
templateBytes, err := ioutil.ReadAll(templateFile)
81-
if err != nil {
82-
return nil, err
83-
}
84-
85-
template := make(map[string]interface{})
86-
87-
// Extract template trying all the supported formats: json and yaml
88-
if err = json.Unmarshal([]byte(templateBytes), &template); err != nil {
89-
if err = yaml.Unmarshal([]byte(templateBytes), &template); err != nil {
90-
return nil, errors.New("reading template file: template format is not valid")
91-
}
92-
}
93-
94-
// Adapt thing template to thing structure
95-
delete(template, "id")
96-
template["properties"] = template["variables"]
97-
delete(template, "variables")
98-
99-
// Convert template into thing structure exploiting json marshalling/unmarshalling
100-
thing := &iotclient.Thing{}
101-
102-
t, err := json.Marshal(template)
103-
if err != nil {
104-
return nil, fmt.Errorf("%s: %w", "extracting template", err)
105-
}
106-
107-
err = json.Unmarshal(t, &thing)
108-
if err != nil {
109-
return nil, fmt.Errorf("%s: %w", "creating thing structure from template", err)
110-
}
111-
112-
return thing, nil
113-
}

Diff for: command/thing/extract.go

+5-58
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,13 @@
1818
package thing
1919

2020
import (
21-
"encoding/json"
2221
"errors"
2322
"fmt"
24-
"io/ioutil"
25-
"os"
2623
"strings"
2724

2825
"github.com/arduino/arduino-cloud-cli/internal/config"
2926
"github.com/arduino/arduino-cloud-cli/internal/iot"
30-
iotclient "github.com/arduino/iot-client-go"
31-
"gopkg.in/yaml.v3"
27+
"github.com/arduino/arduino-cloud-cli/internal/template"
3228
)
3329

3430
// ExtractParams contains the parameters needed to
@@ -62,72 +58,23 @@ func Extract(params *ExtractParams) error {
6258
return err
6359
}
6460

65-
template, err := templateFromThing(thing)
61+
templ, err := template.FromThing(thing)
6662
if err != nil {
6763
return err
6864
}
6965

70-
err = templateToFile(template, params)
71-
if err != nil {
72-
return err
73-
}
74-
75-
return nil
76-
}
77-
78-
func templateFromThing(thing *iotclient.ArduinoThing) (map[string]interface{}, error) {
79-
template := make(map[string]interface{})
80-
template["name"] = thing.Name
81-
82-
// Extract template from thing structure
83-
var props []map[string]interface{}
84-
for _, p := range thing.Properties {
85-
prop := make(map[string]interface{})
86-
prop["name"] = p.Name
87-
prop["permission"] = p.Permission
88-
prop["type"] = p.Type
89-
prop["update_parameter"] = p.UpdateParameter
90-
prop["update_strategy"] = p.UpdateStrategy
91-
prop["variable_name"] = p.VariableName
92-
props = append(props, prop)
93-
}
94-
template["variables"] = props
95-
96-
return template, nil
97-
}
98-
99-
func templateToFile(template map[string]interface{}, params *ExtractParams) error {
100-
var file []byte
101-
var err error
102-
103-
if params.Format == "json" {
104-
file, err = json.MarshalIndent(template, "", " ")
105-
if err != nil {
106-
return fmt.Errorf("%s: %w", "thing marshal failure: ", err)
107-
}
108-
109-
} else if params.Format == "yaml" {
110-
file, err = yaml.Marshal(template)
111-
if err != nil {
112-
return fmt.Errorf("%s: %w", "thing marshal failure: ", err)
113-
}
114-
115-
} else {
116-
return errors.New("format is not valid: only 'json' and 'yaml' are supported")
117-
}
118-
11966
if params.Outfile == nil {
120-
name, ok := template["name"].(string)
67+
name, ok := templ["name"].(string)
12168
if name == "" || !ok {
12269
return errors.New("thing template does not have a valid name")
12370
}
12471
outfile := name + "." + params.Format
12572
params.Outfile = &outfile
12673
}
12774

128-
err = ioutil.WriteFile(*params.Outfile, file, os.FileMode(0644))
75+
err = template.ToFile(templ, *params.Outfile, params.Format)
12976
if err != nil {
130-
return fmt.Errorf("%s: %w", "cannot write outfile: ", err)
77+
return fmt.Errorf("saving template: %w", err)
13178
}
13279

13380
return nil

Diff for: internal/template/extract.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// This file is part of arduino-cloud-cli.
2+
//
3+
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program 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
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
package template
19+
20+
import (
21+
"encoding/json"
22+
"errors"
23+
"fmt"
24+
"io/ioutil"
25+
"os"
26+
27+
iotclient "github.com/arduino/iot-client-go"
28+
"gopkg.in/yaml.v3"
29+
)
30+
31+
// FromThing extracts a template of type map[string]interface{} from a thing.
32+
func FromThing(thing *iotclient.ArduinoThing) (map[string]interface{}, error) {
33+
template := make(map[string]interface{})
34+
template["name"] = thing.Name
35+
36+
// Extract template from thing structure
37+
var props []map[string]interface{}
38+
for _, p := range thing.Properties {
39+
prop := make(map[string]interface{})
40+
prop["name"] = p.Name
41+
prop["permission"] = p.Permission
42+
prop["type"] = p.Type
43+
prop["update_parameter"] = p.UpdateParameter
44+
prop["update_strategy"] = p.UpdateStrategy
45+
prop["variable_name"] = p.VariableName
46+
props = append(props, prop)
47+
}
48+
template["variables"] = props
49+
50+
return template, nil
51+
}
52+
53+
// ToFile takes a generic template and saves it into a file,
54+
// in the specified format (yaml or json).
55+
func ToFile(template map[string]interface{}, outfile string, format string) error {
56+
var file []byte
57+
var err error
58+
59+
if format == "json" {
60+
file, err = json.MarshalIndent(template, "", " ")
61+
if err != nil {
62+
return fmt.Errorf("%s: %w", "template marshal failure: ", err)
63+
}
64+
65+
} else if format == "yaml" {
66+
file, err = yaml.Marshal(template)
67+
if err != nil {
68+
return fmt.Errorf("%s: %w", "template marshal failure: ", err)
69+
}
70+
71+
} else {
72+
return errors.New("format is not valid: only 'json' and 'yaml' are supported")
73+
}
74+
75+
err = ioutil.WriteFile(outfile, file, os.FileMode(0644))
76+
if err != nil {
77+
return fmt.Errorf("%s: %w", "cannot write outfile: ", err)
78+
}
79+
80+
return nil
81+
}

Diff for: internal/template/load.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// This file is part of arduino-cloud-cli.
2+
//
3+
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program 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
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
package template
19+
20+
import (
21+
"encoding/json"
22+
"errors"
23+
"fmt"
24+
"io/ioutil"
25+
"os"
26+
27+
iotclient "github.com/arduino/iot-client-go"
28+
"gopkg.in/yaml.v3"
29+
)
30+
31+
// loadTemplate loads a template file and puts it into a generic template
32+
// of type map[string]interface{}.
33+
// The input template should be in json or yaml format.
34+
func loadTemplate(file string) (map[string]interface{}, error) {
35+
templateFile, err := os.Open(file)
36+
if err != nil {
37+
return nil, err
38+
}
39+
defer templateFile.Close()
40+
41+
templateBytes, err := ioutil.ReadAll(templateFile)
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
template := make(map[string]interface{})
47+
48+
// Extract template trying all the supported formats: json and yaml
49+
if err = json.Unmarshal([]byte(templateBytes), &template); err != nil {
50+
if err = yaml.Unmarshal([]byte(templateBytes), &template); err != nil {
51+
return nil, errors.New("reading template file: template format is not valid")
52+
}
53+
}
54+
55+
return template, nil
56+
}
57+
58+
// LoadThing loads a thing from a thing template file.
59+
func LoadThing(file string) (*iotclient.Thing, error) {
60+
template, err := loadTemplate(file)
61+
if err != nil {
62+
return nil, err
63+
}
64+
65+
// Adapt thing template to thing structure
66+
delete(template, "id")
67+
template["properties"] = template["variables"]
68+
delete(template, "variables")
69+
70+
// Convert template into thing structure exploiting json marshalling/unmarshalling
71+
thing := &iotclient.Thing{}
72+
73+
t, err := json.Marshal(template)
74+
if err != nil {
75+
return nil, fmt.Errorf("%s: %w", "extracting template", err)
76+
}
77+
78+
err = json.Unmarshal(t, &thing)
79+
if err != nil {
80+
return nil, fmt.Errorf("%s: %w", "creating thing structure from template", err)
81+
}
82+
83+
return thing, nil
84+
}

0 commit comments

Comments
 (0)