Skip to content

Commit ffe44ea

Browse files
authored
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

+5-1
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

+3-7
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

+46-9
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

+50
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
void setup() {}
3+
void loop() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
void setup() {}
3+
void loop() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
void setup() {}
3+
void loop() {}

cli/compile/compile.go

+10
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

+11-1
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

+9
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

+9-18
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

+10-7
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
}

0 commit comments

Comments
 (0)