Skip to content

Commit e335327

Browse files
author
Massimiliano Pippi
authored
Allow naming sketches like "RCS" and "CVS" (#537)
* avoid paniking if main sketch file is missing * rewrite the sketch contents collection logic + tests * fix tests
1 parent 48f3aaf commit e335327

File tree

4 files changed

+112
-43
lines changed

4 files changed

+112
-43
lines changed

Diff for: arduino/builder/sketch.go

+29-18
Original file line numberDiff line numberDiff line change
@@ -112,29 +112,31 @@ func SketchLoad(sketchPath, buildPath string) (*sketch.Sketch, error) {
112112
if stat.IsDir() {
113113
sketchFolder = sketchPath
114114
// allowed extensions are .ino and .pde (but not both)
115-
allowedSketchExtensions := [...]string{".ino", ".pde"}
116-
for _, extension := range allowedSketchExtensions {
115+
for extension := range globals.MainFileValidExtensions {
117116
candidateSketchFile := filepath.Join(sketchPath, stat.Name()+extension)
118117
if _, err := os.Stat(candidateSketchFile); !os.IsNotExist(err) {
119118
if mainSketchFile == "" {
120119
mainSketchFile = candidateSketchFile
121120
} else {
122-
return nil, errors.Errorf("more than one main sketch file found (%v,%v)",
121+
return nil, errors.Errorf("multiple main sketch files found (%v,%v)",
123122
filepath.Base(mainSketchFile),
124123
filepath.Base(candidateSketchFile))
125124
}
126125
}
127126
}
128-
// check that .pde or .ino was found
127+
128+
// check main file was found
129129
if mainSketchFile == "" {
130-
return nil, errors.Errorf("unable to find an sketch file in directory %v", sketchFolder)
130+
return nil, errors.Errorf("unable to find a sketch file in directory %v", sketchFolder)
131131
}
132-
// in the case a dir was passed, ensure the main file exists and is readable
132+
133+
// check main file is readable
133134
f, err := os.Open(mainSketchFile)
134135
if err != nil {
135136
return nil, errors.Wrap(err, "unable to open the main sketch file")
136137
}
137138
f.Close()
139+
138140
// ensure it is not a directory
139141
info, err := os.Stat(mainSketchFile)
140142
if err != nil {
@@ -150,28 +152,37 @@ func SketchLoad(sketchPath, buildPath string) (*sketch.Sketch, error) {
150152

151153
// collect all the sketch files
152154
var files []string
155+
rootVisited := false
153156
err = simpleLocalWalk(sketchFolder, maxFileSystemDepth, func(path string, info os.FileInfo, err error) error {
154-
155157
if err != nil {
156158
feedback.Errorf("Error during sketch processing: %v", err)
157159
os.Exit(errorcodes.ErrGeneric)
158160
}
159161

160-
// ignore hidden files and skip hidden directories
161-
if strings.HasPrefix(info.Name(), ".") {
162-
if info.IsDir() {
163-
return filepath.SkipDir
162+
if info.IsDir() {
163+
// Filters in this if-block are NOT applied to the sketch folder itself.
164+
// Since the sketch folder is the first one processed by simpleLocalWalk,
165+
// we can set the `rootVisited` guard to exclude it.
166+
if rootVisited {
167+
// skip hidden folders
168+
if strings.HasPrefix(info.Name(), ".") {
169+
return filepath.SkipDir
170+
}
171+
172+
// skip legacy SCM directories
173+
if info.Name() == "CVS" || info.Name() == "RCS" {
174+
return filepath.SkipDir
175+
}
176+
} else {
177+
rootVisited = true
164178
}
165-
return nil
166-
}
167179

168-
// skip legacy SCM directories
169-
if info.IsDir() && strings.HasPrefix(info.Name(), "CVS") || strings.HasPrefix(info.Name(), "RCS") {
170-
return filepath.SkipDir
180+
// ignore (don't skip) directory
181+
return nil
171182
}
172183

173-
// ignore directory entries
174-
if info.IsDir() {
184+
// ignore hidden files
185+
if strings.HasPrefix(info.Name(), ".") {
175186
return nil
176187
}
177188

Diff for: arduino/builder/sketch_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func TestLoadSketchFolderBothInoAndPde(t *testing.T) {
105105
sketchPath := filepath.Join("testdata", t.Name())
106106
_, err := builder.SketchLoad(sketchPath, "")
107107
require.Error(t, err)
108-
require.Contains(t, err.Error(), "more than one main sketch file found")
108+
require.Contains(t, err.Error(), "multiple main sketch files found")
109109
require.Contains(t, err.Error(), t.Name()+".ino")
110110
require.Contains(t, err.Error(), t.Name()+".pde")
111111
}
@@ -157,7 +157,7 @@ func TestLoadSketchFolderWrongMain(t *testing.T) {
157157
sketchPath := filepath.Join("testdata", t.Name())
158158
_, err := builder.SketchLoad(sketchPath, "")
159159
require.Error(t, err)
160-
require.Contains(t, err.Error(), "unable to find an sketch file in directory testdata")
160+
require.Contains(t, err.Error(), "unable to find a sketch file in directory testdata")
161161

162162
_, err = builder.SketchLoad("does/not/exist", "")
163163
require.Error(t, err)

Diff for: legacy/builder/container_setup.go

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package builder
1717

1818
import (
19+
"fmt"
20+
1921
bldr "github.com/arduino/arduino-cli/arduino/builder"
2022
"github.com/arduino/arduino-cli/legacy/builder/builder_utils"
2123
"github.com/arduino/arduino-cli/legacy/builder/i18n"
@@ -61,6 +63,9 @@ func (s *ContainerSetupHardwareToolsLibsSketchAndProps) Run(ctx *types.Context)
6163
if err != nil {
6264
return i18n.WrapError(err)
6365
}
66+
if sketch.MainFile == nil {
67+
return fmt.Errorf("main file missing from sketch")
68+
}
6469
ctx.SketchLocation = paths.New(sketch.MainFile.Path)
6570
ctx.Sketch = types.SketchToLegacy(sketch)
6671
}

Diff for: test/test_compile.py

+76-23
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,21 @@ def test_compile_with_simple_sketch(run_command, data_dir):
5757
log_file_path = os.path.join(data_dir, log_file_name)
5858
result = run_command(
5959
"compile -b {fqbn} {sketch_path} --log-format json --log-file {log_file} --log-level trace".format(
60-
fqbn=fqbn, sketch_path=sketch_path, log_file=log_file_path))
60+
fqbn=fqbn, sketch_path=sketch_path, log_file=log_file_path
61+
)
62+
)
6163
assert result.ok
6264

6365
# let's test from the logs if the hex file produced by successful compile is moved to our sketch folder
64-
log_json = open(log_file_path, 'r')
66+
log_json = open(log_file_path, "r")
6567
json_log_lines = log_json.readlines()
6668
expected_trace_sequence = [
6769
"Compile {sketch} for {fqbn} started".format(sketch=sketch_path, fqbn=fqbn),
68-
"Compile {sketch} for {fqbn} successful".format(sketch=sketch_name, fqbn=fqbn)
70+
"Compile {sketch} for {fqbn} successful".format(sketch=sketch_name, fqbn=fqbn),
6971
]
70-
assert is_message_sequence_in_json_log_traces(expected_trace_sequence, json_log_lines)
72+
assert is_message_sequence_in_json_log_traces(
73+
expected_trace_sequence, json_log_lines
74+
)
7175

7276

7377
def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir):
@@ -94,8 +98,8 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir):
9498

9599
# Build sketch for arduino:avr:uno
96100
result = run_command(
97-
"compile -b {fqbn} {sketch_path}".format(
98-
fqbn=fqbn, sketch_path=sketch_path))
101+
"compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)
102+
)
99103
# The assertion is a bit relaxed in this case because win behaves differently from macOs and linux
100104
# returning a different error detailed message
101105
assert "Error during sketch processing" in result.stderr
@@ -118,8 +122,8 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir):
118122

119123
# Build sketch for arduino:avr:uno
120124
result = run_command(
121-
"compile -b {fqbn} {sketch_path}".format(
122-
fqbn=fqbn, sketch_path=sketch_path))
125+
"compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)
126+
)
123127
# The assertion is a bit relaxed also in this case because macOS behaves differently from win and linux:
124128
# the cli does not follow recursively the symlink til breaking
125129
assert "Error during sketch processing" in result.stderr
@@ -177,32 +181,50 @@ def test_compile_and_compile_combo(run_command, data_dir):
177181
continue
178182
assert isinstance(boards, list)
179183
for board in boards:
180-
detected_boards.append(dict(address=port.get('address'), fqbn=board.get('FQBN')))
184+
detected_boards.append(
185+
dict(address=port.get("address"), fqbn=board.get("FQBN"))
186+
)
181187

182188
assert len(detected_boards) >= 1, "There are no boards available for testing"
183189

184190
# Build sketch for each detected board
185191
for board in detected_boards:
186-
log_file_name = "{fqbn}-compile.log".format(fqbn=board.get('fqbn').replace(":", "-"))
192+
log_file_name = "{fqbn}-compile.log".format(
193+
fqbn=board.get("fqbn").replace(":", "-")
194+
)
187195
log_file_path = os.path.join(data_dir, log_file_name)
188-
command_log_flags = "--log-format json --log-file {} --log-level trace".format(log_file_path)
189-
result = run_command("compile -b {fqbn} --upload -p {address} {sketch_path} {log_flags}".format(
190-
fqbn=board.get('fqbn'),
191-
address=board.get('address'),
192-
sketch_path=sketch_path,
193-
log_flags=command_log_flags
194-
))
196+
command_log_flags = "--log-format json --log-file {} --log-level trace".format(
197+
log_file_path
198+
)
199+
result = run_command(
200+
"compile -b {fqbn} --upload -p {address} {sketch_path} {log_flags}".format(
201+
fqbn=board.get("fqbn"),
202+
address=board.get("address"),
203+
sketch_path=sketch_path,
204+
log_flags=command_log_flags,
205+
)
206+
)
195207
assert result.ok
196208
# check from the logs if the bin file were uploaded on the current board
197-
log_json = open(log_file_path, 'r')
209+
log_json = open(log_file_path, "r")
198210
json_log_lines = log_json.readlines()
199211
expected_trace_sequence = [
200-
"Compile {sketch} for {fqbn} started".format(sketch=sketch_path, fqbn=board.get('fqbn')),
201-
"Compile {sketch} for {fqbn} successful".format(sketch=sketch_name, fqbn=board.get('fqbn')),
202-
"Upload {sketch} on {fqbn} started".format(sketch=sketch_path, fqbn=board.get('fqbn')),
203-
"Upload {sketch} on {fqbn} successful".format(sketch=sketch_name, fqbn=board.get('fqbn'))
212+
"Compile {sketch} for {fqbn} started".format(
213+
sketch=sketch_path, fqbn=board.get("fqbn")
214+
),
215+
"Compile {sketch} for {fqbn} successful".format(
216+
sketch=sketch_name, fqbn=board.get("fqbn")
217+
),
218+
"Upload {sketch} on {fqbn} started".format(
219+
sketch=sketch_path, fqbn=board.get("fqbn")
220+
),
221+
"Upload {sketch} on {fqbn} successful".format(
222+
sketch=sketch_name, fqbn=board.get("fqbn")
223+
),
204224
]
205-
assert is_message_sequence_in_json_log_traces(expected_trace_sequence, json_log_lines)
225+
assert is_message_sequence_in_json_log_traces(
226+
expected_trace_sequence, json_log_lines
227+
)
206228

207229

208230
def is_message_sequence_in_json_log_traces(message_sequence, log_json_lines):
@@ -213,3 +235,34 @@ def is_message_sequence_in_json_log_traces(message_sequence, log_json_lines):
213235
if entry.get("msg") in message_sequence:
214236
trace_entries.append(entry.get("msg"))
215237
return message_sequence == trace_entries
238+
239+
240+
def test_compile_blacklisted_sketchname(run_command, data_dir):
241+
"""
242+
Compile should ignore folders named `RCS`, `.git` and the likes, but
243+
it should be ok for a sketch to be named like RCS.ino
244+
"""
245+
# Init the environment explicitly
246+
result = run_command("core update-index")
247+
assert result.ok
248+
249+
# Download latest AVR
250+
result = run_command("core install arduino:avr")
251+
assert result.ok
252+
253+
sketch_name = "RCS"
254+
sketch_path = os.path.join(data_dir, sketch_name)
255+
fqbn = "arduino:avr:uno"
256+
257+
# Create a test sketch
258+
result = run_command("sketch new {}".format(sketch_path))
259+
assert result.ok
260+
assert "Sketch created in: {}".format(sketch_path) in result.stdout
261+
262+
# Build sketch for arduino:avr:uno
263+
log_file_name = "compile.log"
264+
log_file_path = os.path.join(data_dir, log_file_name)
265+
result = run_command(
266+
"compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)
267+
)
268+
assert result.ok

0 commit comments

Comments
 (0)