Skip to content

Commit 7e95d55

Browse files
committed
Do not fully rewrite sketch.yaml when a key is automatically updated
1 parent f73f660 commit 7e95d55

File tree

7 files changed

+233
-9
lines changed

7 files changed

+233
-9
lines changed

.licenses/go/gopkg.in/yaml.v3.dep.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
name: gopkg.in/yaml.v3
3+
version: v3.0.1
4+
type: go
5+
summary: Package yaml implements YAML support for the Go language.
6+
homepage: https://pkg.go.dev/gopkg.in/yaml.v3
7+
license: other
8+
licenses:
9+
- sources: LICENSE
10+
text: |2
11+
12+
This project is covered by two different licenses: MIT and Apache.
13+
14+
#### MIT License ####
15+
16+
The following files were ported to Go from C files of libyaml, and thus
17+
are still covered by their original MIT license, with the additional
18+
copyright staring in 2011 when the project was ported over:
19+
20+
apic.go emitterc.go parserc.go readerc.go scannerc.go
21+
writerc.go yamlh.go yamlprivateh.go
22+
23+
Copyright (c) 2006-2010 Kirill Simonov
24+
Copyright (c) 2006-2011 Kirill Simonov
25+
26+
Permission is hereby granted, free of charge, to any person obtaining a copy of
27+
this software and associated documentation files (the "Software"), to deal in
28+
the Software without restriction, including without limitation the rights to
29+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
30+
of the Software, and to permit persons to whom the Software is furnished to do
31+
so, subject to the following conditions:
32+
33+
The above copyright notice and this permission notice shall be included in all
34+
copies or substantial portions of the Software.
35+
36+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42+
SOFTWARE.
43+
44+
### Apache License ###
45+
46+
All the remaining project files are covered by the Apache license:
47+
48+
Copyright (c) 2011-2019 Canonical Ltd
49+
50+
Licensed under the Apache License, Version 2.0 (the "License");
51+
you may not use this file except in compliance with the License.
52+
You may obtain a copy of the License at
53+
54+
http://www.apache.org/licenses/LICENSE-2.0
55+
56+
Unless required by applicable law or agreed to in writing, software
57+
distributed under the License is distributed on an "AS IS" BASIS,
58+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
59+
See the License for the specific language governing permissions and
60+
limitations under the License.
61+
- sources: README.md
62+
text: |-
63+
The yaml package is licensed under the MIT and Apache License 2.0 licenses.
64+
Please see the LICENSE file for details.
65+
notices:
66+
- sources: NOTICE
67+
text: |-
68+
Copyright 2011-2016 Canonical Ltd.
69+
70+
Licensed under the Apache License, Version 2.0 (the "License");
71+
you may not use this file except in compliance with the License.
72+
You may obtain a copy of the License at
73+
74+
http://www.apache.org/licenses/LICENSE-2.0
75+
76+
Unless required by applicable law or agreed to in writing, software
77+
distributed under the License is distributed on an "AS IS" BASIS,
78+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
79+
See the License for the specific language governing permissions and
80+
limitations under the License.

arduino/sketch/profiles.go

Lines changed: 0 additions & 6 deletions
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-
}

arduino/sketch/sketch.go

Lines changed: 5 additions & 2 deletions
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

arduino/sketch/yaml.go

Lines changed: 68 additions & 0 deletions
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 license@arduino.cc.
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+
}

arduino/sketch/yaml_test.go

Lines changed: 78 additions & 0 deletions
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 license@arduino.cc.
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+
}

docsgen/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,5 @@ require (
7777
gopkg.in/src-d/go-git.v4 v4.13.1 // indirect
7878
gopkg.in/warnings.v0 v0.1.2 // indirect
7979
gopkg.in/yaml.v2 v2.4.0 // indirect
80+
gopkg.in/yaml.v3 v3.0.1 // indirect
8081
)

go.mod

Lines changed: 1 addition & 1 deletion
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)