diff --git a/arduino/globals/globals.go b/arduino/globals/globals.go index a7802d6dff2..b58d00f3e0e 100644 --- a/arduino/globals/globals.go +++ b/arduino/globals/globals.go @@ -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, } diff --git a/arduino/libraries/loader.go b/arduino/libraries/loader.go index 8e8462536e4..70e738d3fdd 100644 --- a/arduino/libraries/loader.go +++ b/arduino/libraries/loader.go @@ -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() -} diff --git a/arduino/sketches/sketches.go b/arduino/sketches/sketches.go index fef80969b08..d219e936f62 100644 --- a/arduino/sketches/sketches.go +++ b/arduino/sketches/sketches.go @@ -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 +} diff --git a/arduino/sketches/sketches_test.go b/arduino/sketches/sketches_test.go index 65a30c37cea..49ea771e4fd 100644 --- a/arduino/sketches/sketches_test.go +++ b/arduino/sketches/sketches_test.go @@ -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]) +} diff --git a/arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.ino b/arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.ino new file mode 100644 index 00000000000..5054c040393 --- /dev/null +++ b/arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.ino @@ -0,0 +1,3 @@ + +void setup() {} +void loop() {} diff --git a/arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.pde b/arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.pde new file mode 100644 index 00000000000..5054c040393 --- /dev/null +++ b/arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.pde @@ -0,0 +1,3 @@ + +void setup() {} +void loop() {} diff --git a/arduino/sketches/testdata/SketchPde/SketchPde.pde b/arduino/sketches/testdata/SketchPde/SketchPde.pde new file mode 100644 index 00000000000..5054c040393 --- /dev/null +++ b/arduino/sketches/testdata/SketchPde/SketchPde.pde @@ -0,0 +1,3 @@ + +void setup() {} +void loop() {} diff --git a/cli/compile/compile.go b/cli/compile/compile.go index e77b3fb5740..4b095cdf592 100644 --- a/cli/compile/compile.go +++ b/cli/compile/compile.go @@ -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) + } + } + // 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. diff --git a/cli/sketch/archive.go b/cli/sketch/archive.go index 65eff2d8a98..b44f9990ab8 100644 --- a/cli/sketch/archive.go +++ b/cli/sketch/archive.go @@ -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] diff --git a/cli/upload/upload.go b/cli/upload/upload.go index fc75999ca3b..6476f8a8a9f 100644 --- a/cli/upload/upload.go +++ b/cli/upload/upload.go @@ -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, diff --git a/commands/sketch/archive.go b/commands/sketch/archive.go index d5b77fd792b..d702489a83b 100644 --- a/commands/sketch/archive.go +++ b/commands/sketch/archive.go @@ -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) } diff --git a/commands/upload/upload.go b/commands/upload/upload.go index bd55c7ecd5d..8da6876c287 100644 --- a/commands/upload/upload.go +++ b/commands/upload/upload.go @@ -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 } diff --git a/docs/sketch-specification.md b/docs/sketch-specification.md index fb1a59060e6..f1f2dd9c292 100644 --- a/docs/sketch-specification.md +++ b/docs/sketch-specification.md @@ -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. diff --git a/test/test_compile.py b/test/test_compile.py index 8b5337e02cf..aee5b0c8a1d 100644 --- a/test/test_compile.py +++ b/test/test_compile.py @@ -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 diff --git a/test/test_debug.py b/test/test_debug.py index 9c3d4079396..30fcfd09777 100644 --- a/test/test_debug.py +++ b/test/test_debug.py @@ -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") diff --git a/test/test_lib.py b/test/test_lib.py index 77e03cd13c5..5a164b95f05 100644 --- a/test/test_lib.py +++ b/test/test_lib.py @@ -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 diff --git a/test/test_sketch.py b/test/test_sketch.py index 34ac263a71c..d3fb4126faa 100644 --- a/test/test_sketch.py +++ b/test/test_sketch.py @@ -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 diff --git a/test/test_upload.py b/test/test_upload.py index 60d0149dde4..7f8d272a822 100644 --- a/test/test_upload.py +++ b/test/test_upload.py @@ -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 + ) diff --git a/test/testdata/sketch_multiple_main_files/sketch_multiple_main_files.ino b/test/testdata/sketch_multiple_main_files/sketch_multiple_main_files.ino new file mode 100644 index 00000000000..2263c4bcd9e --- /dev/null +++ b/test/testdata/sketch_multiple_main_files/sketch_multiple_main_files.ino @@ -0,0 +1,3 @@ +void setup() { } + +void loop() { } \ No newline at end of file diff --git a/test/testdata/sketch_multiple_main_files/sketch_multiple_main_files.pde b/test/testdata/sketch_multiple_main_files/sketch_multiple_main_files.pde new file mode 100644 index 00000000000..2263c4bcd9e --- /dev/null +++ b/test/testdata/sketch_multiple_main_files/sketch_multiple_main_files.pde @@ -0,0 +1,3 @@ +void setup() { } + +void loop() { } \ No newline at end of file diff --git a/test/testdata/sketch_pde_main_file/sketch_pde_main_file.pde b/test/testdata/sketch_pde_main_file/sketch_pde_main_file.pde new file mode 100644 index 00000000000..2263c4bcd9e --- /dev/null +++ b/test/testdata/sketch_pde_main_file/sketch_pde_main_file.pde @@ -0,0 +1,3 @@ +void setup() { } + +void loop() { } \ No newline at end of file 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