Skip to content

Commit ffe44ea

Browse files
authoredJan 29, 2021
Add back support for sketches with .pde extension and deprecate it (#1157)
* Compile command now works with sketches containing .pde files * Upload command now works with sketches and builds from .pde files * Archive command now works with sketches containing .pde files * [skip changelog] Add test to verify debug command works with pde sketches * Fix lib examples not showing sketches with .pde files * [skip changelog] Remove duplicated code and enhance tests
1 parent d1163cb commit ffe44ea

File tree

21 files changed

+469
-45
lines changed

21 files changed

+469
-45
lines changed
 

‎arduino/globals/globals.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ package globals
1818
var (
1919
empty struct{}
2020

21+
// MainFileValidExtension is the extension that must be used for files in new sketches
22+
MainFileValidExtension string = ".ino"
23+
2124
// MainFileValidExtensions lists valid extensions for a sketch file
2225
MainFileValidExtensions = map[string]struct{}{
23-
".ino": empty,
26+
MainFileValidExtension: empty,
27+
// .pde extension is deprecated and must not be used for new sketches
2428
".pde": empty,
2529
}
2630

‎arduino/libraries/loader.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020
"strings"
2121

22+
"github.com/arduino/arduino-cli/arduino/sketches"
2223
"github.com/arduino/go-paths-helper"
2324
properties "github.com/arduino/go-properties-orderedmap"
2425
"github.com/pkg/errors"
@@ -172,7 +173,8 @@ func addExamplesToPathList(examplesPath *paths.Path, list *paths.PathList) error
172173
return err
173174
}
174175
for _, file := range files {
175-
if isExample(file) {
176+
_, err := sketches.NewSketchFromPath(file)
177+
if err == nil {
176178
list.Add(file)
177179
} else if file.IsDir() {
178180
if err := addExamplesToPathList(file, list); err != nil {
@@ -182,9 +184,3 @@ func addExamplesToPathList(examplesPath *paths.Path, list *paths.PathList) error
182184
}
183185
return nil
184186
}
185-
186-
// isExample returns true if examplePath contains an example
187-
func isExample(examplePath *paths.Path) bool {
188-
mainIno := examplePath.Join(examplePath.Base() + ".ino")
189-
return mainIno.Exist() && mainIno.IsNotDir()
190-
}

‎arduino/sketches/sketches.go

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@ import (
2020
"fmt"
2121

2222
"github.com/arduino/arduino-cli/arduino/builder"
23+
"github.com/arduino/arduino-cli/arduino/globals"
2324
"github.com/arduino/go-paths-helper"
2425
"github.com/pkg/errors"
2526
)
2627

2728
// Sketch is a sketch for Arduino
2829
type Sketch struct {
29-
Name string
30-
FullPath *paths.Path
31-
Metadata *Metadata
30+
Name string
31+
MainFileExtension string
32+
FullPath *paths.Path
33+
Metadata *Metadata
3234
}
3335

3436
// Metadata is the kind of data associated to a project such as the connected board
@@ -52,14 +54,32 @@ func NewSketchFromPath(path *paths.Path) (*Sketch, error) {
5254
if !path.IsDir() {
5355
path = path.Parent()
5456
}
55-
sketchFile := path.Join(path.Base() + ".ino")
56-
if !sketchFile.Exist() {
57-
return nil, errors.Errorf("no valid sketch found in %s: missing %s", path, sketchFile.Base())
57+
58+
var mainSketchFile *paths.Path
59+
for ext := range globals.MainFileValidExtensions {
60+
candidateSketchMainFile := path.Join(path.Base() + ext)
61+
if candidateSketchMainFile.Exist() {
62+
if mainSketchFile == nil {
63+
mainSketchFile = candidateSketchMainFile
64+
} else {
65+
return nil, errors.Errorf("multiple main sketch files found (%v, %v)",
66+
mainSketchFile,
67+
candidateSketchMainFile,
68+
)
69+
}
70+
}
71+
}
72+
73+
if mainSketchFile == nil {
74+
sketchFile := path.Join(path.Base() + globals.MainFileValidExtension)
75+
return nil, errors.Errorf("no valid sketch found in %s: missing %s", path, sketchFile)
5876
}
77+
5978
sketch := &Sketch{
60-
FullPath: path,
61-
Name: path.Base(),
62-
Metadata: &Metadata{},
79+
FullPath: path,
80+
MainFileExtension: mainSketchFile.Ext(),
81+
Name: path.Base(),
82+
Metadata: &Metadata{},
6383
}
6484
sketch.ImportMetadata()
6585
return sketch, nil
@@ -108,3 +128,20 @@ func (s *Sketch) BuildPath() (*paths.Path, error) {
108128
}
109129
return builder.GenBuildPath(s.FullPath), nil
110130
}
131+
132+
// CheckForPdeFiles returns all files ending with .pde extension
133+
// in dir, this is mainly used to warn the user that these files
134+
// must be changed to .ino extension.
135+
// When .pde files won't be supported anymore this function must be removed.
136+
func CheckForPdeFiles(sketch *paths.Path) []*paths.Path {
137+
if sketch.IsNotDir() {
138+
sketch = sketch.Parent()
139+
}
140+
141+
files, err := sketch.ReadDirRecursive()
142+
if err != nil {
143+
return []*paths.Path{}
144+
}
145+
files.FilterSuffix(".pde")
146+
return files
147+
}

‎arduino/sketches/sketches_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,59 @@ func TestSketchBuildPath(t *testing.T) {
5353
require.NoError(t, err)
5454
require.Contains(t, buildPath.String(), "arduino-sketch-")
5555

56+
// Verifies sketch path is returned if sketch has .pde extension
57+
sketchPath = paths.New("testdata", "SketchPde")
58+
sketch, err = NewSketchFromPath(sketchPath)
59+
require.NoError(t, err)
60+
require.NotNil(t, sketch)
61+
buildPath, err = sketch.BuildPath()
62+
require.NoError(t, err)
63+
require.Contains(t, buildPath.String(), "arduino-sketch-")
64+
65+
// Verifies error is returned if there are multiple main files
66+
sketchPath = paths.New("testdata", "SketchMultipleMainFiles")
67+
sketch, err = NewSketchFromPath(sketchPath)
68+
require.Nil(t, sketch)
69+
require.Error(t, err, "multiple main sketch files found")
70+
5671
// Verifies error is returned if sketch path is not set
5772
sketch = &Sketch{}
5873
buildPath, err = sketch.BuildPath()
5974
require.Nil(t, buildPath)
6075
require.Error(t, err, "sketch path is empty")
6176
}
77+
78+
func TestCheckForPdeFiles(t *testing.T) {
79+
sketchPath := paths.New("testdata", "Sketch1")
80+
files := CheckForPdeFiles(sketchPath)
81+
require.Empty(t, files)
82+
83+
sketchPath = paths.New("testdata", "SketchPde")
84+
files = CheckForPdeFiles(sketchPath)
85+
require.Len(t, files, 1)
86+
require.Equal(t, sketchPath.Join("SketchPde.pde"), files[0])
87+
88+
sketchPath = paths.New("testdata", "SketchMultipleMainFiles")
89+
files = CheckForPdeFiles(sketchPath)
90+
require.Len(t, files, 1)
91+
require.Equal(t, sketchPath.Join("SketchMultipleMainFiles.pde"), files[0])
92+
93+
sketchPath = paths.New("testdata", "Sketch1", "Sketch1.ino")
94+
files = CheckForPdeFiles(sketchPath)
95+
require.Empty(t, files)
96+
97+
sketchPath = paths.New("testdata", "SketchPde", "SketchPde.pde")
98+
files = CheckForPdeFiles(sketchPath)
99+
require.Len(t, files, 1)
100+
require.Equal(t, sketchPath.Parent().Join("SketchPde.pde"), files[0])
101+
102+
sketchPath = paths.New("testdata", "SketchMultipleMainFiles", "SketchMultipleMainFiles.ino")
103+
files = CheckForPdeFiles(sketchPath)
104+
require.Len(t, files, 1)
105+
require.Equal(t, sketchPath.Parent().Join("SketchMultipleMainFiles.pde"), files[0])
106+
107+
sketchPath = paths.New("testdata", "SketchMultipleMainFiles", "SketchMultipleMainFiles.pde")
108+
files = CheckForPdeFiles(sketchPath)
109+
require.Len(t, files, 1)
110+
require.Equal(t, sketchPath.Parent().Join("SketchMultipleMainFiles.pde"), files[0])
111+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
void setup() {}
3+
void loop() {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
void setup() {}
3+
void loop() {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
void setup() {}
3+
void loop() {}

‎cli/compile/compile.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"encoding/json"
2222
"os"
2323

24+
"github.com/arduino/arduino-cli/arduino/sketches"
2425
"github.com/arduino/arduino-cli/cli/feedback"
2526
"github.com/arduino/arduino-cli/cli/output"
2627
"github.com/arduino/arduino-cli/configuration"
@@ -127,6 +128,15 @@ func run(cmd *cobra.Command, args []string) {
127128
}
128129

129130
sketchPath := initSketchPath(path)
131+
132+
// .pde files are still supported but deprecated, this warning urges the user to rename them
133+
if files := sketches.CheckForPdeFiles(sketchPath); len(files) > 0 {
134+
feedback.Error("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
135+
for _, f := range files {
136+
feedback.Error(f)
137+
}
138+
}
139+
130140
// We must read this from settings since the value is set when the binding is accessed from viper,
131141
// accessing it from cobra would only read it if the flag is explicitly set by the user and ignore
132142
// the config file and the env vars.

‎cli/sketch/archive.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ import (
1919
"context"
2020
"os"
2121

22+
"github.com/arduino/arduino-cli/arduino/sketches"
2223
"github.com/arduino/arduino-cli/cli/errorcodes"
2324
"github.com/arduino/arduino-cli/cli/feedback"
2425
"github.com/arduino/arduino-cli/commands/sketch"
2526
rpc "github.com/arduino/arduino-cli/rpc/commands"
27+
"github.com/arduino/go-paths-helper"
2628
"github.com/sirupsen/logrus"
2729
"github.com/spf13/cobra"
2830
)
@@ -53,11 +55,19 @@ func initArchiveCommand() *cobra.Command {
5355
func runArchiveCommand(cmd *cobra.Command, args []string) {
5456
logrus.Info("Executing `arduino sketch archive`")
5557

56-
sketchPath := ""
58+
sketchPath := "."
5759
if len(args) >= 1 {
5860
sketchPath = args[0]
5961
}
6062

63+
// .pde files are still supported but deprecated, this warning urges the user to rename them
64+
if files := sketches.CheckForPdeFiles(paths.New(sketchPath)); len(files) > 0 {
65+
feedback.Error("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
66+
for _, f := range files {
67+
feedback.Error(f)
68+
}
69+
}
70+
6171
archivePath := ""
6272
if len(args) == 2 {
6373
archivePath = args[1]

‎cli/upload/upload.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"context"
2020
"os"
2121

22+
"github.com/arduino/arduino-cli/arduino/sketches"
2223
"github.com/arduino/arduino-cli/cli/errorcodes"
2324
"github.com/arduino/arduino-cli/cli/feedback"
2425
"github.com/arduino/arduino-cli/cli/instance"
@@ -83,6 +84,14 @@ func run(command *cobra.Command, args []string) {
8384
}
8485
sketchPath := initSketchPath(path)
8586

87+
// .pde files are still supported but deprecated, this warning urges the user to rename them
88+
if files := sketches.CheckForPdeFiles(sketchPath); len(files) > 0 {
89+
feedback.Error("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
90+
for _, f := range files {
91+
feedback.Error(f)
92+
}
93+
}
94+
8695
if _, err := upload.Upload(context.Background(), &rpc.UploadReq{
8796
Instance: instance,
8897
Fqbn: fqbn,

‎commands/sketch/archive.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"path/filepath"
2424
"strings"
2525

26+
"github.com/arduino/arduino-cli/arduino/sketches"
2627
rpc "github.com/arduino/arduino-cli/rpc/commands"
2728
paths "github.com/arduino/go-paths-helper"
2829
)
@@ -37,27 +38,17 @@ func ArchiveSketch(ctx context.Context, req *rpc.ArchiveSketchReq) (*rpc.Archive
3738
sketchPath = paths.New(".")
3839
}
3940

40-
sketchPath, err := sketchPath.Clean().Abs()
41+
sketch, err := sketches.NewSketchFromPath(sketchPath)
4142
if err != nil {
42-
return nil, fmt.Errorf("Error getting absolute sketch path %v", err)
43+
return nil, err
4344
}
4445

45-
// Get the sketch name and make sketchPath point to the ino file
46-
if sketchPath.IsDir() {
47-
sketchName = sketchPath.Base()
48-
sketchPath = sketchPath.Join(sketchName + ".ino")
49-
} else if sketchPath.Ext() == ".ino" {
50-
sketchName = strings.TrimSuffix(sketchPath.Base(), ".ino")
51-
}
52-
53-
// Checks if it's really a sketch
54-
if sketchPath.NotExist() {
55-
return nil, fmt.Errorf("specified path is not a sketch: %v", sketchPath.String())
56-
}
46+
sketchPath = sketch.FullPath
47+
sketchName = sketch.Name
5748

5849
archivePath := paths.New(req.ArchivePath)
5950
if archivePath == nil {
60-
archivePath = sketchPath.Parent().Parent()
51+
archivePath = sketchPath.Parent()
6152
}
6253

6354
archivePath, err = archivePath.Clean().Abs()
@@ -76,7 +67,7 @@ func ArchiveSketch(ctx context.Context, req *rpc.ArchiveSketchReq) (*rpc.Archive
7667
return nil, fmt.Errorf("archive already exists")
7768
}
7869

79-
filesToZip, err := sketchPath.Parent().ReadDirRecursive()
70+
filesToZip, err := sketchPath.ReadDirRecursive()
8071
if err != nil {
8172
return nil, fmt.Errorf("Error retrieving sketch files: %v", err)
8273
}
@@ -94,7 +85,7 @@ func ArchiveSketch(ctx context.Context, req *rpc.ArchiveSketchReq) (*rpc.Archive
9485
for _, f := range filesToZip {
9586

9687
if !req.IncludeBuildDir {
97-
filePath, err := sketchPath.Parent().Parent().RelTo(f)
88+
filePath, err := sketchPath.Parent().RelTo(f)
9889
if err != nil {
9990
return nil, fmt.Errorf("Error calculating relative file path: %v", err)
10091
}
@@ -107,7 +98,7 @@ func ArchiveSketch(ctx context.Context, req *rpc.ArchiveSketchReq) (*rpc.Archive
10798

10899
// We get the parent path since we want the archive to unpack as a folder.
109100
// If we don't do this the archive would contain all the sketch files as top level.
110-
err = addFileToSketchArchive(zipWriter, f, sketchPath.Parent().Parent())
101+
err = addFileToSketchArchive(zipWriter, f, sketchPath.Parent())
111102
if err != nil {
112103
return nil, fmt.Errorf("Error adding file to archive: %v", err)
113104
}

‎commands/upload/upload.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
bldr "github.com/arduino/arduino-cli/arduino/builder"
2727
"github.com/arduino/arduino-cli/arduino/cores"
2828
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
29+
"github.com/arduino/arduino-cli/arduino/globals"
2930
"github.com/arduino/arduino-cli/arduino/serialutils"
3031
"github.com/arduino/arduino-cli/arduino/sketches"
3132
"github.com/arduino/arduino-cli/commands"
@@ -452,7 +453,7 @@ func determineBuildPathAndSketchName(importFile, importDir string, sketch *sketc
452453

453454
// Case 4: only sketch specified. In this case we use the generated build path
454455
// and the given sketch name.
455-
return bldr.GenBuildPath(sketch.FullPath), sketch.Name + ".ino", nil
456+
return bldr.GenBuildPath(sketch.FullPath), sketch.Name + sketch.MainFileExtension, nil
456457
}
457458

458459
func detectSketchNameFromBuildPath(buildPath *paths.Path) (string, error) {
@@ -462,11 +463,13 @@ func detectSketchNameFromBuildPath(buildPath *paths.Path) (string, error) {
462463
}
463464

464465
if absBuildPath, err := buildPath.Abs(); err == nil {
465-
candidateName := absBuildPath.Base() + ".ino"
466-
f := files.Clone()
467-
f.FilterPrefix(candidateName + ".")
468-
if f.Len() > 0 {
469-
return candidateName, nil
466+
for ext := range globals.MainFileValidExtensions {
467+
candidateName := absBuildPath.Base() + ext
468+
f := files.Clone()
469+
f.FilterPrefix(candidateName + ".")
470+
if f.Len() > 0 {
471+
return candidateName, nil
472+
}
470473
}
471474
}
472475

@@ -479,7 +482,7 @@ func detectSketchNameFromBuildPath(buildPath *paths.Path) (string, error) {
479482

480483
// Sometimes we may have particular files like:
481484
// Blink.ino.with_bootloader.bin
482-
if filepath.Ext(name) != ".ino" {
485+
if _, ok := globals.MainFileValidExtensions[filepath.Ext(name)]; !ok {
483486
// just ignore those files
484487
continue
485488
}

‎docs/sketch-specification.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ Support for sketch folder names starting with a number was added in Arduino IDE
1818

1919
### Primary sketch file
2020

21-
Every sketch must contain a .ino or .pde file with a file name matching the sketch root folder name.
21+
Every sketch must contain a `.ino` file with a file name matching the sketch root folder name.
22+
23+
`.pde` is also supported but **deprecated** and will be removed in the future, using the `.ino` extension is strongly
24+
recommended.
2225

2326
### Additional code files
2427

@@ -28,7 +31,7 @@ The following extensions are supported:
2831

2932
- .ino - [Arduino language](https://www.arduino.cc/reference/en/) files.
3033
- .pde - Alternate extension for Arduino language files. This file extension is also used by Processing sketches. .ino
31-
is recommended to avoid confusion.
34+
is recommended to avoid confusion. **`.pde` extension is deprecated and will be removed in the future.**
3235
- .cpp - C++ files.
3336
- .c - C Files.
3437
- .S - Assembly language files.

‎test/test_compile.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import platform
1717
import tempfile
1818
import hashlib
19+
import shutil
1920
from pathlib import Path
2021
import simplejson as json
2122

@@ -629,3 +630,68 @@ def test_compile_with_fully_precompiled_library(run_command, data_dir):
629630
result = run_command(f"compile -b {fqbn} {sketch_folder} -v")
630631
assert result.ok
631632
assert "Skipping dependencies detection for precompiled library Arduino_TensorFlowLite" in result.stdout
633+
634+
635+
def test_compile_sketch_with_pde_extension(run_command, data_dir):
636+
# Init the environment explicitly
637+
assert run_command("update")
638+
639+
# Install core to compile
640+
assert run_command("core install arduino:avr@1.8.3")
641+
642+
sketch_name = "CompilePdeSketch"
643+
sketch_path = Path(data_dir, sketch_name)
644+
fqbn = "arduino:avr:uno"
645+
646+
# Create a test sketch
647+
assert run_command(f"sketch new {sketch_path}")
648+
649+
# Renames sketch file to pde
650+
sketch_file = Path(sketch_path, f"{sketch_name}.ino").rename(sketch_path / f"{sketch_name}.pde")
651+
652+
# Build sketch from folder
653+
res = run_command(f"compile --clean -b {fqbn} {sketch_path}")
654+
assert res.ok
655+
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino:" in res.stderr
656+
assert str(sketch_file) in res.stderr
657+
658+
# Build sketch from file
659+
res = run_command(f"compile --clean -b {fqbn} {sketch_file}")
660+
assert res.ok
661+
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
662+
assert str(sketch_file) in res.stderr
663+
664+
665+
def test_compile_sketch_with_multiple_main_files(run_command, data_dir):
666+
# Init the environment explicitly
667+
assert run_command("update")
668+
669+
# Install core to compile
670+
assert run_command("core install arduino:avr@1.8.3")
671+
672+
sketch_name = "CompileSketchMultipleMainFiles"
673+
sketch_path = Path(data_dir, sketch_name)
674+
fqbn = "arduino:avr:uno"
675+
676+
# Create a test sketch
677+
assert run_command(f"sketch new {sketch_path}")
678+
679+
# Copy .ino sketch file to .pde
680+
sketch_ino_file = Path(sketch_path, f"{sketch_name}.ino")
681+
sketch_pde_file = Path(sketch_path / f"{sketch_name}.pde")
682+
shutil.copyfile(sketch_ino_file, sketch_pde_file)
683+
684+
# Build sketch from folder
685+
res = run_command(f"compile --clean -b {fqbn} {sketch_path}")
686+
assert res.failed
687+
assert "Error during build: opening sketch: multiple main sketch files found" in res.stderr
688+
689+
# Build sketch from .ino file
690+
res = run_command(f"compile --clean -b {fqbn} {sketch_ino_file}")
691+
assert res.failed
692+
assert "Error during build: opening sketch: multiple main sketch files found" in res.stderr
693+
694+
# Build sketch from .pde file
695+
res = run_command(f"compile --clean -b {fqbn} {sketch_pde_file}")
696+
assert res.failed
697+
assert "Error during build: opening sketch: multiple main sketch files found" in res.stderr

‎test/test_debug.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,27 @@ def test_debugger_starts(run_command, data_dir):
3737
programmer = "atmel_ice"
3838
# Starts debugger
3939
assert run_command(f"debug -b {fqbn} -P {programmer} {sketch_path} --info")
40+
41+
42+
def test_debugger_with_pde_sketch_starts(run_command, data_dir):
43+
assert run_command("update")
44+
45+
# Install core
46+
assert run_command("core install arduino:samd")
47+
48+
# Create sketch for testing
49+
sketch_name = "DebuggerPdeSketchStartTest"
50+
sketch_path = Path(data_dir, sketch_name)
51+
fqbn = "arduino:samd:mkr1000"
52+
53+
assert run_command(f"sketch new {sketch_path}")
54+
55+
# Renames sketch file to pde
56+
Path(sketch_path, f"{sketch_name}.ino").rename(sketch_path / f"{sketch_name}.pde")
57+
58+
# Build sketch
59+
assert run_command(f"compile -b {fqbn} {sketch_path}")
60+
61+
programmer = "atmel_ice"
62+
# Starts debugger
63+
assert run_command(f"debug -b {fqbn} -P {programmer} {sketch_path} --info")

‎test/test_lib.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,36 @@ def test_install_with_zip_path_multiple_libraries(run_command, downloads_dir, da
635635
# Verifies library are installed
636636
assert wifi_install_dir.exists()
637637
assert ble_install_dir.exists()
638+
639+
640+
def test_lib_examples(run_command, data_dir):
641+
assert run_command("update")
642+
643+
assert run_command("lib install Arduino_JSON@0.1.0")
644+
645+
res = run_command("lib examples Arduino_JSON --format json")
646+
assert res.ok
647+
data = json.loads(res.stdout)
648+
assert len(data) == 1
649+
examples = data[0]["examples"]
650+
651+
assert str(Path(data_dir, "libraries", "Arduino_JSON", "examples", "JSONArray")) in examples
652+
assert str(Path(data_dir, "libraries", "Arduino_JSON", "examples", "JSONKitchenSink")) in examples
653+
assert str(Path(data_dir, "libraries", "Arduino_JSON", "examples", "JSONObject")) in examples
654+
655+
656+
def test_lib_examples_with_pde_file(run_command, data_dir):
657+
assert run_command("update")
658+
659+
assert run_command("lib install Encoder@1.4.1")
660+
661+
res = run_command("lib examples Encoder --format json")
662+
assert res.ok
663+
data = json.loads(res.stdout)
664+
assert len(data) == 1
665+
examples = data[0]["examples"]
666+
667+
assert str(Path(data_dir, "libraries", "Encoder", "examples", "Basic")) in examples
668+
assert str(Path(data_dir, "libraries", "Encoder", "examples", "NoInterrupts")) in examples
669+
assert str(Path(data_dir, "libraries", "Encoder", "examples", "SpeedTest")) in examples
670+
assert str(Path(data_dir, "libraries", "Encoder", "examples", "TwoKnobs")) in examples

‎test/test_sketch.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,3 +818,31 @@ def test_sketch_archive_absolute_sketch_path_with_absolute_zip_path_and_name_wit
818818
verify_zip_contains_sketch_including_build_dir(archive_files)
819819

820820
archive.close()
821+
822+
823+
def test_sketch_archive_with_pde_main_file(run_command, copy_sketch, working_dir):
824+
sketch_name = "sketch_pde_main_file"
825+
sketch_dir = copy_sketch(sketch_name)
826+
sketch_file = Path(sketch_dir, f"{sketch_name}.pde")
827+
res = run_command("sketch archive", sketch_dir)
828+
assert res.ok
829+
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
830+
assert str(sketch_file.relative_to(sketch_dir)) in res.stderr
831+
832+
archive = zipfile.ZipFile(f"{working_dir}/{sketch_name}.zip")
833+
archive_files = archive.namelist()
834+
835+
assert f"{sketch_name}/{sketch_name}.pde" in archive_files
836+
837+
archive.close()
838+
839+
840+
def test_sketch_archive_with_multiple_main_files(run_command, copy_sketch, working_dir):
841+
sketch_name = "sketch_multiple_main_files"
842+
sketch_dir = copy_sketch(sketch_name)
843+
sketch_file = Path(sketch_dir, f"{sketch_name}.pde")
844+
res = run_command("sketch archive", sketch_dir)
845+
assert res.failed
846+
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
847+
assert str(sketch_file.relative_to(sketch_dir)) in res.stderr
848+
assert "Error archiving: multiple main sketch files found" in res.stderr

‎test/test_upload.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# software without disclosing the source code of your own applications. To purchase
1414
# a commercial license, send an email to license@arduino.cc.
1515
import os
16+
import shutil
17+
import json
1618
from pathlib import Path
1719

1820
import pytest
@@ -195,3 +197,143 @@ def test_compile_and_upload_combo_with_custom_build_path(run_command, data_dir,
195197
assert f"Compile {sketch_name} for {board.fqbn} successful" in traces
196198
assert f"Upload {sketch_path} on {board.fqbn} started" in traces
197199
assert "Upload successful" in traces
200+
201+
202+
def test_compile_and_upload_combo_sketch_with_pde_extension(run_command, data_dir, detected_boards, wait_for_board):
203+
assert run_command("update")
204+
205+
sketch_name = "CompileAndUploadPdeSketch"
206+
sketch_path = Path(data_dir, sketch_name)
207+
208+
# Create a test sketch
209+
assert run_command(f"sketch new {sketch_path}")
210+
211+
# Renames sketch file to pde
212+
sketch_file = Path(sketch_path, f"{sketch_name}.ino").rename(sketch_path / f"{sketch_name}.pde")
213+
214+
for board in detected_boards:
215+
# Install core
216+
core = ":".join(board.fqbn.split(":")[:2])
217+
assert run_command(f"core install {core}")
218+
219+
# Build sketch and upload from folder
220+
wait_for_board()
221+
res = run_command(f"compile --clean -b {board.fqbn} -u -p {board.address} {sketch_path}")
222+
assert res.ok
223+
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
224+
assert str(sketch_file) in res.stderr
225+
226+
# Build sketch and upload from file
227+
wait_for_board()
228+
res = run_command(f"compile --clean -b {board.fqbn} -u -p {board.address} {sketch_file}")
229+
assert res.ok
230+
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
231+
assert str(sketch_file) in res.stderr
232+
233+
234+
def test_upload_sketch_with_pde_extension(run_command, data_dir, detected_boards, wait_for_board):
235+
assert run_command("update")
236+
237+
sketch_name = "UploadPdeSketch"
238+
sketch_path = Path(data_dir, sketch_name)
239+
240+
# Create a test sketch
241+
assert run_command(f"sketch new {sketch_path}")
242+
243+
# Renames sketch file to pde
244+
sketch_file = Path(sketch_path, f"{sketch_name}.ino").rename(sketch_path / f"{sketch_name}.pde")
245+
246+
for board in detected_boards:
247+
# Install core
248+
core = ":".join(board.fqbn.split(":")[:2])
249+
assert run_command(f"core install {core}")
250+
251+
# Compile sketch first
252+
res = run_command(f"compile --clean -b {board.fqbn} {sketch_path} --format json")
253+
assert res.ok
254+
data = json.loads(res.stdout)
255+
build_dir = Path(data["builder_result"]["build_path"])
256+
257+
# Upload from sketch folder
258+
wait_for_board()
259+
assert run_command(f"upload -b {board.fqbn} -p {board.address} {sketch_path}")
260+
261+
# Upload from sketch file
262+
wait_for_board()
263+
assert run_command(f"upload -b {board.fqbn} -p {board.address} {sketch_file}")
264+
265+
wait_for_board()
266+
res = run_command(f"upload -b {board.fqbn} -p {board.address} --input-dir {build_dir}")
267+
assert (
268+
"Sketches with .pde extension are deprecated, please rename the following files to .ino:" not in res.stderr
269+
)
270+
271+
# Upload from binary file
272+
wait_for_board()
273+
# We don't need a specific file when using the --input-file flag to upload since
274+
# it's just used to calculate the directory, so it's enough to get a random file
275+
# that's inside that directory
276+
binary_file = next(build_dir.glob(f"{sketch_name}.pde.*"))
277+
res = run_command(f"upload -b {board.fqbn} -p {board.address} --input-file {binary_file}")
278+
assert (
279+
"Sketches with .pde extension are deprecated, please rename the following files to .ino:" not in res.stderr
280+
)
281+
282+
283+
def test_upload_with_input_dir_containing_multiple_binaries(run_command, data_dir, detected_boards, wait_for_board):
284+
# This tests verifies the behaviour outlined in this issue:
285+
# https://github.com/arduino/arduino-cli/issues/765#issuecomment-699678646
286+
assert run_command("update")
287+
288+
# Create a two different sketches
289+
sketch_one_name = "UploadMultipleBinariesSketchOne"
290+
sketch_one_path = Path(data_dir, sketch_one_name)
291+
assert run_command(f"sketch new {sketch_one_path}")
292+
293+
sketch_two_name = "UploadMultipleBinariesSketchTwo"
294+
sketch_two_path = Path(data_dir, sketch_two_name)
295+
assert run_command(f"sketch new {sketch_two_path}")
296+
297+
for board in detected_boards:
298+
# Install core
299+
core = ":".join(board.fqbn.split(":")[:2])
300+
assert run_command(f"core install {core}")
301+
302+
# Compile both sketches and copy binaries in the same directory same build directory
303+
res = run_command(f"compile --clean -b {board.fqbn} {sketch_one_path} --format json")
304+
assert res.ok
305+
data = json.loads(res.stdout)
306+
build_dir_one = Path(data["builder_result"]["build_path"])
307+
res = run_command(f"compile --clean -b {board.fqbn} {sketch_two_path} --format json")
308+
assert res.ok
309+
data = json.loads(res.stdout)
310+
build_dir_two = Path(data["builder_result"]["build_path"])
311+
312+
# Copy binaries to same folder
313+
binaries_dir = Path(data_dir, "build", "BuiltBinaries")
314+
shutil.copytree(build_dir_one, binaries_dir, dirs_exist_ok=True)
315+
shutil.copytree(build_dir_two, binaries_dir, dirs_exist_ok=True)
316+
317+
wait_for_board()
318+
# Verifies upload fails because multiple binaries are found
319+
res = run_command(f"upload -b {board.fqbn} -p {board.address} --input-dir {binaries_dir}")
320+
assert res.failed
321+
assert (
322+
"Error during Upload: "
323+
+ "retrieving build artifacts: "
324+
+ "autodetect build artifact: "
325+
+ "multiple build artifacts found:"
326+
in res.stderr
327+
)
328+
329+
# Copy binaries to folder with same name of a sketch
330+
binaries_dir = Path(data_dir, "build", "UploadMultipleBinariesSketchOne")
331+
shutil.copytree(build_dir_one, binaries_dir, dirs_exist_ok=True)
332+
shutil.copytree(build_dir_two, binaries_dir, dirs_exist_ok=True)
333+
334+
wait_for_board()
335+
# Verifies upload is successful using the binaries with the same name of the containing folder
336+
res = run_command(f"upload -b {board.fqbn} -p {board.address} --input-dir {binaries_dir}")
337+
assert (
338+
"Sketches with .pde extension are deprecated, please rename the following files to .ino:" not in res.stderr
339+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void setup() { }
2+
3+
void loop() { }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void setup() { }
2+
3+
void loop() { }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void setup() { }
2+
3+
void loop() { }

0 commit comments

Comments
 (0)
Please sign in to comment.