Skip to content

Add back support for sketches with .pde extension and deprecate it #1157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 29, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion arduino/globals/globals.go
Original file line number Diff line number Diff line change
@@ -18,9 +18,13 @@ package globals
var (
empty struct{}

// MainFileValidExtension is the extension that must be used for files in new sketches
MainFileValidExtension string = ".ino"

// MainFileValidExtensions lists valid extensions for a sketch file
MainFileValidExtensions = map[string]struct{}{
".ino": empty,
MainFileValidExtension: empty,
// .pde extension is deprecated and must not be used for new sketches
".pde": empty,
}

10 changes: 3 additions & 7 deletions arduino/libraries/loader.go
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ import (
"fmt"
"strings"

"github.com/arduino/arduino-cli/arduino/sketches"
"github.com/arduino/go-paths-helper"
properties "github.com/arduino/go-properties-orderedmap"
"github.com/pkg/errors"
@@ -172,7 +173,8 @@ func addExamplesToPathList(examplesPath *paths.Path, list *paths.PathList) error
return err
}
for _, file := range files {
if isExample(file) {
_, err := sketches.NewSketchFromPath(file)
if err == nil {
list.Add(file)
} else if file.IsDir() {
if err := addExamplesToPathList(file, list); err != nil {
@@ -182,9 +184,3 @@ func addExamplesToPathList(examplesPath *paths.Path, list *paths.PathList) error
}
return nil
}

// isExample returns true if examplePath contains an example
func isExample(examplePath *paths.Path) bool {
mainIno := examplePath.Join(examplePath.Base() + ".ino")
return mainIno.Exist() && mainIno.IsNotDir()
}
55 changes: 46 additions & 9 deletions arduino/sketches/sketches.go
Original file line number Diff line number Diff line change
@@ -20,15 +20,17 @@ import (
"fmt"

"github.com/arduino/arduino-cli/arduino/builder"
"github.com/arduino/arduino-cli/arduino/globals"
"github.com/arduino/go-paths-helper"
"github.com/pkg/errors"
)

// Sketch is a sketch for Arduino
type Sketch struct {
Name string
FullPath *paths.Path
Metadata *Metadata
Name string
MainFileExtension string
FullPath *paths.Path
Metadata *Metadata
}

// 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) {
if !path.IsDir() {
path = path.Parent()
}
sketchFile := path.Join(path.Base() + ".ino")
if !sketchFile.Exist() {
return nil, errors.Errorf("no valid sketch found in %s: missing %s", path, sketchFile.Base())

var mainSketchFile *paths.Path
for ext := range globals.MainFileValidExtensions {
candidateSketchMainFile := path.Join(path.Base() + ext)
if candidateSketchMainFile.Exist() {
if mainSketchFile == nil {
mainSketchFile = candidateSketchMainFile
} else {
return nil, errors.Errorf("multiple main sketch files found (%v, %v)",
mainSketchFile,
candidateSketchMainFile,
)
}
}
}

if mainSketchFile == nil {
sketchFile := path.Join(path.Base() + globals.MainFileValidExtension)
return nil, errors.Errorf("no valid sketch found in %s: missing %s", path, sketchFile)
}

sketch := &Sketch{
FullPath: path,
Name: path.Base(),
Metadata: &Metadata{},
FullPath: path,
MainFileExtension: mainSketchFile.Ext(),
Name: path.Base(),
Metadata: &Metadata{},
}
sketch.ImportMetadata()
return sketch, nil
@@ -108,3 +128,20 @@ func (s *Sketch) BuildPath() (*paths.Path, error) {
}
return builder.GenBuildPath(s.FullPath), nil
}

// CheckForPdeFiles returns all files ending with .pde extension
// in dir, this is mainly used to warn the user that these files
// must be changed to .ino extension.
// When .pde files won't be supported anymore this function must be removed.
func CheckForPdeFiles(sketch *paths.Path) []*paths.Path {
if sketch.IsNotDir() {
sketch = sketch.Parent()
}

files, err := sketch.ReadDirRecursive()
if err != nil {
return []*paths.Path{}
}
files.FilterSuffix(".pde")
return files
}
50 changes: 50 additions & 0 deletions arduino/sketches/sketches_test.go
Original file line number Diff line number Diff line change
@@ -53,9 +53,59 @@ func TestSketchBuildPath(t *testing.T) {
require.NoError(t, err)
require.Contains(t, buildPath.String(), "arduino-sketch-")

// Verifies sketch path is returned if sketch has .pde extension
sketchPath = paths.New("testdata", "SketchPde")
sketch, err = NewSketchFromPath(sketchPath)
require.NoError(t, err)
require.NotNil(t, sketch)
buildPath, err = sketch.BuildPath()
require.NoError(t, err)
require.Contains(t, buildPath.String(), "arduino-sketch-")

// Verifies error is returned if there are multiple main files
sketchPath = paths.New("testdata", "SketchMultipleMainFiles")
sketch, err = NewSketchFromPath(sketchPath)
require.Nil(t, sketch)
require.Error(t, err, "multiple main sketch files found")

// Verifies error is returned if sketch path is not set
sketch = &Sketch{}
buildPath, err = sketch.BuildPath()
require.Nil(t, buildPath)
require.Error(t, err, "sketch path is empty")
}

func TestCheckForPdeFiles(t *testing.T) {
sketchPath := paths.New("testdata", "Sketch1")
files := CheckForPdeFiles(sketchPath)
require.Empty(t, files)

sketchPath = paths.New("testdata", "SketchPde")
files = CheckForPdeFiles(sketchPath)
require.Len(t, files, 1)
require.Equal(t, sketchPath.Join("SketchPde.pde"), files[0])

sketchPath = paths.New("testdata", "SketchMultipleMainFiles")
files = CheckForPdeFiles(sketchPath)
require.Len(t, files, 1)
require.Equal(t, sketchPath.Join("SketchMultipleMainFiles.pde"), files[0])

sketchPath = paths.New("testdata", "Sketch1", "Sketch1.ino")
files = CheckForPdeFiles(sketchPath)
require.Empty(t, files)

sketchPath = paths.New("testdata", "SketchPde", "SketchPde.pde")
files = CheckForPdeFiles(sketchPath)
require.Len(t, files, 1)
require.Equal(t, sketchPath.Parent().Join("SketchPde.pde"), files[0])

sketchPath = paths.New("testdata", "SketchMultipleMainFiles", "SketchMultipleMainFiles.ino")
files = CheckForPdeFiles(sketchPath)
require.Len(t, files, 1)
require.Equal(t, sketchPath.Parent().Join("SketchMultipleMainFiles.pde"), files[0])

sketchPath = paths.New("testdata", "SketchMultipleMainFiles", "SketchMultipleMainFiles.pde")
files = CheckForPdeFiles(sketchPath)
require.Len(t, files, 1)
require.Equal(t, sketchPath.Parent().Join("SketchMultipleMainFiles.pde"), files[0])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

void setup() {}
void loop() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

void setup() {}
void loop() {}
3 changes: 3 additions & 0 deletions arduino/sketches/testdata/SketchPde/SketchPde.pde
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

void setup() {}
void loop() {}
10 changes: 10 additions & 0 deletions cli/compile/compile.go
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ import (
"encoding/json"
"os"

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

sketchPath := initSketchPath(path)

// .pde files are still supported but deprecated, this warning urges the user to rename them
if files := sketches.CheckForPdeFiles(sketchPath); len(files) > 0 {
feedback.Error("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
for _, f := range files {
feedback.Error(f)
}
}

Comment on lines 130 to +139
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This piece is duplicated in compile.go, upload.go and archive.go.
On compile.go and upload.go there is also initSketchPath() that is duplicated as well.
This makes me wonder two things:

  • in archive.go we are missing some cases because we miss an initSketchPath(...)
  • we must move everything (the current initSketchPath and the pde check) into a common function args.InitSketchParh(path) or something like that...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably something that we need to tackle in a systematic way and not in this PR or it would make it explode.

// We must read this from settings since the value is set when the binding is accessed from viper,
// accessing it from cobra would only read it if the flag is explicitly set by the user and ignore
// the config file and the env vars.
12 changes: 11 additions & 1 deletion cli/sketch/archive.go
Original file line number Diff line number Diff line change
@@ -19,10 +19,12 @@ import (
"context"
"os"

"github.com/arduino/arduino-cli/arduino/sketches"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/commands/sketch"
rpc "github.com/arduino/arduino-cli/rpc/commands"
"github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -53,11 +55,19 @@ func initArchiveCommand() *cobra.Command {
func runArchiveCommand(cmd *cobra.Command, args []string) {
logrus.Info("Executing `arduino sketch archive`")

sketchPath := ""
sketchPath := "."
if len(args) >= 1 {
sketchPath = args[0]
}

// .pde files are still supported but deprecated, this warning urges the user to rename them
if files := sketches.CheckForPdeFiles(paths.New(sketchPath)); len(files) > 0 {
feedback.Error("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
for _, f := range files {
feedback.Error(f)
}
}

archivePath := ""
if len(args) == 2 {
archivePath = args[1]
9 changes: 9 additions & 0 deletions cli/upload/upload.go
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ import (
"context"
"os"

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

// .pde files are still supported but deprecated, this warning urges the user to rename them
if files := sketches.CheckForPdeFiles(sketchPath); len(files) > 0 {
feedback.Error("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
for _, f := range files {
feedback.Error(f)
}
}

if _, err := upload.Upload(context.Background(), &rpc.UploadReq{
Instance: instance,
Fqbn: fqbn,
27 changes: 9 additions & 18 deletions commands/sketch/archive.go
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ import (
"path/filepath"
"strings"

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

sketchPath, err := sketchPath.Clean().Abs()
sketch, err := sketches.NewSketchFromPath(sketchPath)
if err != nil {
return nil, fmt.Errorf("Error getting absolute sketch path %v", err)
return nil, err
}

// Get the sketch name and make sketchPath point to the ino file
if sketchPath.IsDir() {
sketchName = sketchPath.Base()
sketchPath = sketchPath.Join(sketchName + ".ino")
} else if sketchPath.Ext() == ".ino" {
sketchName = strings.TrimSuffix(sketchPath.Base(), ".ino")
}

// Checks if it's really a sketch
if sketchPath.NotExist() {
return nil, fmt.Errorf("specified path is not a sketch: %v", sketchPath.String())
}
sketchPath = sketch.FullPath
sketchName = sketch.Name

archivePath := paths.New(req.ArchivePath)
if archivePath == nil {
archivePath = sketchPath.Parent().Parent()
archivePath = sketchPath.Parent()
}

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

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

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

// We get the parent path since we want the archive to unpack as a folder.
// If we don't do this the archive would contain all the sketch files as top level.
err = addFileToSketchArchive(zipWriter, f, sketchPath.Parent().Parent())
err = addFileToSketchArchive(zipWriter, f, sketchPath.Parent())
if err != nil {
return nil, fmt.Errorf("Error adding file to archive: %v", err)
}
17 changes: 10 additions & 7 deletions commands/upload/upload.go
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ import (
bldr "github.com/arduino/arduino-cli/arduino/builder"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/arduino/globals"
"github.com/arduino/arduino-cli/arduino/serialutils"
"github.com/arduino/arduino-cli/arduino/sketches"
"github.com/arduino/arduino-cli/commands"
@@ -452,7 +453,7 @@ func determineBuildPathAndSketchName(importFile, importDir string, sketch *sketc

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

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

if absBuildPath, err := buildPath.Abs(); err == nil {
candidateName := absBuildPath.Base() + ".ino"
f := files.Clone()
f.FilterPrefix(candidateName + ".")
if f.Len() > 0 {
return candidateName, nil
for ext := range globals.MainFileValidExtensions {
candidateName := absBuildPath.Base() + ext
f := files.Clone()
f.FilterPrefix(candidateName + ".")
if f.Len() > 0 {
return candidateName, nil
}
}
}

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

// Sometimes we may have particular files like:
// Blink.ino.with_bootloader.bin
if filepath.Ext(name) != ".ino" {
if _, ok := globals.MainFileValidExtensions[filepath.Ext(name)]; !ok {
// just ignore those files
continue
}
7 changes: 5 additions & 2 deletions docs/sketch-specification.md
Original file line number Diff line number Diff line change
@@ -18,7 +18,10 @@ Support for sketch folder names starting with a number was added in Arduino IDE

### Primary sketch file

Every sketch must contain a .ino or .pde file with a file name matching the sketch root folder name.
Every sketch must contain a `.ino` file with a file name matching the sketch root folder name.

`.pde` is also supported but **deprecated** and will be removed in the future, using the `.ino` extension is strongly
recommended.

### Additional code files

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

- .ino - [Arduino language](https://www.arduino.cc/reference/en/) files.
- .pde - Alternate extension for Arduino language files. This file extension is also used by Processing sketches. .ino
is recommended to avoid confusion.
is recommended to avoid confusion. **`.pde` extension is deprecated and will be removed in the future.**
- .cpp - C++ files.
- .c - C Files.
- .S - Assembly language files.
66 changes: 66 additions & 0 deletions test/test_compile.py
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
import platform
import tempfile
import hashlib
import shutil
from pathlib import Path
import simplejson as json

@@ -629,3 +630,68 @@ def test_compile_with_fully_precompiled_library(run_command, data_dir):
result = run_command(f"compile -b {fqbn} {sketch_folder} -v")
assert result.ok
assert "Skipping dependencies detection for precompiled library Arduino_TensorFlowLite" in result.stdout


def test_compile_sketch_with_pde_extension(run_command, data_dir):
# Init the environment explicitly
assert run_command("update")

# Install core to compile
assert run_command("core install arduino:avr@1.8.3")

sketch_name = "CompilePdeSketch"
sketch_path = Path(data_dir, sketch_name)
fqbn = "arduino:avr:uno"

# Create a test sketch
assert run_command(f"sketch new {sketch_path}")

# Renames sketch file to pde
sketch_file = Path(sketch_path, f"{sketch_name}.ino").rename(sketch_path / f"{sketch_name}.pde")

# Build sketch from folder
res = run_command(f"compile --clean -b {fqbn} {sketch_path}")
assert res.ok
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino:" in res.stderr
assert str(sketch_file) in res.stderr

# Build sketch from file
res = run_command(f"compile --clean -b {fqbn} {sketch_file}")
assert res.ok
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
assert str(sketch_file) in res.stderr


def test_compile_sketch_with_multiple_main_files(run_command, data_dir):
# Init the environment explicitly
assert run_command("update")

# Install core to compile
assert run_command("core install arduino:avr@1.8.3")

sketch_name = "CompileSketchMultipleMainFiles"
sketch_path = Path(data_dir, sketch_name)
fqbn = "arduino:avr:uno"

# Create a test sketch
assert run_command(f"sketch new {sketch_path}")

# Copy .ino sketch file to .pde
sketch_ino_file = Path(sketch_path, f"{sketch_name}.ino")
sketch_pde_file = Path(sketch_path / f"{sketch_name}.pde")
shutil.copyfile(sketch_ino_file, sketch_pde_file)

# Build sketch from folder
res = run_command(f"compile --clean -b {fqbn} {sketch_path}")
assert res.failed
assert "Error during build: opening sketch: multiple main sketch files found" in res.stderr

# Build sketch from .ino file
res = run_command(f"compile --clean -b {fqbn} {sketch_ino_file}")
assert res.failed
assert "Error during build: opening sketch: multiple main sketch files found" in res.stderr

# Build sketch from .pde file
res = run_command(f"compile --clean -b {fqbn} {sketch_pde_file}")
assert res.failed
assert "Error during build: opening sketch: multiple main sketch files found" in res.stderr
24 changes: 24 additions & 0 deletions test/test_debug.py
Original file line number Diff line number Diff line change
@@ -37,3 +37,27 @@ def test_debugger_starts(run_command, data_dir):
programmer = "atmel_ice"
# Starts debugger
assert run_command(f"debug -b {fqbn} -P {programmer} {sketch_path} --info")


def test_debugger_with_pde_sketch_starts(run_command, data_dir):
assert run_command("update")

# Install core
assert run_command("core install arduino:samd")

# Create sketch for testing
sketch_name = "DebuggerPdeSketchStartTest"
sketch_path = Path(data_dir, sketch_name)
fqbn = "arduino:samd:mkr1000"

assert run_command(f"sketch new {sketch_path}")

# Renames sketch file to pde
Path(sketch_path, f"{sketch_name}.ino").rename(sketch_path / f"{sketch_name}.pde")

# Build sketch
assert run_command(f"compile -b {fqbn} {sketch_path}")

programmer = "atmel_ice"
# Starts debugger
assert run_command(f"debug -b {fqbn} -P {programmer} {sketch_path} --info")
33 changes: 33 additions & 0 deletions test/test_lib.py
Original file line number Diff line number Diff line change
@@ -621,3 +621,36 @@ def test_install_with_zip_path_multiple_libraries(run_command, downloads_dir, da
# Verifies library are installed
assert wifi_install_dir.exists()
assert ble_install_dir.exists()


def test_lib_examples(run_command, data_dir):
assert run_command("update")

assert run_command("lib install Arduino_JSON@0.1.0")

res = run_command("lib examples Arduino_JSON --format json")
assert res.ok
data = json.loads(res.stdout)
assert len(data) == 1
examples = data[0]["examples"]

assert str(Path(data_dir, "libraries", "Arduino_JSON", "examples", "JSONArray")) in examples
assert str(Path(data_dir, "libraries", "Arduino_JSON", "examples", "JSONKitchenSink")) in examples
assert str(Path(data_dir, "libraries", "Arduino_JSON", "examples", "JSONObject")) in examples


def test_lib_examples_with_pde_file(run_command, data_dir):
assert run_command("update")

assert run_command("lib install Encoder@1.4.1")

res = run_command("lib examples Encoder --format json")
assert res.ok
data = json.loads(res.stdout)
assert len(data) == 1
examples = data[0]["examples"]

assert str(Path(data_dir, "libraries", "Encoder", "examples", "Basic")) in examples
assert str(Path(data_dir, "libraries", "Encoder", "examples", "NoInterrupts")) in examples
assert str(Path(data_dir, "libraries", "Encoder", "examples", "SpeedTest")) in examples
assert str(Path(data_dir, "libraries", "Encoder", "examples", "TwoKnobs")) in examples
28 changes: 28 additions & 0 deletions test/test_sketch.py
Original file line number Diff line number Diff line change
@@ -818,3 +818,31 @@ def test_sketch_archive_absolute_sketch_path_with_absolute_zip_path_and_name_wit
verify_zip_contains_sketch_including_build_dir(archive_files)

archive.close()


def test_sketch_archive_with_pde_main_file(run_command, copy_sketch, working_dir):
sketch_name = "sketch_pde_main_file"
sketch_dir = copy_sketch(sketch_name)
sketch_file = Path(sketch_dir, f"{sketch_name}.pde")
res = run_command("sketch archive", sketch_dir)
assert res.ok
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
assert str(sketch_file.relative_to(sketch_dir)) in res.stderr

archive = zipfile.ZipFile(f"{working_dir}/{sketch_name}.zip")
archive_files = archive.namelist()

assert f"{sketch_name}/{sketch_name}.pde" in archive_files

archive.close()


def test_sketch_archive_with_multiple_main_files(run_command, copy_sketch, working_dir):
sketch_name = "sketch_multiple_main_files"
sketch_dir = copy_sketch(sketch_name)
sketch_file = Path(sketch_dir, f"{sketch_name}.pde")
res = run_command("sketch archive", sketch_dir)
assert res.failed
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
assert str(sketch_file.relative_to(sketch_dir)) in res.stderr
assert "Error archiving: multiple main sketch files found" in res.stderr
142 changes: 142 additions & 0 deletions test/test_upload.py
Original file line number Diff line number Diff line change
@@ -13,6 +13,8 @@
# software without disclosing the source code of your own applications. To purchase
# a commercial license, send an email to license@arduino.cc.
import os
import shutil
import json
from pathlib import Path

import pytest
@@ -195,3 +197,143 @@ def test_compile_and_upload_combo_with_custom_build_path(run_command, data_dir,
assert f"Compile {sketch_name} for {board.fqbn} successful" in traces
assert f"Upload {sketch_path} on {board.fqbn} started" in traces
assert "Upload successful" in traces


def test_compile_and_upload_combo_sketch_with_pde_extension(run_command, data_dir, detected_boards, wait_for_board):
assert run_command("update")

sketch_name = "CompileAndUploadPdeSketch"
sketch_path = Path(data_dir, sketch_name)

# Create a test sketch
assert run_command(f"sketch new {sketch_path}")

# Renames sketch file to pde
sketch_file = Path(sketch_path, f"{sketch_name}.ino").rename(sketch_path / f"{sketch_name}.pde")

for board in detected_boards:
# Install core
core = ":".join(board.fqbn.split(":")[:2])
assert run_command(f"core install {core}")

# Build sketch and upload from folder
wait_for_board()
res = run_command(f"compile --clean -b {board.fqbn} -u -p {board.address} {sketch_path}")
assert res.ok
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
assert str(sketch_file) in res.stderr

# Build sketch and upload from file
wait_for_board()
res = run_command(f"compile --clean -b {board.fqbn} -u -p {board.address} {sketch_file}")
assert res.ok
assert "Sketches with .pde extension are deprecated, please rename the following files to .ino" in res.stderr
assert str(sketch_file) in res.stderr


def test_upload_sketch_with_pde_extension(run_command, data_dir, detected_boards, wait_for_board):
assert run_command("update")

sketch_name = "UploadPdeSketch"
sketch_path = Path(data_dir, sketch_name)

# Create a test sketch
assert run_command(f"sketch new {sketch_path}")

# Renames sketch file to pde
sketch_file = Path(sketch_path, f"{sketch_name}.ino").rename(sketch_path / f"{sketch_name}.pde")

for board in detected_boards:
# Install core
core = ":".join(board.fqbn.split(":")[:2])
assert run_command(f"core install {core}")

# Compile sketch first
res = run_command(f"compile --clean -b {board.fqbn} {sketch_path} --format json")
assert res.ok
data = json.loads(res.stdout)
build_dir = Path(data["builder_result"]["build_path"])

# Upload from sketch folder
wait_for_board()
assert run_command(f"upload -b {board.fqbn} -p {board.address} {sketch_path}")

# Upload from sketch file
wait_for_board()
assert run_command(f"upload -b {board.fqbn} -p {board.address} {sketch_file}")

wait_for_board()
res = run_command(f"upload -b {board.fqbn} -p {board.address} --input-dir {build_dir}")
assert (
"Sketches with .pde extension are deprecated, please rename the following files to .ino:" not in res.stderr
)

# Upload from binary file
wait_for_board()
# We don't need a specific file when using the --input-file flag to upload since
# it's just used to calculate the directory, so it's enough to get a random file
# that's inside that directory
binary_file = next(build_dir.glob(f"{sketch_name}.pde.*"))
res = run_command(f"upload -b {board.fqbn} -p {board.address} --input-file {binary_file}")
assert (
"Sketches with .pde extension are deprecated, please rename the following files to .ino:" not in res.stderr
)


def test_upload_with_input_dir_containing_multiple_binaries(run_command, data_dir, detected_boards, wait_for_board):
# This tests verifies the behaviour outlined in this issue:
# https://github.com/arduino/arduino-cli/issues/765#issuecomment-699678646
assert run_command("update")

# Create a two different sketches
sketch_one_name = "UploadMultipleBinariesSketchOne"
sketch_one_path = Path(data_dir, sketch_one_name)
assert run_command(f"sketch new {sketch_one_path}")

sketch_two_name = "UploadMultipleBinariesSketchTwo"
sketch_two_path = Path(data_dir, sketch_two_name)
assert run_command(f"sketch new {sketch_two_path}")

for board in detected_boards:
# Install core
core = ":".join(board.fqbn.split(":")[:2])
assert run_command(f"core install {core}")

# Compile both sketches and copy binaries in the same directory same build directory
res = run_command(f"compile --clean -b {board.fqbn} {sketch_one_path} --format json")
assert res.ok
data = json.loads(res.stdout)
build_dir_one = Path(data["builder_result"]["build_path"])
res = run_command(f"compile --clean -b {board.fqbn} {sketch_two_path} --format json")
assert res.ok
data = json.loads(res.stdout)
build_dir_two = Path(data["builder_result"]["build_path"])

# Copy binaries to same folder
binaries_dir = Path(data_dir, "build", "BuiltBinaries")
shutil.copytree(build_dir_one, binaries_dir, dirs_exist_ok=True)
shutil.copytree(build_dir_two, binaries_dir, dirs_exist_ok=True)

wait_for_board()
# Verifies upload fails because multiple binaries are found
res = run_command(f"upload -b {board.fqbn} -p {board.address} --input-dir {binaries_dir}")
assert res.failed
assert (
"Error during Upload: "
+ "retrieving build artifacts: "
+ "autodetect build artifact: "
+ "multiple build artifacts found:"
in res.stderr
)

# Copy binaries to folder with same name of a sketch
binaries_dir = Path(data_dir, "build", "UploadMultipleBinariesSketchOne")
shutil.copytree(build_dir_one, binaries_dir, dirs_exist_ok=True)
shutil.copytree(build_dir_two, binaries_dir, dirs_exist_ok=True)

wait_for_board()
# Verifies upload is successful using the binaries with the same name of the containing folder
res = run_command(f"upload -b {board.fqbn} -p {board.address} --input-dir {binaries_dir}")
assert (
"Sketches with .pde extension are deprecated, please rename the following files to .ino:" not in res.stderr
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void setup() { }

void loop() { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void setup() { }

void loop() { }
3 changes: 3 additions & 0 deletions test/testdata/sketch_pde_main_file/sketch_pde_main_file.pde
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void setup() { }

void loop() { }