Skip to content

Commit e335327

Browse files
author
Massimiliano Pippi
authored
Allow naming sketches like "RCS" and "CVS" (arduino#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

arduino/builder/sketch.go

Lines changed: 29 additions & 18 deletions
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

arduino/builder/sketch_test.go

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

legacy/builder/container_setup.go

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

test/test_compile.py

Lines changed: 76 additions & 23 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy