Skip to content

Commit e9460fd

Browse files
committed
Do not fully rewrite sketch.yaml when a key is automatically updated
1 parent 95a7122 commit e9460fd

File tree

5 files changed

+152
-9
lines changed

5 files changed

+152
-9
lines changed

Diff for: arduino/sketch/profiles.go

-6
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,3 @@ func LoadProjectFile(file *paths.Path) (*Project, error) {
262262
}
263263
return res, nil
264264
}
265-
266-
// SaveProjectFile save the sketch project to a file
267-
func (s *Sketch) SaveProjectFile() error {
268-
projectFile := s.GetProjectPath()
269-
return projectFile.WriteFile([]byte(s.Project.AsYaml()))
270-
}

Diff for: arduino/sketch/sketch.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -252,15 +252,18 @@ func (s *Sketch) GetDefaultPortAddressAndProtocol() (string, string) {
252252
// SetDefaultFQBN sets the default FQBN for the sketch and saves it in the sketch.yaml project file.
253253
func (s *Sketch) SetDefaultFQBN(fqbn string) error {
254254
s.Project.DefaultFqbn = fqbn
255-
return s.SaveProjectFile()
255+
return updateOrAddYamlRootEntry(s.GetProjectPath(), "default_fqbn", fqbn)
256256
}
257257

258258
// SetDefaultPort sets the default port address and port protocol for the sketch and saves it in the
259259
// sketch.yaml project file.
260260
func (s *Sketch) SetDefaultPort(address, protocol string) error {
261261
s.Project.DefaultPort = address
262262
s.Project.DefaultProtocol = protocol
263-
return s.SaveProjectFile()
263+
if err := updateOrAddYamlRootEntry(s.GetProjectPath(), "default_port", address); err != nil {
264+
return err
265+
}
266+
return updateOrAddYamlRootEntry(s.GetProjectPath(), "default_protocol", protocol)
264267
}
265268

266269
// InvalidSketchFolderNameError is returned when the sketch directory doesn't match the sketch name

Diff for: arduino/sketch/yaml.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020-2022 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package sketch
17+
18+
import (
19+
"fmt"
20+
"strings"
21+
22+
"github.com/arduino/go-paths-helper"
23+
"gopkg.in/yaml.v3"
24+
)
25+
26+
func updateOrAddYamlRootEntry(path *paths.Path, key, newValue string) error {
27+
var srcYaml []string
28+
if path.Exist() {
29+
src, err := path.ReadFileAsLines()
30+
if err != nil {
31+
return err
32+
}
33+
srcYaml = src
34+
}
35+
36+
// Generate the new yaml key/value pair
37+
v, err := yaml.Marshal(newValue)
38+
if err != nil {
39+
return err
40+
}
41+
updatedLine := key + ": " + strings.TrimSpace(string(v))
42+
43+
// Update or add the key/value pair into the original yaml
44+
addMissing := true
45+
for i, line := range srcYaml {
46+
if strings.HasPrefix(line, key+": ") {
47+
srcYaml[i] = updatedLine
48+
addMissing = false
49+
break
50+
}
51+
}
52+
if addMissing {
53+
srcYaml = append(srcYaml, updatedLine)
54+
}
55+
56+
// Validate the new yaml
57+
dstYaml := []byte(strings.Join(srcYaml, fmt.Sprintln()))
58+
var dst interface{}
59+
if err := yaml.Unmarshal(dstYaml, &dst); err != nil {
60+
return fmt.Errorf("%s: %w", tr("could not update sketch project file"), err)
61+
}
62+
if dstMap, ok := dst.(map[string]interface{}); !ok || dstMap[key] != newValue {
63+
return fmt.Errorf(tr("could not update sketch project file"))
64+
}
65+
66+
// Write back the updated YAML
67+
return path.WriteFile(dstYaml)
68+
}

Diff for: arduino/sketch/yaml_test.go

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020-2022 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package sketch
17+
18+
import (
19+
"fmt"
20+
"strings"
21+
"testing"
22+
23+
"github.com/arduino/go-paths-helper"
24+
"github.com/stretchr/testify/require"
25+
)
26+
27+
func TestYamlUpdate(t *testing.T) {
28+
{
29+
sample, err := paths.New("testdata", "SketchWithProfiles", "sketch.yml").ReadFile()
30+
require.NoError(t, err)
31+
tmp, err := paths.WriteToTempFile(sample, nil, "")
32+
require.NoError(t, err)
33+
defer tmp.Remove()
34+
35+
err = updateOrAddYamlRootEntry(tmp, "default_fqbn", "arduino:avr:uno")
36+
require.NoError(t, err)
37+
err = updateOrAddYamlRootEntry(tmp, "default_port", "/dev/ttyACM0")
38+
require.NoError(t, err)
39+
40+
updated, err := tmp.ReadFile()
41+
require.NoError(t, err)
42+
expected := string(sample) + fmt.Sprintln()
43+
expected += fmt.Sprintln("default_fqbn: arduino:avr:uno")
44+
expected += "default_port: /dev/ttyACM0"
45+
require.Equal(t, expected, string(updated))
46+
}
47+
{
48+
sample, err := paths.New("testdata", "SketchWithDefaultFQBNAndPort", "sketch.yml").ReadFile()
49+
require.NoError(t, err)
50+
tmp, err := paths.WriteToTempFile(sample, nil, "")
51+
require.NoError(t, err)
52+
defer tmp.Remove()
53+
54+
err = updateOrAddYamlRootEntry(tmp, "default_fqbn", "TEST1")
55+
require.NoError(t, err)
56+
err = updateOrAddYamlRootEntry(tmp, "default_port", "TEST2")
57+
require.NoError(t, err)
58+
59+
updated, err := tmp.ReadFile()
60+
fmt.Print(string(updated))
61+
require.NoError(t, err)
62+
expected := strings.Replace(string(sample), "arduino:avr:uno", "TEST1", 1)
63+
expected = strings.Replace(expected, "/dev/ttyACM0", "TEST2", 1)
64+
require.Equal(t, expected, string(updated))
65+
}
66+
{
67+
tmp, err := paths.WriteToTempFile([]byte{}, nil, "")
68+
require.NoError(t, err)
69+
require.NoError(t, tmp.Remove())
70+
err = updateOrAddYamlRootEntry(tmp, "default_fqbn", "TEST1")
71+
require.NoError(t, err)
72+
73+
updated, err := tmp.ReadFile()
74+
require.NoError(t, err)
75+
expected := "default_fqbn: TEST1"
76+
require.Equal(t, expected, string(updated))
77+
}
78+
}

Diff for: go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ require (
5353
require (
5454
github.com/rogpeppe/go-internal v1.3.0
5555
go.bug.st/testifyjson v1.1.1
56+
gopkg.in/yaml.v3 v3.0.1
5657
)
5758

5859
require (
@@ -89,5 +90,4 @@ require (
8990
gopkg.in/ini.v1 v1.62.0 // indirect
9091
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
9192
gopkg.in/warnings.v0 v0.1.2 // indirect
92-
gopkg.in/yaml.v3 v3.0.1 // indirect
9393
)

0 commit comments

Comments
 (0)