From d6d16532c1a6eb4160b8cf8d3b4075e74d23f782 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Thu, 8 Jul 2021 12:11:35 +0200 Subject: [PATCH 01/10] Refactor codebase to use a single Sketch struct --- arduino/builder/builder.go | 46 --- arduino/builder/builder_test.go | 59 --- arduino/builder/sketch.go | 234 ++---------- arduino/builder/sketch_test.go | 256 ++----------- .../testdata/TestMergeSketchSources.txt | 6 +- .../testdata/TestMergeSketchSources_win.txt | 6 +- arduino/libraries/loader.go | 4 +- arduino/sketch/sketch.go | 297 ++++++++++------ arduino/sketch/sketch_test.go | 336 ++++++++++++------ .../SketchBothInoAndPde.ino} | 0 .../SketchBothInoAndPde.pde} | 0 .../SketchMultipleMainFiles.ino | 0 .../SketchMultipleMainFiles.pde | 0 .../testdata/SketchPde/SketchPde.pde | 0 .../SketchSimple.ino} | 0 .../{TestNew => SketchSimple}/other.cpp | 0 .../testdata/SketchSymlinkSrc/.#sketch.ino | 2 + .../SketchSymlinkSrc/SketchSymlinkSrc.ino | 7 + .../sketch/testdata/SketchSymlinkSrc/doc.txt | 0 .../sketch/testdata/SketchSymlinkSrc/header.h | 1 + .../sketch/testdata/SketchSymlinkSrc/old.pde | 0 .../testdata/SketchSymlinkSrc/other.ino | 3 + .../sketch/testdata/SketchSymlinkSrc/s_file.S | 0 .../SketchSymlinkSrc/src/dont_load_me.ino | 2 + .../testdata/SketchSymlinkSrc/src/helper.h | 0 .../testdata/SketchWithWrongMain/main.ino} | 1 - arduino/sketches/sketches.go | 148 -------- arduino/sketches/sketches_test.go | 132 ------- cli/compile/compile.go | 4 +- cli/sketch/archive.go | 14 +- cli/upload/upload.go | 4 +- commands/board/attach.go | 12 +- commands/compile/compile.go | 16 +- commands/debug/debug_info.go | 18 +- commands/instances.go | 29 +- commands/sketch/archive.go | 8 +- commands/upload/upload.go | 25 +- commands/upload/upload_test.go | 11 +- legacy/builder/builder.go | 10 +- legacy/builder/container_add_prototypes.go | 4 +- legacy/builder/container_find_includes.go | 2 +- .../container_merge_copy_sketch_files.go | 10 +- legacy/builder/container_setup.go | 13 +- legacy/builder/create_cmake_rule.go | 2 +- legacy/builder/ctags_runner.go | 2 +- legacy/builder/filter_sketch_source.go | 6 +- .../builder/merge_sketch_with_bootloader.go | 2 +- legacy/builder/preprocess_sketch.go | 4 +- legacy/builder/setup_build_properties.go | 2 +- legacy/builder/sketch_loader.go | 68 +--- .../test/Baladuino/Baladuino.preprocessed.txt | 8 +- ...harWithEscapedDoubleQuote.preprocessed.txt | 46 +-- ...deBetweenMultilineComment.preprocessed.txt | 8 +- .../LineContinuations.preprocessed.txt | 8 +- .../SketchWithIfDef.preprocessed.txt | 14 +- .../SketchWithIfDef.resolved.directives.txt | 2 +- .../SketchWithStruct.preprocessed.txt | 10 +- .../StringWithComment.preprocessed.txt | 8 +- legacy/builder/test/ctags_runner_test.go | 47 --- legacy/builder/test/sketch1/merged_sketch.txt | 2 +- .../sketch_with_config.preprocessed.txt | 8 +- .../sketch.preprocessed.SAM.txt | 14 +- .../sketch_with_ifdef/sketch.preprocessed.txt | 14 +- .../sketch_with_templates_and_shift.cpp | 19 - legacy/builder/types/context.go | 9 +- legacy/builder/types/types.go | 54 +-- test/test_compile.py | 10 +- 67 files changed, 700 insertions(+), 1387 deletions(-) delete mode 100644 arduino/builder/builder.go delete mode 100644 arduino/builder/builder_test.go rename arduino/{sketches/testdata/SketchCasingCorrect/SketchCasingCorrect.ino => sketch/testdata/SketchBothInoAndPde/SketchBothInoAndPde.ino} (100%) rename arduino/{sketches/testdata/SketchCasingWrong/sketchcasingwrong.ino => sketch/testdata/SketchBothInoAndPde/SketchBothInoAndPde.pde} (100%) rename arduino/{sketches => sketch}/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.ino (100%) rename arduino/{sketches => sketch}/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.pde (100%) rename arduino/{sketches => sketch}/testdata/SketchPde/SketchPde.pde (100%) rename arduino/sketch/testdata/{TestNew/TestNew.ino => SketchSimple/SketchSimple.ino} (100%) rename arduino/sketch/testdata/{TestNew => SketchSimple}/other.cpp (100%) create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/.#sketch.ino create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/SketchSymlinkSrc.ino create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/doc.txt create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/header.h create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/old.pde create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/other.ino create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/s_file.S create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/src/dont_load_me.ino create mode 100644 arduino/sketch/testdata/SketchSymlinkSrc/src/helper.h rename arduino/{sketches/testdata/Sketch1/Sketch1.ino => sketch/testdata/SketchWithWrongMain/main.ino} (96%) delete mode 100644 arduino/sketches/sketches.go delete mode 100644 arduino/sketches/sketches_test.go delete mode 100644 legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.cpp diff --git a/arduino/builder/builder.go b/arduino/builder/builder.go deleted file mode 100644 index a0c3d9b8153..00000000000 --- a/arduino/builder/builder.go +++ /dev/null @@ -1,46 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) -// -// This software is released under the GNU General Public License version 3, -// which covers the main part of arduino-cli. -// The terms of this license can be found at: -// https://www.gnu.org/licenses/gpl-3.0.en.html -// -// You can be released from the requirements of the above licenses by purchasing -// a commercial license. Buying such a license is mandatory if you want to -// modify or otherwise use the software for commercial activities involving the -// Arduino software without disclosing the source code of your own applications. -// To purchase a commercial license, send an email to license@arduino.cc. - -package builder - -import ( - "crypto/md5" - "encoding/hex" - "os" - "strings" - - "github.com/arduino/go-paths-helper" - "github.com/pkg/errors" -) - -// GenBuildPath generates a suitable name for the build folder. -// The sketchPath, if not nil, is also used to furhter differentiate build paths. -func GenBuildPath(sketchPath *paths.Path) *paths.Path { - path := "" - if sketchPath != nil { - path = sketchPath.String() - } - md5SumBytes := md5.Sum([]byte(path)) - md5Sum := strings.ToUpper(hex.EncodeToString(md5SumBytes[:])) - return paths.TempDir().Join("arduino-sketch-" + md5Sum) -} - -// EnsureBuildPathExists creates the build path if doesn't already exists. -func EnsureBuildPathExists(path string) error { - if err := os.MkdirAll(path, os.FileMode(0755)); err != nil { - return errors.Wrap(err, "unable to create build path") - } - return nil -} diff --git a/arduino/builder/builder_test.go b/arduino/builder/builder_test.go deleted file mode 100644 index 44cf1e73771..00000000000 --- a/arduino/builder/builder_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) -// -// This software is released under the GNU General Public License version 3, -// which covers the main part of arduino-cli. -// The terms of this license can be found at: -// https://www.gnu.org/licenses/gpl-3.0.en.html -// -// You can be released from the requirements of the above licenses by purchasing -// a commercial license. Buying such a license is mandatory if you want to -// modify or otherwise use the software for commercial activities involving the -// Arduino software without disclosing the source code of your own applications. -// To purchase a commercial license, send an email to license@arduino.cc. - -package builder_test - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/arduino/arduino-cli/arduino/builder" - "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/assert" -) - -func tmpDirOrDie() string { - dir, err := ioutil.TempDir(os.TempDir(), "builder_test") - if err != nil { - panic(fmt.Sprintf("error creating tmp dir: %v", err)) - } - return dir -} - -func TestGenBuildPath(t *testing.T) { - want := paths.TempDir().Join("arduino-sketch-ACBD18DB4CC2F85CEDEF654FCCC4A4D8") - assert.True(t, builder.GenBuildPath(paths.New("foo")).EquivalentTo(want)) - - want = paths.TempDir().Join("arduino-sketch-D41D8CD98F00B204E9800998ECF8427E") - assert.True(t, builder.GenBuildPath(nil).EquivalentTo(want)) -} - -func TestEnsureBuildPathExists(t *testing.T) { - tmp := tmpDirOrDie() - defer os.RemoveAll(tmp) - bp := filepath.Join(tmp, "build_path") - - assert.Nil(t, builder.EnsureBuildPathExists(bp)) - _, err := os.Stat(bp) - assert.Nil(t, err) - - // run again over an existing folder - assert.Nil(t, builder.EnsureBuildPathExists(bp)) - _, err = os.Stat(bp) - assert.Nil(t, err) -} diff --git a/arduino/builder/sketch.go b/arduino/builder/sketch.go index a1a761f795d..7b192fab37a 100644 --- a/arduino/builder/sketch.go +++ b/arduino/builder/sketch.go @@ -17,24 +17,16 @@ package builder import ( "bytes" - "io/ioutil" - "os" - "path/filepath" + "fmt" "regexp" "strings" - "github.com/arduino/arduino-cli/arduino/globals" "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/arduino-cli/cli/errorcodes" - "github.com/arduino/arduino-cli/cli/feedback" + "github.com/arduino/go-paths-helper" "github.com/pkg/errors" ) -// As currently implemented on Linux, -// the maximum number of symbolic links that will be followed while resolving a pathname is 40 -const maxFileSystemDepth = 40 - var includesArduinoH = regexp.MustCompile(`(?m)^\s*#\s*include\s*[<\"]Arduino\.h[>\"]`) // QuoteCppString returns the given string as a quoted string for use with the C @@ -47,188 +39,39 @@ func QuoteCppString(str string) string { } // SketchSaveItemCpp saves a preprocessed .cpp sketch file on disk -func SketchSaveItemCpp(path string, contents []byte, destPath string) error { - - sketchName := filepath.Base(path) - - if err := os.MkdirAll(destPath, os.FileMode(0755)); err != nil { +func SketchSaveItemCpp(path *paths.Path, contents []byte, destPath *paths.Path) error { + sketchName := path.Base() + if err := destPath.MkdirAll(); err != nil { return errors.Wrap(err, "unable to create a folder to save the sketch") } - destFile := filepath.Join(destPath, sketchName+".cpp") + destFile := destPath.Join(fmt.Sprintf("%s.cpp", sketchName)) - if err := ioutil.WriteFile(destFile, contents, os.FileMode(0644)); err != nil { + if err := destFile.WriteFile(contents); err != nil { return errors.Wrap(err, "unable to save the sketch on disk") } return nil } -// simpleLocalWalk locally replaces filepath.Walk and/but goes through symlinks -func simpleLocalWalk(root string, maxDepth int, walkFn func(path string, info os.FileInfo, err error) error) error { - - info, err := os.Stat(root) - - if err != nil { - return walkFn(root, nil, err) - } - - err = walkFn(root, info, err) - if err == filepath.SkipDir { - return nil - } - - if info.IsDir() { - if maxDepth <= 0 { - return walkFn(root, info, errors.New("Filesystem bottom is too deep (directory recursion or filesystem really deep): "+root)) - } - maxDepth-- - files, err := ioutil.ReadDir(root) - if err == nil { - for _, file := range files { - err = simpleLocalWalk(root+string(os.PathSeparator)+file.Name(), maxDepth, walkFn) - if err == filepath.SkipDir { - return nil - } - } - } - } - - return nil -} - -// SketchLoad collects all the files composing a sketch. -// The parameter `sketchPath` holds a path pointing to a single sketch file or a sketch folder, -// the path must be absolute. -func SketchLoad(sketchPath, buildPath string) (*sketch.Sketch, error) { - stat, err := os.Stat(sketchPath) - if err != nil { - return nil, errors.Wrap(err, "unable to stat Sketch location") - } - - var sketchFolder, mainSketchFile string - - // if a sketch folder was passed, save the parent and point sketchPath to the main sketch file - if stat.IsDir() { - sketchFolder = sketchPath - // allowed extensions are .ino and .pde (but not both) - for extension := range globals.MainFileValidExtensions { - candidateSketchFile := filepath.Join(sketchPath, stat.Name()+extension) - if _, err := os.Stat(candidateSketchFile); !os.IsNotExist(err) { - if mainSketchFile == "" { - mainSketchFile = candidateSketchFile - } else { - return nil, errors.Errorf("multiple main sketch files found (%v,%v)", - filepath.Base(mainSketchFile), - filepath.Base(candidateSketchFile)) - } - } - } - - // check main file was found - if mainSketchFile == "" { - return nil, errors.Errorf("unable to find a sketch file in directory %v", sketchFolder) - } - - // check main file is readable - f, err := os.Open(mainSketchFile) - if err != nil { - return nil, errors.Wrap(err, "unable to open the main sketch file") - } - f.Close() - - // ensure it is not a directory - info, err := os.Stat(mainSketchFile) - if err != nil { - return nil, errors.Wrap(err, "unable to check the main sketch file") - } - if info.IsDir() { - return nil, errors.Wrap(errors.New(mainSketchFile), "sketch must not be a directory") - } - } else { - sketchFolder = filepath.Dir(sketchPath) - mainSketchFile = sketchPath - } - - // collect all the sketch files - var files []string - rootVisited := false - err = simpleLocalWalk(sketchFolder, maxFileSystemDepth, func(path string, info os.FileInfo, err error) error { - if err != nil { - feedback.Errorf("Error during sketch processing: %v", err) - os.Exit(errorcodes.ErrGeneric) - } - - if info.IsDir() { - // Filters in this if-block are NOT applied to the sketch folder itself. - // Since the sketch folder is the first one processed by simpleLocalWalk, - // we can set the `rootVisited` guard to exclude it. - if rootVisited { - // skip hidden folders - if strings.HasPrefix(info.Name(), ".") { - return filepath.SkipDir - } - - // skip legacy SCM directories - if info.Name() == "CVS" || info.Name() == "RCS" { - return filepath.SkipDir - } - } else { - rootVisited = true - } - - // ignore (don't skip) directory - return nil - } - - // ignore hidden files - if strings.HasPrefix(info.Name(), ".") { - return nil - } - - // ignore if file extension doesn't match - ext := filepath.Ext(path) - _, isMain := globals.MainFileValidExtensions[ext] - _, isAdditional := globals.AdditionalFileValidExtensions[ext] - if !(isMain || isAdditional) { - return nil - } - - // check if file is readable - f, err := os.Open(path) - if err != nil { - return nil - } - f.Close() - - // collect the file - files = append(files, path) - - // done - return nil - }) - - if err != nil { - return nil, errors.Wrap(err, "there was an error while collecting the sketch files") - } - - return sketch.New(sketchFolder, mainSketchFile, buildPath, files) -} - // SketchMergeSources merges all the source files included in a sketch func SketchMergeSources(sk *sketch.Sketch, overrides map[string]string) (int, string, error) { lineOffset := 0 mergedSource := "" - getSource := func(i *sketch.Item) (string, error) { - path, err := filepath.Rel(sk.LocationPath, i.Path) + getSource := func(f *paths.Path) (string, error) { + path, err := sk.FullPath.RelTo(f) if err != nil { return "", errors.Wrap(err, "unable to compute relative path to the sketch for the item") } - if override, ok := overrides[path]; ok { + if override, ok := overrides[path.String()]; ok { return override, nil } - return i.GetSourceStr() + data, err := f.ReadFile() + if err != nil { + return "", fmt.Errorf("reading file %s: %s", f, err) + } + return string(data), nil } // add Arduino.h inclusion directive if missing @@ -241,16 +84,16 @@ func SketchMergeSources(sk *sketch.Sketch, overrides map[string]string) (int, st lineOffset++ } - mergedSource += "#line 1 " + QuoteCppString(sk.MainFile.Path) + "\n" + mergedSource += "#line 1 " + QuoteCppString(sk.MainFile.String()) + "\n" mergedSource += mainSrc + "\n" lineOffset++ - for _, item := range sk.OtherSketchFiles { - src, err := getSource(item) + for _, file := range *sk.OtherSketchFiles { + src, err := getSource(file) if err != nil { return 0, "", err } - mergedSource += "#line 1 " + QuoteCppString(item.Path) + "\n" + mergedSource += "#line 1 " + QuoteCppString(file.String()) + "\n" mergedSource += src + "\n" } @@ -259,30 +102,30 @@ func SketchMergeSources(sk *sketch.Sketch, overrides map[string]string) (int, st // SketchCopyAdditionalFiles copies the additional files for a sketch to the // specified destination directory. -func SketchCopyAdditionalFiles(sketch *sketch.Sketch, destPath string, overrides map[string]string) error { - if err := os.MkdirAll(destPath, os.FileMode(0755)); err != nil { +func SketchCopyAdditionalFiles(sketch *sketch.Sketch, destPath *paths.Path, overrides map[string]string) error { + if err := destPath.MkdirAll(); err != nil { return errors.Wrap(err, "unable to create a folder to save the sketch files") } - for _, item := range sketch.AdditionalFiles { - relpath, err := filepath.Rel(sketch.LocationPath, item.Path) + for _, file := range *sketch.AdditionalFiles { + relpath, err := sketch.FullPath.RelTo(file) if err != nil { return errors.Wrap(err, "unable to compute relative path to the sketch for the item") } - targetPath := filepath.Join(destPath, relpath) + targetPath := destPath.JoinPath(relpath) // create the directory containing the target - if err = os.MkdirAll(filepath.Dir(targetPath), os.FileMode(0755)); err != nil { + if err = targetPath.Parent().MkdirAll(); err != nil { return errors.Wrap(err, "unable to create the folder containing the item") } var sourceBytes []byte - if override, ok := overrides[relpath]; ok { + if override, ok := overrides[relpath.String()]; ok { // use override source sourceBytes = []byte(override) } else { // read the source file - s, err := item.GetSourceBytes() + s, err := file.ReadFile() if err != nil { return errors.Wrap(err, "unable to read contents of the source item") } @@ -290,7 +133,7 @@ func SketchCopyAdditionalFiles(sketch *sketch.Sketch, destPath string, overrides } // tag each addtional file with the filename of the source it was copied from - sourceBytes = append([]byte("#line 1 "+QuoteCppString(item.Path)+"\n"), sourceBytes...) + sourceBytes = append([]byte("#line 1 "+QuoteCppString(file.String())+"\n"), sourceBytes...) err = writeIfDifferent(sourceBytes, targetPath) if err != nil { @@ -301,25 +144,24 @@ func SketchCopyAdditionalFiles(sketch *sketch.Sketch, destPath string, overrides return nil } -func writeIfDifferent(source []byte, destPath string) error { - // check whether the destination file exists - _, err := os.Stat(destPath) - if os.IsNotExist(err) { - // write directly - return ioutil.WriteFile(destPath, source, os.FileMode(0644)) +func writeIfDifferent(source []byte, destPath *paths.Path) error { + // Check whether the destination file exists + if destPath.NotExist() { + // Write directly + return destPath.WriteFile(source) } - // read the destination file if it ex - existingBytes, err := ioutil.ReadFile(destPath) + // Read the destination file if it exists + existingBytes, err := destPath.ReadFile() if err != nil { return errors.Wrap(err, "unable to read contents of the destination item") } - // overwrite if contents are different + // Overwrite if contents are different if bytes.Compare(existingBytes, source) != 0 { - return ioutil.WriteFile(destPath, source, os.FileMode(0644)) + return destPath.WriteFile(source) } - // source and destination are the same, don't write anything + // Source and destination are the same, don't write anything return nil } diff --git a/arduino/builder/sketch_test.go b/arduino/builder/sketch_test.go index 7b535203d6d..d7fd40b22c5 100644 --- a/arduino/builder/sketch_test.go +++ b/arduino/builder/sketch_test.go @@ -25,23 +25,33 @@ import ( "testing" "github.com/arduino/arduino-cli/arduino/builder" + "github.com/arduino/arduino-cli/arduino/sketch" + "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" ) +func tmpDirOrDie() *paths.Path { + dir, err := ioutil.TempDir(os.TempDir(), "builder_test") + if err != nil { + panic(fmt.Sprintf("error creating tmp dir: %v", err)) + } + return paths.New(dir) +} + func TestSaveSketch(t *testing.T) { sketchName := t.Name() + ".ino" outName := sketchName + ".cpp" sketchFile := filepath.Join("testdata", sketchName) tmp := tmpDirOrDie() - defer os.RemoveAll(tmp) + defer tmp.RemoveAll() source, err := ioutil.ReadFile(sketchFile) if err != nil { t.Fatalf("unable to read golden file %s: %v", sketchFile, err) } - builder.SketchSaveItemCpp(sketchName, source, tmp) + builder.SketchSaveItemCpp(paths.New(sketchName), source, tmp) - out, err := ioutil.ReadFile(filepath.Join(tmp, outName)) + out, err := tmp.Join(outName).ReadFile() if err != nil { t.Fatalf("unable to read output file %s: %v", outName, err) } @@ -49,148 +59,9 @@ func TestSaveSketch(t *testing.T) { require.Equal(t, source, out) } -func TestLoadSketchFolder(t *testing.T) { - // pass the path to the sketch folder - sketchPath := filepath.Join("testdata", t.Name()) - mainFilePath := filepath.Join(sketchPath, t.Name()+".ino") - s, err := builder.SketchLoad(sketchPath, "") - require.Nil(t, err) - require.NotNil(t, s) - require.Equal(t, mainFilePath, s.MainFile.Path) - require.Equal(t, sketchPath, s.LocationPath) - require.Len(t, s.OtherSketchFiles, 2) - require.Equal(t, "old.pde", filepath.Base(s.OtherSketchFiles[0].Path)) - require.Equal(t, "other.ino", filepath.Base(s.OtherSketchFiles[1].Path)) - require.Len(t, s.AdditionalFiles, 3) - require.Equal(t, "header.h", filepath.Base(s.AdditionalFiles[0].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.AdditionalFiles[1].Path)) - require.Equal(t, "helper.h", filepath.Base(s.AdditionalFiles[2].Path)) - require.Len(t, s.RootFolderFiles, 4) - require.Equal(t, "header.h", filepath.Base(s.RootFolderFiles[0].Path)) - require.Equal(t, "old.pde", filepath.Base(s.RootFolderFiles[1].Path)) - require.Equal(t, "other.ino", filepath.Base(s.RootFolderFiles[2].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.RootFolderFiles[3].Path)) - - // pass the path to the main file - sketchPath = mainFilePath - s, err = builder.SketchLoad(sketchPath, "") - require.Nil(t, err) - require.NotNil(t, s) - require.Equal(t, mainFilePath, s.MainFile.Path) - require.Len(t, s.OtherSketchFiles, 2) - require.Equal(t, "old.pde", filepath.Base(s.OtherSketchFiles[0].Path)) - require.Equal(t, "other.ino", filepath.Base(s.OtherSketchFiles[1].Path)) - require.Len(t, s.AdditionalFiles, 3) - require.Equal(t, "header.h", filepath.Base(s.AdditionalFiles[0].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.AdditionalFiles[1].Path)) - require.Equal(t, "helper.h", filepath.Base(s.AdditionalFiles[2].Path)) - require.Len(t, s.RootFolderFiles, 4) - require.Equal(t, "header.h", filepath.Base(s.RootFolderFiles[0].Path)) - require.Equal(t, "old.pde", filepath.Base(s.RootFolderFiles[1].Path)) - require.Equal(t, "other.ino", filepath.Base(s.RootFolderFiles[2].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.RootFolderFiles[3].Path)) -} - -func TestLoadSketchFolderPde(t *testing.T) { - // pass the path to the sketch folder - sketchPath := filepath.Join("testdata", t.Name()) - mainFilePath := filepath.Join(sketchPath, t.Name()+".pde") - s, err := builder.SketchLoad(sketchPath, "") - require.Nil(t, err) - require.NotNil(t, s) - require.Equal(t, mainFilePath, s.MainFile.Path) - require.Equal(t, sketchPath, s.LocationPath) - require.Len(t, s.OtherSketchFiles, 2) - require.Equal(t, "old.pde", filepath.Base(s.OtherSketchFiles[0].Path)) - require.Equal(t, "other.ino", filepath.Base(s.OtherSketchFiles[1].Path)) - require.Len(t, s.AdditionalFiles, 3) - require.Equal(t, "header.h", filepath.Base(s.AdditionalFiles[0].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.AdditionalFiles[1].Path)) - require.Equal(t, "helper.h", filepath.Base(s.AdditionalFiles[2].Path)) - require.Len(t, s.RootFolderFiles, 4) - require.Equal(t, "header.h", filepath.Base(s.RootFolderFiles[0].Path)) - require.Equal(t, "old.pde", filepath.Base(s.RootFolderFiles[1].Path)) - require.Equal(t, "other.ino", filepath.Base(s.RootFolderFiles[2].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.RootFolderFiles[3].Path)) -} - -func TestLoadSketchFolderBothInoAndPde(t *testing.T) { - // pass the path to the sketch folder containing two main sketches, .ino and .pde - sketchPath := filepath.Join("testdata", t.Name()) - _, err := builder.SketchLoad(sketchPath, "") - require.Error(t, err) - require.Contains(t, err.Error(), "multiple main sketch files found") - require.Contains(t, err.Error(), t.Name()+".ino") - require.Contains(t, err.Error(), t.Name()+".pde") -} - -func TestLoadSketchFolderSymlink(t *testing.T) { - // pass the path to the sketch folder - symlinkSketchPath := filepath.Join("testdata", t.Name()) - srcSketchPath := t.Name() + "Src" - os.Symlink(srcSketchPath, symlinkSketchPath) - defer os.Remove(symlinkSketchPath) - mainFilePath := filepath.Join(symlinkSketchPath, t.Name()+".ino") - s, err := builder.SketchLoad(symlinkSketchPath, "") - require.Nil(t, err) - require.NotNil(t, s) - require.Equal(t, mainFilePath, s.MainFile.Path) - require.Equal(t, symlinkSketchPath, s.LocationPath) - require.Len(t, s.OtherSketchFiles, 2) - require.Equal(t, "old.pde", filepath.Base(s.OtherSketchFiles[0].Path)) - require.Equal(t, "other.ino", filepath.Base(s.OtherSketchFiles[1].Path)) - require.Len(t, s.AdditionalFiles, 3) - require.Equal(t, "header.h", filepath.Base(s.AdditionalFiles[0].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.AdditionalFiles[1].Path)) - require.Equal(t, "helper.h", filepath.Base(s.AdditionalFiles[2].Path)) - require.Len(t, s.RootFolderFiles, 4) - require.Equal(t, "header.h", filepath.Base(s.RootFolderFiles[0].Path)) - require.Equal(t, "old.pde", filepath.Base(s.RootFolderFiles[1].Path)) - require.Equal(t, "other.ino", filepath.Base(s.RootFolderFiles[2].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.RootFolderFiles[3].Path)) - - // pass the path to the main file - symlinkSketchPath = mainFilePath - s, err = builder.SketchLoad(symlinkSketchPath, "") - require.Nil(t, err) - require.NotNil(t, s) - require.Equal(t, mainFilePath, s.MainFile.Path) - require.Len(t, s.OtherSketchFiles, 2) - require.Equal(t, "old.pde", filepath.Base(s.OtherSketchFiles[0].Path)) - require.Equal(t, "other.ino", filepath.Base(s.OtherSketchFiles[1].Path)) - require.Len(t, s.AdditionalFiles, 3) - require.Equal(t, "header.h", filepath.Base(s.AdditionalFiles[0].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.AdditionalFiles[1].Path)) - require.Equal(t, "helper.h", filepath.Base(s.AdditionalFiles[2].Path)) - require.Len(t, s.RootFolderFiles, 4) - require.Equal(t, "header.h", filepath.Base(s.RootFolderFiles[0].Path)) - require.Equal(t, "old.pde", filepath.Base(s.RootFolderFiles[1].Path)) - require.Equal(t, "other.ino", filepath.Base(s.RootFolderFiles[2].Path)) - require.Equal(t, "s_file.S", filepath.Base(s.RootFolderFiles[3].Path)) -} - -func TestLoadSketchFolderIno(t *testing.T) { - // pass the path to the sketch folder - sketchPath := filepath.Join("testdata", t.Name()) - _, err := builder.SketchLoad(sketchPath, "") - require.Error(t, err) - require.Contains(t, err.Error(), "sketch must not be a directory") -} - -func TestLoadSketchFolderWrongMain(t *testing.T) { - sketchPath := filepath.Join("testdata", t.Name()) - _, err := builder.SketchLoad(sketchPath, "") - require.Error(t, err) - require.Contains(t, err.Error(), "unable to find a sketch file in directory testdata") - - _, err = builder.SketchLoad("does/not/exist", "") - require.Error(t, err) - require.Contains(t, err.Error(), "does/not/exist") -} - func TestMergeSketchSources(t *testing.T) { // borrow the sketch from TestLoadSketchFolder to avoid boilerplate - s, err := builder.SketchLoad(filepath.Join("testdata", "TestLoadSketchFolder"), "") + s, err := sketch.New(paths.New("testdata", "TestLoadSketchFolder")) require.Nil(t, err) require.NotNil(t, s) @@ -199,20 +70,27 @@ func TestMergeSketchSources(t *testing.T) { if runtime.GOOS == "windows" { suffix = "_win.txt" } - mergedPath := filepath.Join("testdata", t.Name()+suffix) - mergedBytes, err := ioutil.ReadFile(mergedPath) + mergedPath := paths.New("testdata", t.Name()+suffix) + mergedBytes, err := mergedPath.ReadFile() if err != nil { t.Fatalf("unable to read golden file %s: %v", mergedPath, err) } + mergedPath.ToAbs() + pathToGoldenSource := mergedPath.Parent().Parent().String() + if runtime.GOOS == "windows" { + pathToGoldenSource = strings.ReplaceAll(pathToGoldenSource, `\`, `\\`) + } + mergedSources := strings.ReplaceAll(string(mergedBytes), "%s", pathToGoldenSource) + offset, source, err := builder.SketchMergeSources(s, nil) require.Nil(t, err) require.Equal(t, 2, offset) - require.Equal(t, string(mergedBytes), source) + require.Equal(t, mergedSources, source) } func TestMergeSketchSourcesArduinoIncluded(t *testing.T) { - s, err := builder.SketchLoad(filepath.Join("testdata", t.Name()), "") + s, err := sketch.New(paths.New("testdata", t.Name())) require.Nil(t, err) require.NotNil(t, s) @@ -224,27 +102,27 @@ func TestMergeSketchSourcesArduinoIncluded(t *testing.T) { func TestCopyAdditionalFiles(t *testing.T) { tmp := tmpDirOrDie() - defer os.RemoveAll(tmp) + defer tmp.RemoveAll() // load the golden sketch - s1, err := builder.SketchLoad(filepath.Join("testdata", t.Name()), "") + s1, err := sketch.New(paths.New("testdata", t.Name())) require.Nil(t, err) - require.Len(t, s1.AdditionalFiles, 1) + require.Equal(t, s1.AdditionalFiles.Len(), 1) // copy the sketch over, create a fake main file we don't care about it // but we need it for `SketchLoad` to succeed later err = builder.SketchCopyAdditionalFiles(s1, tmp, nil) require.Nil(t, err) - fakeIno := filepath.Join(tmp, fmt.Sprintf("%s.ino", filepath.Base(tmp))) - require.Nil(t, ioutil.WriteFile(fakeIno, []byte{}, os.FileMode(0644))) + fakeIno := tmp.Join(fmt.Sprintf("%s.ino", tmp.Base())) + require.Nil(t, fakeIno.WriteFile([]byte{})) // compare - s2, err := builder.SketchLoad(tmp, "") + s2, err := sketch.New(tmp) require.Nil(t, err) - require.Len(t, s2.AdditionalFiles, 1) + require.Equal(t, s2.AdditionalFiles.Len(), 1) // save file info - info1, err := os.Stat(s2.AdditionalFiles[0].Path) + info1, err := paths.New(s2.AdditionalFiles.AsStrings()[0]).Stat() require.Nil(t, err) // copy again @@ -252,72 +130,6 @@ func TestCopyAdditionalFiles(t *testing.T) { require.Nil(t, err) // verify file hasn't changed - info2, err := os.Stat(s2.AdditionalFiles[0].Path) + info2, err := paths.New(s2.AdditionalFiles.AsStrings()[0]).Stat() require.Equal(t, info1.ModTime(), info2.ModTime()) } - -func TestLoadSketchCaseMismatch(t *testing.T) { - // pass the path to the sketch folder - sketchPath := filepath.Join("testdata", t.Name()) - mainFilePath := filepath.Join(sketchPath, t.Name()+".ino") - s, err := builder.SketchLoad(sketchPath, "") - require.Nil(t, s) - require.Error(t, err) - - // pass the path to the main file - s, err = builder.SketchLoad(mainFilePath, "") - require.Nil(t, s) - require.Error(t, err) -} - -func TestSketchWithMarkdownAsciidocJson(t *testing.T) { - sketchPath := filepath.Join("testdata", t.Name()) - mainFilePath := filepath.Join(sketchPath, t.Name()+".ino") - - sketch, err := builder.SketchLoad(sketchPath, "") - require.NotNil(t, sketch) - require.NoError(t, err) - require.Equal(t, sketchPath, sketch.LocationPath) - require.Equal(t, mainFilePath, sketch.MainFile.Path) - require.Len(t, sketch.OtherSketchFiles, 0) - require.Len(t, sketch.AdditionalFiles, 3) - require.Equal(t, "foo.adoc", filepath.Base(sketch.AdditionalFiles[0].Path)) - require.Equal(t, "foo.json", filepath.Base(sketch.AdditionalFiles[1].Path)) - require.Equal(t, "foo.md", filepath.Base(sketch.AdditionalFiles[2].Path)) - require.Len(t, sketch.RootFolderFiles, 3) - require.Equal(t, "foo.adoc", filepath.Base(sketch.RootFolderFiles[0].Path)) - require.Equal(t, "foo.json", filepath.Base(sketch.RootFolderFiles[1].Path)) - require.Equal(t, "foo.md", filepath.Base(sketch.RootFolderFiles[2].Path)) -} - -func TestSketchWithTppFile(t *testing.T) { - sketchPath := filepath.Join("testdata", t.Name()) - mainFilePath := filepath.Join(sketchPath, t.Name()+".ino") - - sketch, err := builder.SketchLoad(sketchPath, "") - require.NotNil(t, sketch) - require.NoError(t, err) - require.Equal(t, sketchPath, sketch.LocationPath) - require.Equal(t, mainFilePath, sketch.MainFile.Path) - require.Len(t, sketch.OtherSketchFiles, 0) - require.Len(t, sketch.AdditionalFiles, 1) - require.Equal(t, "template.tpp", filepath.Base(sketch.AdditionalFiles[0].Path)) - require.Len(t, sketch.RootFolderFiles, 1) - require.Equal(t, "template.tpp", filepath.Base(sketch.RootFolderFiles[0].Path)) -} - -func TestSketchWithIppFile(t *testing.T) { - sketchPath := filepath.Join("testdata", t.Name()) - mainFilePath := filepath.Join(sketchPath, t.Name()+".ino") - - sketch, err := builder.SketchLoad(sketchPath, "") - require.NotNil(t, sketch) - require.NoError(t, err) - require.Equal(t, sketchPath, sketch.LocationPath) - require.Equal(t, mainFilePath, sketch.MainFile.Path) - require.Len(t, sketch.OtherSketchFiles, 0) - require.Len(t, sketch.AdditionalFiles, 1) - require.Equal(t, "template.ipp", filepath.Base(sketch.AdditionalFiles[0].Path)) - require.Len(t, sketch.RootFolderFiles, 1) - require.Equal(t, "template.ipp", filepath.Base(sketch.RootFolderFiles[0].Path)) -} diff --git a/arduino/builder/testdata/TestMergeSketchSources.txt b/arduino/builder/testdata/TestMergeSketchSources.txt index 57f68974397..7021957c534 100644 --- a/arduino/builder/testdata/TestMergeSketchSources.txt +++ b/arduino/builder/testdata/TestMergeSketchSources.txt @@ -1,5 +1,5 @@ #include -#line 1 "testdata/TestLoadSketchFolder/TestLoadSketchFolder.ino" +#line 1 "%s/testdata/TestLoadSketchFolder/TestLoadSketchFolder.ino" void setup() { } @@ -7,9 +7,9 @@ void setup() { void loop() { } -#line 1 "testdata/TestLoadSketchFolder/old.pde" +#line 1 "%s/testdata/TestLoadSketchFolder/old.pde" -#line 1 "testdata/TestLoadSketchFolder/other.ino" +#line 1 "%s/testdata/TestLoadSketchFolder/other.ino" String hello() { return "world"; } diff --git a/arduino/builder/testdata/TestMergeSketchSources_win.txt b/arduino/builder/testdata/TestMergeSketchSources_win.txt index 933987f7b60..4eed9b8eefd 100644 --- a/arduino/builder/testdata/TestMergeSketchSources_win.txt +++ b/arduino/builder/testdata/TestMergeSketchSources_win.txt @@ -1,5 +1,5 @@ #include -#line 1 "testdata\\TestLoadSketchFolder\\TestLoadSketchFolder.ino" +#line 1 "%s\\testdata\\TestLoadSketchFolder\\TestLoadSketchFolder.ino" void setup() { } @@ -7,9 +7,9 @@ void setup() { void loop() { } -#line 1 "testdata\\TestLoadSketchFolder\\old.pde" +#line 1 "%s\\testdata\\TestLoadSketchFolder\\old.pde" -#line 1 "testdata\\TestLoadSketchFolder\\other.ino" +#line 1 "%s\\testdata\\TestLoadSketchFolder\\other.ino" String hello() { return "world"; } diff --git a/arduino/libraries/loader.go b/arduino/libraries/loader.go index 0546229745a..482ff39a78c 100644 --- a/arduino/libraries/loader.go +++ b/arduino/libraries/loader.go @@ -19,7 +19,7 @@ import ( "fmt" "strings" - "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" @@ -173,7 +173,7 @@ func addExamplesToPathList(examplesPath *paths.Path, list *paths.PathList) error return err } for _, file := range files { - _, err := sketches.NewSketchFromPath(file) + _, err := sketch.New(file) if err == nil { list.Add(file) } else if file.IsDir() { diff --git a/arduino/sketch/sketch.go b/arduino/sketch/sketch.go index 9de4fdfd077..2991f2ad920 100644 --- a/arduino/sketch/sketch.go +++ b/arduino/sketch/sketch.go @@ -16,9 +16,10 @@ package sketch import ( + "crypto/md5" + "encoding/hex" + "encoding/json" "fmt" - "io/ioutil" - "path/filepath" "sort" "strings" @@ -27,123 +28,189 @@ import ( "github.com/pkg/errors" ) -// Item holds the source and the path for a single sketch file -type Item struct { - Path string +// Sketch holds all the files composing a sketch +type Sketch struct { + Name string + MainFile *paths.Path + FullPath *paths.Path // FullPath is the path to the Sketch folder + BuildPath *paths.Path + OtherSketchFiles *paths.PathList // Sketch files that end in .ino other than main file + AdditionalFiles *paths.PathList + RootFolderFiles *paths.PathList // All files that are in the Sketch root + Metadata *Metadata } -// NewItem reads the source code for a sketch item and returns an -// Item instance -func NewItem(itemPath string) *Item { - return &Item{itemPath} +// Metadata is the kind of data associated to a project such as the connected board +type Metadata struct { + CPU BoardMetadata `json:"cpu,omitempty"` } -// GetSourceBytes reads the item file contents and returns it as bytes -func (i *Item) GetSourceBytes() ([]byte, error) { - // read the file - source, err := ioutil.ReadFile(i.Path) - if err != nil { - return nil, errors.Wrap(err, "error reading source file") - } - return source, nil +// BoardMetadata represents the board metadata for the sketch +type BoardMetadata struct { + Fqbn string `json:"fqbn,required"` + Name string `json:"name,omitempty"` + Port string `json:"port,omitepty"` } -// GetSourceStr reads the item file contents and returns it as a string -func (i *Item) GetSourceStr() (string, error) { - source, err := i.GetSourceBytes() - if err != nil { - return "", err +// New creates an Sketch instance by reading all the files composing a sketch and grouping them +// by file type. +func New(path *paths.Path) (*Sketch, error) { + path = path.Canonical() + if !path.IsDir() { + path = path.Parent() } - return string(source), nil -} -// ItemByPath implements sort.Interface for []Item based on -// lexicographic order of the path string. -type ItemByPath []*Item + var mainFile *paths.Path + for ext := range globals.MainFileValidExtensions { + candidateSketchMainFile := path.Join(path.Base() + ext) + if candidateSketchMainFile.Exist() { + if mainFile == nil { + mainFile = candidateSketchMainFile + } else { + return nil, errors.Errorf("multiple main sketch files found (%v, %v)", + mainFile, + candidateSketchMainFile, + ) + } + } + } -func (ibn ItemByPath) Len() int { return len(ibn) } -func (ibn ItemByPath) Swap(i, j int) { ibn[i], ibn[j] = ibn[j], ibn[i] } -func (ibn ItemByPath) Less(i, j int) bool { return ibn[i].Path < ibn[j].Path } + sketch := &Sketch{ + Name: path.Base(), + MainFile: mainFile, + FullPath: path, + BuildPath: GenBuildPath(path), + OtherSketchFiles: new(paths.PathList), + AdditionalFiles: new(paths.PathList), + RootFolderFiles: new(paths.PathList), + } -// Sketch holds all the files composing a sketch -type Sketch struct { - MainFile *Item - LocationPath string - OtherSketchFiles []*Item - AdditionalFiles []*Item - RootFolderFiles []*Item -} + err := sketch.checkSketchCasing() + if e, ok := err.(*InvalidSketchFolderNameError); ok { + return nil, e + } + if err != nil { + return nil, err + } -// New creates an Sketch instance by reading all the files composing a sketch and grouping them -// by file type. -func New(sketchFolderPath, mainFilePath, buildPath string, allFilesPaths []string) (*Sketch, error) { - var mainFile *Item - - // read all the sketch contents and create sketch Items - pathToItem := make(map[string]*Item) - for _, p := range allFilesPaths { - // create an Item - item := NewItem(p) - - if p == mainFilePath { - // store the main sketch file - mainFile = item - } else { - // map the file path to sketch.Item - pathToItem[p] = item - } + if mainFile == nil { + return nil, fmt.Errorf("can't find main Sketch file in %s", path) } - // organize the Items - additionalFiles := []*Item{} - otherSketchFiles := []*Item{} - rootFolderFiles := []*Item{} - for p, item := range pathToItem { - ext := filepath.Ext(p) + sketchFolderFiles, err := sketch.supportedFiles() + if err != nil { + return nil, err + } + + // Collect files + for _, p := range *sketchFolderFiles { + // Skip files that can't be opened + f, err := p.Open() + if err != nil { + continue + } + f.Close() + + ext := p.Ext() if _, found := globals.MainFileValidExtensions[ext]; found { - // item is a valid main file, see if it's stored at the + if p.EqualsTo(mainFile) { + // The main file must be included in the lists of other files + continue + } + // file is a valid sketch file, see if it's stored at the // sketch root and ignore if it's not. - if filepath.Dir(p) == sketchFolderPath { - otherSketchFiles = append(otherSketchFiles, item) - rootFolderFiles = append(rootFolderFiles, item) + if p.Parent().EqualsTo(path) { + sketch.OtherSketchFiles.Add(p) + sketch.RootFolderFiles.Add(p) } } else if _, found := globals.AdditionalFileValidExtensions[ext]; found { - // item is a valid sketch file, grab it only if the buildPath is empty - // or the file is within the buildPath - if buildPath == "" || !strings.Contains(filepath.Dir(p), buildPath) { - additionalFiles = append(additionalFiles, item) - if filepath.Dir(p) == sketchFolderPath { - rootFolderFiles = append(rootFolderFiles, item) - } + // If the user exported the compiles binaries to the Sketch "build" folder + // they would be picked up but we don't want them, so we skip them like so + if isInBuildFolder, err := p.IsInsideDir(sketch.FullPath.Join("build")); isInBuildFolder || err != nil { + continue + } + + sketch.AdditionalFiles.Add(p) + if p.Parent().EqualsTo(path) { + sketch.RootFolderFiles.Add(p) } } else { return nil, errors.Errorf("unknown sketch file extension '%s'", ext) } } - sort.Sort(ItemByPath(additionalFiles)) - sort.Sort(ItemByPath(otherSketchFiles)) - sort.Sort(ItemByPath(rootFolderFiles)) + sort.Sort(sketch.AdditionalFiles) + sort.Sort(sketch.OtherSketchFiles) + sort.Sort(sketch.RootFolderFiles) - sk := &Sketch{ - MainFile: mainFile, - LocationPath: sketchFolderPath, - OtherSketchFiles: otherSketchFiles, - AdditionalFiles: additionalFiles, - RootFolderFiles: rootFolderFiles, - } - err := CheckSketchCasing(sketchFolderPath) - if e, ok := err.(*InvalidSketchFoldernameError); ok { - e.Sketch = sk - return nil, e + if err := sketch.importMetadata(); err != nil { + return nil, fmt.Errorf("importing sketch metadata: %s", err) } + return sketch, nil +} + +// supportedFiles reads all files recursively contained in Sketch and +// filter out unneded or unsupported ones and returns them +func (s *Sketch) supportedFiles() (*paths.PathList, error) { + files, err := s.FullPath.ReadDirRecursive() if err != nil { return nil, err } - return sk, nil + files.FilterOutDirs() + files.FilterOutHiddenFiles() + validExtensions := []string{} + for ext := range globals.MainFileValidExtensions { + validExtensions = append(validExtensions, ext) + } + for ext := range globals.AdditionalFileValidExtensions { + validExtensions = append(validExtensions, ext) + } + files.FilterSuffix(validExtensions...) + return &files, nil + +} + +// ImportMetadata imports metadata into the sketch from a sketch.json file in the root +// path of the sketch. +func (s *Sketch) importMetadata() error { + sketchJSON := s.FullPath.Join("sketch.json") + if sketchJSON.NotExist() { + // File doesn't exist, nothing to import + return nil + } + + content, err := sketchJSON.ReadFile() + if err != nil { + return fmt.Errorf("reading sketch metadata %s: %s", sketchJSON, err) + } + var meta Metadata + err = json.Unmarshal(content, &meta) + if err != nil { + if s.Metadata == nil { + s.Metadata = new(Metadata) + } + return fmt.Errorf("encoding sketch metadata: %s", err) + } + s.Metadata = &meta + return nil +} + +// ExportMetadata writes sketch metadata into a sketch.json file in the root path of +// the sketch +func (s *Sketch) ExportMetadata() error { + d, err := json.MarshalIndent(&s.Metadata, "", " ") + if err != nil { + return fmt.Errorf("decoding sketch metadata: %s", err) + } + + sketchJSON := s.FullPath.Join("sketch.json") + if err := sketchJSON.WriteFile(d); err != nil { + return fmt.Errorf("writing sketch metadata %s: %s", sketchJSON, err) + } + return nil } -// CheckSketchCasing returns an error if the casing of the sketch folder and the main file are different. +// checkSketchCasing returns an error if the casing of the sketch folder and the main file are different. // Correct: // MySketch/MySketch.ino // Wrong: @@ -152,33 +219,63 @@ func New(sketchFolderPath, mainFilePath, buildPath string, allFilesPaths []strin // // This is mostly necessary to avoid errors on Mac OS X. // For more info see: https://github.com/arduino/arduino-cli/issues/1174 -func CheckSketchCasing(sketchFolder string) error { - sketchPath := paths.New(sketchFolder) - files, err := sketchPath.ReadDir() +func (s *Sketch) checkSketchCasing() error { + files, err := s.FullPath.ReadDir() if err != nil { return errors.Errorf("reading files: %v", err) } files.FilterOutDirs() - sketchName := sketchPath.Base() - files.FilterPrefix(sketchName) + files.FilterPrefix(s.Name) if files.Len() == 0 { - sketchFolderPath := paths.New(sketchFolder) - sketchFile := sketchFolderPath.Join(sketchFolderPath.Base() + globals.MainFileValidExtension) - return &InvalidSketchFoldernameError{SketchFolder: sketchFolderPath, SketchFile: sketchFile} + sketchFile := s.FullPath.Join(s.Name + globals.MainFileValidExtension) + return &InvalidSketchFolderNameError{ + SketchFolder: s.FullPath, + SketchFile: sketchFile, + Sketch: s, + } } return nil } -// InvalidSketchFoldernameError is returned when the sketch directory doesn't match the sketch name -type InvalidSketchFoldernameError struct { +// InvalidSketchFolderNameError is returned when the sketch directory doesn't match the sketch name +type InvalidSketchFolderNameError struct { SketchFolder *paths.Path SketchFile *paths.Path Sketch *Sketch } -func (e *InvalidSketchFoldernameError) Error() string { +func (e *InvalidSketchFolderNameError) Error() string { return fmt.Sprintf("no valid sketch found in %s: missing %s", e.SketchFolder, e.SketchFile) } + +// CheckForPdeFiles returns all files ending with .pde extension +// in sketch, 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 +} + +// GenBuildPath generates a suitable name for the build folder. +// The sketchPath, if not nil, is also used to furhter differentiate build paths. +func GenBuildPath(sketchPath *paths.Path) *paths.Path { + path := "" + if sketchPath != nil { + path = sketchPath.String() + } + md5SumBytes := md5.Sum([]byte(path)) + md5Sum := strings.ToUpper(hex.EncodeToString(md5SumBytes[:])) + return paths.TempDir().Join("arduino-sketch-" + md5Sum) +} diff --git a/arduino/sketch/sketch_test.go b/arduino/sketch/sketch_test.go index 8136b679645..dc53727010e 100644 --- a/arduino/sketch/sketch_test.go +++ b/arduino/sketch/sketch_test.go @@ -17,8 +17,7 @@ package sketch import ( "fmt" - "path/filepath" - "sort" + "os" "testing" "github.com/arduino/go-paths-helper" @@ -26,149 +25,278 @@ import ( "github.com/stretchr/testify/require" ) -func TestNewItem(t *testing.T) { - sketchItem := filepath.Join("testdata", t.Name()+".ino") - item := NewItem(sketchItem) - assert.Equal(t, sketchItem, item.Path) - sourceBytes, err := item.GetSourceBytes() - assert.Nil(t, err) - assert.Equal(t, []byte(`#include `), sourceBytes) - sourceStr, err := item.GetSourceStr() +func TestNew(t *testing.T) { + sketchFolderPath := paths.New("testdata", "SketchSimple") + mainFilePath := sketchFolderPath.Join(fmt.Sprintf("%s.ino", "SketchSimple")) + otherFile := sketchFolderPath.Join("other.cpp") + + // Loading using Sketch folder path + sketch, err := New(sketchFolderPath) assert.Nil(t, err) - assert.Equal(t, "#include ", sourceStr) + assert.True(t, mainFilePath.EquivalentTo(sketch.MainFile)) + assert.True(t, sketchFolderPath.EquivalentTo(sketch.FullPath)) + assert.Equal(t, sketch.OtherSketchFiles.Len(), 0) + assert.Equal(t, sketch.AdditionalFiles.Len(), 1) + assert.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(otherFile)) + assert.Equal(t, sketch.RootFolderFiles.Len(), 1) + assert.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(otherFile)) - item = NewItem("doesnt/exist") - sourceBytes, err = item.GetSourceBytes() - assert.Nil(t, sourceBytes) - assert.NotNil(t, err) + // Loading using Sketch main file path + sketch, err = New(mainFilePath) + assert.Nil(t, err) + assert.True(t, mainFilePath.EquivalentTo(sketch.MainFile)) + assert.True(t, sketchFolderPath.EquivalentTo(sketch.FullPath)) + assert.Equal(t, sketch.OtherSketchFiles.Len(), 0) + assert.Equal(t, sketch.AdditionalFiles.Len(), 1) + assert.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(otherFile)) + assert.Equal(t, sketch.RootFolderFiles.Len(), 1) + assert.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(otherFile)) } -func TestSort(t *testing.T) { - items := []*Item{ - {"foo"}, - {"baz"}, - {"bar"}, - } +func TestNewSketchPde(t *testing.T) { + sketchFolderPath := paths.New("testdata", "SketchPde") + mainFilePath := sketchFolderPath.Join(fmt.Sprintf("%s.pde", "SketchPde")) - sort.Sort(ItemByPath(items)) + // Loading using Sketch folder path + sketch, err := New(sketchFolderPath) + assert.Nil(t, err) + assert.True(t, mainFilePath.EquivalentTo(sketch.MainFile)) + assert.True(t, sketchFolderPath.EquivalentTo(sketch.FullPath)) + assert.Equal(t, sketch.OtherSketchFiles.Len(), 0) + assert.Equal(t, sketch.AdditionalFiles.Len(), 0) + assert.Equal(t, sketch.RootFolderFiles.Len(), 0) - assert.Equal(t, "bar", items[0].Path) - assert.Equal(t, "baz", items[1].Path) - assert.Equal(t, "foo", items[2].Path) + // Loading using Sketch main file path + sketch, err = New(mainFilePath) + assert.Nil(t, err) + assert.True(t, mainFilePath.EquivalentTo(sketch.MainFile)) + assert.True(t, sketchFolderPath.EquivalentTo(sketch.FullPath)) + assert.Equal(t, sketch.OtherSketchFiles.Len(), 0) + assert.Equal(t, sketch.AdditionalFiles.Len(), 0) + assert.Equal(t, sketch.RootFolderFiles.Len(), 0) } -func TestNew(t *testing.T) { - sketchFolderPath := filepath.Join("testdata", t.Name()) - mainFilePath := filepath.Join(sketchFolderPath, t.Name()+".ino") - otherFile := filepath.Join(sketchFolderPath, "other.cpp") - allFilesPaths := []string{ - mainFilePath, - otherFile, - } - - sketch, err := New(sketchFolderPath, mainFilePath, "", allFilesPaths) - assert.Nil(t, err) - assert.Equal(t, mainFilePath, sketch.MainFile.Path) - assert.Equal(t, sketchFolderPath, sketch.LocationPath) - assert.Len(t, sketch.OtherSketchFiles, 0) - assert.Len(t, sketch.AdditionalFiles, 1) - assert.Equal(t, sketch.AdditionalFiles[0].Path, paths.New(sketchFolderPath).Join("other.cpp").String()) - assert.Len(t, sketch.RootFolderFiles, 1) - assert.Equal(t, sketch.RootFolderFiles[0].Path, paths.New(sketchFolderPath).Join("other.cpp").String()) +func TestNewSketchBothInoAndPde(t *testing.T) { + sketchName := "SketchBothInoAndPde" + sketchFolderPath := paths.New("testdata", sketchName) + sketch, err := New(sketchFolderPath) + require.Nil(t, sketch) + require.Error(t, err) + require.Contains(t, err.Error(), "multiple main sketch files found") + require.Contains(t, err.Error(), fmt.Sprintf("%s.ino", sketchName)) + require.Contains(t, err.Error(), fmt.Sprintf("%s.pde", sketchName)) +} + +func TestNewSketchWrongMain(t *testing.T) { + sketchName := "SketchWithWrongMain" + sketchFolderPath := paths.New("testdata", sketchName) + sketch, err := New(sketchFolderPath) + require.Nil(t, sketch) + require.Error(t, err) + sketchFolderPath, _ = sketchFolderPath.Abs() + expectedMainFile := sketchFolderPath.Join(sketchName) + expectedError := fmt.Sprintf("no valid sketch found in %s: missing %s", sketchFolderPath, expectedMainFile) + require.Contains(t, err.Error(), expectedError) + + sketchFolderPath = paths.New("testdata", sketchName) + mainFilePath := sketchFolderPath.Join(fmt.Sprintf("%s.ino", sketchName)) + sketch, err = New(mainFilePath) + require.Nil(t, sketch) + require.Error(t, err) + sketchFolderPath, _ = sketchFolderPath.Abs() + expectedError = fmt.Sprintf("no valid sketch found in %s: missing %s", sketchFolderPath, expectedMainFile) + require.Contains(t, err.Error(), expectedError) } func TestNewSketchCasingWrong(t *testing.T) { - sketchPath := paths.New("testdata", "SketchCasingWrong") - mainFilePath := sketchPath.Join("sketchcasingwrong.ino").String() - sketch, err := New(sketchPath.String(), mainFilePath, "", []string{mainFilePath}) + sketchPath := paths.New("testdata", "SketchWithWrongMain") + sketch, err := New(sketchPath) assert.Nil(t, sketch) assert.Error(t, err) - assert.IsType(t, &InvalidSketchFoldernameError{}, err) - e := err.(*InvalidSketchFoldernameError) + assert.IsType(t, &InvalidSketchFolderNameError{}, err) + e := err.(*InvalidSketchFolderNameError) assert.NotNil(t, e.Sketch) + sketchPath, _ = sketchPath.Abs() expectedError := fmt.Sprintf("no valid sketch found in %s: missing %s", sketchPath.String(), sketchPath.Join(sketchPath.Base()+".ino")) assert.EqualError(t, err, expectedError) } func TestNewSketchCasingCorrect(t *testing.T) { sketchPath := paths.New("testdata", "SketchCasingCorrect") - mainFilePath := sketchPath.Join("SketchCasingCorrect.ino").String() - sketch, err := New(sketchPath.String(), mainFilePath, "", []string{mainFilePath}) + mainFilePath := sketchPath.Join("SketchCasingCorrect.ino") + sketch, err := New(sketchPath) assert.NotNil(t, sketch) assert.NoError(t, err) - assert.Equal(t, sketchPath.String(), sketch.LocationPath) - assert.Equal(t, mainFilePath, sketch.MainFile.Path) - assert.Len(t, sketch.OtherSketchFiles, 0) - assert.Len(t, sketch.AdditionalFiles, 0) - assert.Len(t, sketch.RootFolderFiles, 0) -} - -func TestCheckSketchCasingWrong(t *testing.T) { - sketchFolder := paths.New("testdata", "SketchCasingWrong") - err := CheckSketchCasing(sketchFolder.String()) - expectedError := fmt.Sprintf("no valid sketch found in %s: missing %s", sketchFolder, sketchFolder.Join(sketchFolder.Base()+".ino")) - assert.EqualError(t, err, expectedError) -} - -func TestCheckSketchCasingCorrect(t *testing.T) { - sketchFolder := paths.New("testdata", "SketchCasingCorrect").String() - err := CheckSketchCasing(sketchFolder) - require.NoError(t, err) + assert.True(t, sketchPath.EquivalentTo(sketch.FullPath)) + assert.True(t, mainFilePath.EquivalentTo(sketch.MainFile)) + assert.Equal(t, sketch.OtherSketchFiles.Len(), 0) + assert.Equal(t, sketch.AdditionalFiles.Len(), 0) + assert.Equal(t, sketch.RootFolderFiles.Len(), 0) } func TestSketchWithMarkdownAsciidocJson(t *testing.T) { sketchPath := paths.New("testdata", "SketchWithMarkdownAsciidocJson") - mainFilePath := sketchPath.Join("SketchWithMarkdownAsciidocJson.ino").String() - adocFilePath := sketchPath.Join("foo.adoc").String() - jsonFilePath := sketchPath.Join("foo.json").String() - mdFilePath := sketchPath.Join("foo.md").String() + mainFilePath := sketchPath.Join("SketchWithMarkdownAsciidocJson.ino") + adocFilePath := sketchPath.Join("foo.adoc") + jsonFilePath := sketchPath.Join("foo.json") + mdFilePath := sketchPath.Join("foo.md") - sketch, err := New(sketchPath.String(), mainFilePath, "", []string{mainFilePath, adocFilePath, jsonFilePath, mdFilePath}) + sketch, err := New(sketchPath) assert.NotNil(t, sketch) assert.NoError(t, err) - assert.Equal(t, sketchPath.String(), sketch.LocationPath) - assert.Equal(t, mainFilePath, sketch.MainFile.Path) - assert.Len(t, sketch.OtherSketchFiles, 0) - require.Len(t, sketch.AdditionalFiles, 3) - require.Equal(t, "foo.adoc", filepath.Base(sketch.AdditionalFiles[0].Path)) - require.Equal(t, "foo.json", filepath.Base(sketch.AdditionalFiles[1].Path)) - require.Equal(t, "foo.md", filepath.Base(sketch.AdditionalFiles[2].Path)) - assert.Len(t, sketch.RootFolderFiles, 3) - require.Equal(t, "foo.adoc", filepath.Base(sketch.RootFolderFiles[0].Path)) - require.Equal(t, "foo.json", filepath.Base(sketch.RootFolderFiles[1].Path)) - require.Equal(t, "foo.md", filepath.Base(sketch.RootFolderFiles[2].Path)) + assert.True(t, sketchPath.EquivalentTo(sketch.FullPath)) + assert.True(t, mainFilePath.EquivalentTo(sketch.MainFile)) + assert.Equal(t, sketch.OtherSketchFiles.Len(), 0) + require.Equal(t, sketch.AdditionalFiles.Len(), 3) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(adocFilePath)) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(jsonFilePath)) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(mdFilePath)) + assert.Equal(t, sketch.RootFolderFiles.Len(), 3) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(adocFilePath)) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(jsonFilePath)) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(mdFilePath)) } func TestSketchWithTppFile(t *testing.T) { sketchPath := paths.New("testdata", "SketchWithTppFile") - mainFilePath := sketchPath.Join("SketchWithTppFile.ino").String() - templateFile := sketchPath.Join("template.tpp").String() + mainFilePath := sketchPath.Join("SketchWithTppFile.ino") + templateFile := sketchPath.Join("template.tpp") - sketch, err := New(sketchPath.String(), mainFilePath, "", []string{mainFilePath, templateFile}) + sketch, err := New(sketchPath) require.NotNil(t, sketch) require.NoError(t, err) - require.Equal(t, sketchPath.String(), sketch.LocationPath) - require.Equal(t, mainFilePath, sketch.MainFile.Path) - require.Len(t, sketch.OtherSketchFiles, 0) - require.Len(t, sketch.AdditionalFiles, 1) - require.Equal(t, "template.tpp", filepath.Base(sketch.AdditionalFiles[0].Path)) - require.Len(t, sketch.RootFolderFiles, 1) - require.Equal(t, "template.tpp", filepath.Base(sketch.RootFolderFiles[0].Path)) + require.True(t, sketchPath.EquivalentTo(sketch.FullPath)) + require.True(t, mainFilePath.EquivalentTo(sketch.MainFile)) + require.Equal(t, sketch.OtherSketchFiles.Len(), 0) + require.Equal(t, sketch.AdditionalFiles.Len(), 1) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(templateFile)) + require.Equal(t, sketch.RootFolderFiles.Len(), 1) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(templateFile)) } func TestSketchWithIppFile(t *testing.T) { sketchPath := paths.New("testdata", "SketchWithIppFile") - mainFilePath := sketchPath.Join("SketchWithIppFile.ino").String() - templateFile := sketchPath.Join("template.ipp").String() + mainFilePath := sketchPath.Join("SketchWithIppFile.ino") + templateFile := sketchPath.Join("template.ipp") - sketch, err := New(sketchPath.String(), mainFilePath, "", []string{mainFilePath, templateFile}) + sketch, err := New(sketchPath) require.NotNil(t, sketch) require.NoError(t, err) - require.Equal(t, sketchPath.String(), sketch.LocationPath) - require.Equal(t, mainFilePath, sketch.MainFile.Path) - require.Len(t, sketch.OtherSketchFiles, 0) - require.Len(t, sketch.AdditionalFiles, 1) - require.Equal(t, "template.ipp", filepath.Base(sketch.AdditionalFiles[0].Path)) - require.Len(t, sketch.RootFolderFiles, 1) - require.Equal(t, "template.ipp", filepath.Base(sketch.RootFolderFiles[0].Path)) + require.True(t, sketchPath.EquivalentTo(sketch.FullPath)) + require.True(t, mainFilePath.EquivalentTo(sketch.MainFile)) + require.Equal(t, sketch.OtherSketchFiles.Len(), 0) + require.Equal(t, sketch.AdditionalFiles.Len(), 1) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(templateFile)) + require.Equal(t, sketch.RootFolderFiles.Len(), 1) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(templateFile)) +} + +func TestNewSketchFolderSymlink(t *testing.T) { + // pass the path to the sketch folder + sketchName := "SketchSymlink" + sketchPath, _ := paths.New("testdata", fmt.Sprintf("%sSrc", sketchName)).Abs() + sketchPathSymlink, _ := paths.New("testdata", sketchName).Abs() + os.Symlink(sketchPath.String(), sketchPathSymlink.String()) + defer sketchPathSymlink.Remove() + + mainFilePath := sketchPathSymlink.Join(fmt.Sprintf("%sSrc.ino", sketchName)) + sketch, err := New(sketchPathSymlink) + require.Nil(t, err) + require.NotNil(t, sketch) + require.True(t, sketch.MainFile.EquivalentTo(mainFilePath)) + require.True(t, sketch.FullPath.EquivalentTo(sketchPath)) + require.True(t, sketch.FullPath.EquivalentTo(sketchPathSymlink)) + require.Equal(t, sketch.OtherSketchFiles.Len(), 2) + require.True(t, sketch.OtherSketchFiles.ContainsEquivalentTo(sketchPath.Join("old.pde"))) + require.True(t, sketch.OtherSketchFiles.ContainsEquivalentTo(sketchPath.Join("other.ino"))) + require.True(t, sketch.OtherSketchFiles.ContainsEquivalentTo(sketchPathSymlink.Join("old.pde"))) + require.True(t, sketch.OtherSketchFiles.ContainsEquivalentTo(sketchPathSymlink.Join("other.ino"))) + require.Equal(t, sketch.AdditionalFiles.Len(), 3) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPath.Join("header.h"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPath.Join("s_file.S"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPath.Join("src", "helper.h"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPathSymlink.Join("header.h"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPathSymlink.Join("s_file.S"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPathSymlink.Join("src", "helper.h"))) + require.Equal(t, sketch.RootFolderFiles.Len(), 4) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPath.Join("header.h"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPath.Join("old.pde"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPath.Join("other.ino"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPath.Join("s_file.S"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPathSymlink.Join("header.h"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPathSymlink.Join("old.pde"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPathSymlink.Join("other.ino"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPathSymlink.Join("s_file.S"))) + + // pass the path to the main file + sketch, err = New(mainFilePath) + require.Nil(t, err) + require.NotNil(t, sketch) + require.True(t, sketch.MainFile.EquivalentTo(mainFilePath)) + require.True(t, sketch.FullPath.EquivalentTo(sketchPath)) + require.True(t, sketch.FullPath.EquivalentTo(sketchPathSymlink)) + require.Equal(t, sketch.OtherSketchFiles.Len(), 2) + require.True(t, sketch.OtherSketchFiles.ContainsEquivalentTo(sketchPath.Join("old.pde"))) + require.True(t, sketch.OtherSketchFiles.ContainsEquivalentTo(sketchPath.Join("other.ino"))) + require.True(t, sketch.OtherSketchFiles.ContainsEquivalentTo(sketchPathSymlink.Join("old.pde"))) + require.True(t, sketch.OtherSketchFiles.ContainsEquivalentTo(sketchPathSymlink.Join("other.ino"))) + require.Equal(t, sketch.AdditionalFiles.Len(), 3) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPath.Join("header.h"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPath.Join("s_file.S"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPath.Join("src", "helper.h"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPathSymlink.Join("header.h"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPathSymlink.Join("s_file.S"))) + require.True(t, sketch.AdditionalFiles.ContainsEquivalentTo(sketchPathSymlink.Join("src", "helper.h"))) + require.Equal(t, sketch.RootFolderFiles.Len(), 4) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPath.Join("header.h"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPath.Join("old.pde"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPath.Join("other.ino"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPath.Join("s_file.S"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPathSymlink.Join("header.h"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPathSymlink.Join("old.pde"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPathSymlink.Join("other.ino"))) + require.True(t, sketch.RootFolderFiles.ContainsEquivalentTo(sketchPathSymlink.Join("s_file.S"))) +} + +func TestGenBuildPath(t *testing.T) { + want := paths.TempDir().Join("arduino-sketch-ACBD18DB4CC2F85CEDEF654FCCC4A4D8") + assert.True(t, GenBuildPath(paths.New("foo")).EquivalentTo(want)) + + want = paths.TempDir().Join("arduino-sketch-D41D8CD98F00B204E9800998ECF8427E") + assert.True(t, GenBuildPath(nil).EquivalentTo(want)) +} + +func TestCheckForPdeFiles(t *testing.T) { + sketchPath := paths.New("testdata", "SketchSimple") + 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", "SketchSimple", "SketchSimple.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/SketchCasingCorrect/SketchCasingCorrect.ino b/arduino/sketch/testdata/SketchBothInoAndPde/SketchBothInoAndPde.ino similarity index 100% rename from arduino/sketches/testdata/SketchCasingCorrect/SketchCasingCorrect.ino rename to arduino/sketch/testdata/SketchBothInoAndPde/SketchBothInoAndPde.ino diff --git a/arduino/sketches/testdata/SketchCasingWrong/sketchcasingwrong.ino b/arduino/sketch/testdata/SketchBothInoAndPde/SketchBothInoAndPde.pde similarity index 100% rename from arduino/sketches/testdata/SketchCasingWrong/sketchcasingwrong.ino rename to arduino/sketch/testdata/SketchBothInoAndPde/SketchBothInoAndPde.pde diff --git a/arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.ino b/arduino/sketch/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.ino similarity index 100% rename from arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.ino rename to arduino/sketch/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.ino diff --git a/arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.pde b/arduino/sketch/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.pde similarity index 100% rename from arduino/sketches/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.pde rename to arduino/sketch/testdata/SketchMultipleMainFiles/SketchMultipleMainFiles.pde diff --git a/arduino/sketches/testdata/SketchPde/SketchPde.pde b/arduino/sketch/testdata/SketchPde/SketchPde.pde similarity index 100% rename from arduino/sketches/testdata/SketchPde/SketchPde.pde rename to arduino/sketch/testdata/SketchPde/SketchPde.pde diff --git a/arduino/sketch/testdata/TestNew/TestNew.ino b/arduino/sketch/testdata/SketchSimple/SketchSimple.ino similarity index 100% rename from arduino/sketch/testdata/TestNew/TestNew.ino rename to arduino/sketch/testdata/SketchSimple/SketchSimple.ino diff --git a/arduino/sketch/testdata/TestNew/other.cpp b/arduino/sketch/testdata/SketchSimple/other.cpp similarity index 100% rename from arduino/sketch/testdata/TestNew/other.cpp rename to arduino/sketch/testdata/SketchSimple/other.cpp diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/.#sketch.ino b/arduino/sketch/testdata/SketchSymlinkSrc/.#sketch.ino new file mode 100644 index 00000000000..71048175432 --- /dev/null +++ b/arduino/sketch/testdata/SketchSymlinkSrc/.#sketch.ino @@ -0,0 +1,2 @@ +void setup() +void loop) } \ No newline at end of file diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/SketchSymlinkSrc.ino b/arduino/sketch/testdata/SketchSymlinkSrc/SketchSymlinkSrc.ino new file mode 100644 index 00000000000..32f56baab79 --- /dev/null +++ b/arduino/sketch/testdata/SketchSymlinkSrc/SketchSymlinkSrc.ino @@ -0,0 +1,7 @@ +void setup() { + +} + +void loop() { + +} diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/doc.txt b/arduino/sketch/testdata/SketchSymlinkSrc/doc.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/header.h b/arduino/sketch/testdata/SketchSymlinkSrc/header.h new file mode 100644 index 00000000000..0e7d3b1a6a9 --- /dev/null +++ b/arduino/sketch/testdata/SketchSymlinkSrc/header.h @@ -0,0 +1 @@ +#define FOO "BAR" \ No newline at end of file diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/old.pde b/arduino/sketch/testdata/SketchSymlinkSrc/old.pde new file mode 100644 index 00000000000..e69de29bb2d diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/other.ino b/arduino/sketch/testdata/SketchSymlinkSrc/other.ino new file mode 100644 index 00000000000..c426196c017 --- /dev/null +++ b/arduino/sketch/testdata/SketchSymlinkSrc/other.ino @@ -0,0 +1,3 @@ +String hello() { + return "world"; +} \ No newline at end of file diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/s_file.S b/arduino/sketch/testdata/SketchSymlinkSrc/s_file.S new file mode 100644 index 00000000000..e69de29bb2d diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/src/dont_load_me.ino b/arduino/sketch/testdata/SketchSymlinkSrc/src/dont_load_me.ino new file mode 100644 index 00000000000..46b07018d09 --- /dev/null +++ b/arduino/sketch/testdata/SketchSymlinkSrc/src/dont_load_me.ino @@ -0,0 +1,2 @@ +#include +#error "Whattya looking at?" diff --git a/arduino/sketch/testdata/SketchSymlinkSrc/src/helper.h b/arduino/sketch/testdata/SketchSymlinkSrc/src/helper.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/arduino/sketches/testdata/Sketch1/Sketch1.ino b/arduino/sketch/testdata/SketchWithWrongMain/main.ino similarity index 96% rename from arduino/sketches/testdata/Sketch1/Sketch1.ino rename to arduino/sketch/testdata/SketchWithWrongMain/main.ino index 5054c040393..660bdbccfdb 100644 --- a/arduino/sketches/testdata/Sketch1/Sketch1.ino +++ b/arduino/sketch/testdata/SketchWithWrongMain/main.ino @@ -1,3 +1,2 @@ - void setup() {} void loop() {} diff --git a/arduino/sketches/sketches.go b/arduino/sketches/sketches.go deleted file mode 100644 index bc15dfb9762..00000000000 --- a/arduino/sketches/sketches.go +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) -// -// This software is released under the GNU General Public License version 3, -// which covers the main part of arduino-cli. -// The terms of this license can be found at: -// https://www.gnu.org/licenses/gpl-3.0.en.html -// -// You can be released from the requirements of the above licenses by purchasing -// a commercial license. Buying such a license is mandatory if you want to -// modify or otherwise use the software for commercial activities involving the -// Arduino software without disclosing the source code of your own applications. -// To purchase a commercial license, send an email to license@arduino.cc. - -package sketches - -import ( - "encoding/json" - "fmt" - - "github.com/arduino/arduino-cli/arduino/builder" - "github.com/arduino/arduino-cli/arduino/globals" - "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/go-paths-helper" - "github.com/pkg/errors" -) - -// Sketch is a sketch for Arduino -type Sketch struct { - Name string - MainFileExtension string - FullPath *paths.Path - Metadata *Metadata -} - -// Metadata is the kind of data associated to a project such as the connected board -type Metadata struct { - CPU BoardMetadata `json:"cpu,omitempty" gorethink:"cpu"` -} - -// BoardMetadata represents the board metadata for the sketch -type BoardMetadata struct { - Fqbn string `json:"fqbn,required"` - Name string `json:"name,omitempty"` - Port string `json:"port,omitepty"` -} - -// NewSketchFromPath loads a sketch from the specified path -func NewSketchFromPath(path *paths.Path) (*Sketch, error) { - path, err := path.Abs() - if err != nil { - return nil, errors.Errorf("getting sketch path: %s", err) - } - if !path.IsDir() { - path = path.Parent() - } - - 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 || sketch.CheckSketchCasing(path.String()) != nil { - sketchFile := path.Join(path.Base() + globals.MainFileValidExtension) - return nil, errors.Errorf("no valid sketch found in %s: missing %s", path, sketchFile) - } - - s := &Sketch{ - FullPath: path, - MainFileExtension: mainSketchFile.Ext(), - Name: path.Base(), - Metadata: &Metadata{}, - } - s.ImportMetadata() - return s, nil -} - -// ImportMetadata imports metadata into the sketch from a sketch.json file in the root -// path of the sketch. -func (s *Sketch) ImportMetadata() error { - sketchJSON := s.FullPath.Join("sketch.json") - content, err := sketchJSON.ReadFile() - if err != nil { - return fmt.Errorf("reading sketch metadata %s: %s", sketchJSON, err) - } - var meta Metadata - err = json.Unmarshal(content, &meta) - if err != nil { - if s.Metadata == nil { - s.Metadata = new(Metadata) - } - return fmt.Errorf("encoding sketch metadata: %s", err) - } - s.Metadata = &meta - return nil -} - -// ExportMetadata writes sketch metadata into a sketch.json file in the root path of -// the sketch -func (s *Sketch) ExportMetadata() error { - d, err := json.MarshalIndent(&s.Metadata, "", " ") - if err != nil { - return fmt.Errorf("decoding sketch metadata: %s", err) - } - - sketchJSON := s.FullPath.Join("sketch.json") - if err := sketchJSON.WriteFile(d); err != nil { - return fmt.Errorf("writing sketch metadata %s: %s", sketchJSON, err) - } - return nil -} - -// BuildPath returns this Sketch build path in the temp directory of the system. -// Returns an error if the Sketch's FullPath is not set -func (s *Sketch) BuildPath() (*paths.Path, error) { - if s.FullPath == nil { - return nil, fmt.Errorf("sketch path is empty") - } - 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 deleted file mode 100644 index ad65df39c0b..00000000000 --- a/arduino/sketches/sketches_test.go +++ /dev/null @@ -1,132 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) -// -// This software is released under the GNU General Public License version 3, -// which covers the main part of arduino-cli. -// The terms of this license can be found at: -// https://www.gnu.org/licenses/gpl-3.0.en.html -// -// You can be released from the requirements of the above licenses by purchasing -// a commercial license. Buying such a license is mandatory if you want to -// modify or otherwise use the software for commercial activities involving the -// Arduino software without disclosing the source code of your own applications. -// To purchase a commercial license, send an email to license@arduino.cc. - -package sketches - -import ( - "fmt" - "testing" - - "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" -) - -func TestSketchLoadingFromFolderOrMainFile(t *testing.T) { - skFolder := paths.New("testdata/Sketch1") - skMainIno := skFolder.Join("Sketch1.ino") - - { - sk, err := NewSketchFromPath(skFolder) - require.NoError(t, err) - require.Equal(t, sk.Name, "Sketch1") - fmt.Println(sk.FullPath.String(), "==", skFolder.String()) - require.True(t, sk.FullPath.EquivalentTo(skFolder)) - } - - { - sk, err := NewSketchFromPath(skMainIno) - require.NoError(t, err) - require.Equal(t, sk.Name, "Sketch1") - fmt.Println(sk.FullPath.String(), "==", skFolder.String()) - require.True(t, sk.FullPath.EquivalentTo(skFolder)) - } -} - -func TestSketchBuildPath(t *testing.T) { - // Verifies build path is returned if sketch path is set - sketchPath := paths.New("testdata/Sketch1") - sketch, err := NewSketchFromPath(sketchPath) - require.NoError(t, err) - buildPath, err := sketch.BuildPath() - 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]) -} - -func TestSketchLoadWithCasing(t *testing.T) { - sketchFolder := paths.New("testdata", "SketchCasingWrong") - - sketch, err := NewSketchFromPath(sketchFolder) - require.Nil(t, sketch) - - sketchFolderAbs, _ := sketchFolder.Abs() - sketchMainFileAbs := sketchFolderAbs.Join("SketchCasingWrong.ino") - expectedError := fmt.Sprintf("no valid sketch found in %s: missing %s", sketchFolderAbs, sketchMainFileAbs) - require.EqualError(t, err, expectedError) -} - -func TestSketchLoadingCorrectCasing(t *testing.T) { - sketchFolder := paths.New("testdata", "SketchCasingCorrect") - sketch, err := NewSketchFromPath(sketchFolder) - require.NotNil(t, sketch) - require.NoError(t, err) - require.Equal(t, sketch.Name, "SketchCasingCorrect") - require.True(t, sketch.FullPath.EquivalentTo(sketchFolder)) -} diff --git a/cli/compile/compile.go b/cli/compile/compile.go index 73f479507be..eac43f41150 100644 --- a/cli/compile/compile.go +++ b/cli/compile/compile.go @@ -21,7 +21,7 @@ import ( "encoding/json" "os" - "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/configuration" @@ -130,7 +130,7 @@ 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 { + if files := sketch.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) diff --git a/cli/sketch/archive.go b/cli/sketch/archive.go index 940f0e6c0fc..4b7c07b03dc 100644 --- a/cli/sketch/archive.go +++ b/cli/sketch/archive.go @@ -19,10 +19,10 @@ import ( "context" "os" - "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" - "github.com/arduino/arduino-cli/commands/sketch" + sk "github.com/arduino/arduino-cli/commands/sketch" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" "github.com/sirupsen/logrus" @@ -55,13 +55,13 @@ func initArchiveCommand() *cobra.Command { func runArchiveCommand(cmd *cobra.Command, args []string) { logrus.Info("Executing `arduino sketch archive`") - sketchPath := "." + sketchPath := paths.New(".") if len(args) >= 1 { - sketchPath = args[0] + sketchPath = paths.New(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 { + if files := sketch.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) @@ -73,9 +73,9 @@ func runArchiveCommand(cmd *cobra.Command, args []string) { archivePath = args[1] } - _, err := sketch.ArchiveSketch(context.Background(), + _, err := sk.ArchiveSketch(context.Background(), &rpc.ArchiveSketchRequest{ - SketchPath: sketchPath, + SketchPath: sketchPath.String(), ArchivePath: archivePath, IncludeBuildDir: includeBuildDir, }) diff --git a/cli/upload/upload.go b/cli/upload/upload.go index 9a89c4efd9f..7d0f69f6b52 100644 --- a/cli/upload/upload.go +++ b/cli/upload/upload.go @@ -19,7 +19,7 @@ import ( "context" "os" - "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/instance" @@ -82,7 +82,7 @@ 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 { + if files := sketch.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) diff --git a/commands/board/attach.go b/commands/board/attach.go index f5bd4017eaa..32b8e2e53a8 100644 --- a/commands/board/attach.go +++ b/commands/board/attach.go @@ -25,7 +25,7 @@ import ( "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" - "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/commands" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" discovery "github.com/arduino/board-discovery" @@ -42,7 +42,7 @@ func Attach(ctx context.Context, req *rpc.BoardAttachRequest, taskCB commands.Ta if req.GetSketchPath() != "" { sketchPath = paths.New(req.GetSketchPath()) } - sketch, err := sketches.NewSketchFromPath(sketchPath) + sk, err := sketch.New(sketchPath) if err != nil { return nil, fmt.Errorf("opening sketch: %s", err) } @@ -54,7 +54,7 @@ func Attach(ctx context.Context, req *rpc.BoardAttachRequest, taskCB commands.Ta } if fqbn != nil { - sketch.Metadata.CPU = sketches.BoardMetadata{ + sk.Metadata.CPU = sketch.BoardMetadata{ Fqbn: fqbn.String(), } } else { @@ -92,18 +92,18 @@ func Attach(ctx context.Context, req *rpc.BoardAttachRequest, taskCB commands.Ta // TODO: should be stoped the monitor: when running as a pure CLI is released // by the OS, when run as daemon the resource's state is unknown and could be leaked. - sketch.Metadata.CPU = sketches.BoardMetadata{ + sk.Metadata.CPU = sketch.BoardMetadata{ Fqbn: board.FQBN(), Name: board.Name(), Port: deviceURI.String(), } } - err = sketch.ExportMetadata() + err = sk.ExportMetadata() if err != nil { return nil, fmt.Errorf("cannot export sketch metadata: %s", err) } - taskCB(&rpc.TaskProgress{Name: "Selected fqbn: " + sketch.Metadata.CPU.Fqbn, Completed: true}) + taskCB(&rpc.TaskProgress{Name: "Selected fqbn: " + sk.Metadata.CPU.Fqbn, Completed: true}) return &rpc.BoardAttachResponse{}, nil } diff --git a/commands/compile/compile.go b/commands/compile/compile.go index 79d8a6b6fc9..4a884e600ca 100644 --- a/commands/compile/compile.go +++ b/commands/compile/compile.go @@ -27,7 +27,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/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/configuration" "github.com/arduino/arduino-cli/legacy/builder" @@ -95,14 +95,14 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream return nil, fmt.Errorf("missing sketchPath") } sketchPath := paths.New(req.GetSketchPath()) - sketch, err := sketches.NewSketchFromPath(sketchPath) + sk, err := sketch.New(sketchPath) if err != nil { return nil, fmt.Errorf("opening sketch: %s", err) } fqbnIn := req.GetFqbn() - if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { - fqbnIn = sketch.Metadata.CPU.Fqbn + if fqbnIn == "" && sk != nil && sk.Metadata != nil { + fqbnIn = sk.Metadata.CPU.Fqbn } if fqbnIn == "" { return nil, fmt.Errorf("no FQBN provided") @@ -128,7 +128,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream builderCtx := &types.Context{} builderCtx.PackageManager = pm builderCtx.FQBN = fqbn - builderCtx.SketchLocation = sketch.FullPath + builderCtx.SketchLocation = sk.FullPath // FIXME: This will be redundant when arduino-builder will be part of the cli builderCtx.HardwareDirs = configuration.HardwareDirectories(configuration.Settings) @@ -140,7 +140,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream builderCtx.LibraryDirs = paths.NewPathList(req.Library...) if req.GetBuildPath() == "" { - builderCtx.BuildPath = bldr.GenBuildPath(sketch.FullPath) + builderCtx.BuildPath = sk.BuildPath } else { builderCtx.BuildPath = paths.New(req.GetBuildPath()) } @@ -243,7 +243,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream } else { // Add FQBN (without configs part) to export path fqbnSuffix := strings.Replace(fqbn.StringWithoutConfig(), ":", ".", -1) - exportPath = sketch.FullPath.Join("build", fqbnSuffix) + exportPath = sk.FullPath.Join("build", fqbnSuffix) } logrus.WithField("path", exportPath).Trace("Saving sketch to export path.") if err := exportPath.MkdirAll(); err != nil { @@ -281,7 +281,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream importedLibs = append(importedLibs, rpcLib) } - logrus.Tracef("Compile %s for %s successful", sketch.Name, fqbnIn) + logrus.Tracef("Compile %s for %s successful", sk.Name, fqbnIn) return &rpc.CompileResponse{ UsedLibraries: importedLibs, diff --git a/commands/debug/debug_info.go b/commands/debug/debug_info.go index 76b39145f3b..d3bdf949b02 100644 --- a/commands/debug/debug_info.go +++ b/commands/debug/debug_info.go @@ -22,7 +22,7 @@ import ( "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" - "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/debug/v1" "github.com/arduino/go-paths-helper" @@ -47,15 +47,15 @@ func getDebugProperties(req *debug.DebugConfigRequest, pm *packagemanager.Packag return nil, fmt.Errorf("missing sketchPath") } sketchPath := paths.New(req.GetSketchPath()) - sketch, err := sketches.NewSketchFromPath(sketchPath) + sk, err := sketch.New(sketchPath) if err != nil { return nil, errors.Wrap(err, "opening sketch") } // XXX Remove this code duplication!! fqbnIn := req.GetFqbn() - if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { - fqbnIn = sketch.Metadata.CPU.Fqbn + if fqbnIn == "" && sk != nil && sk.Metadata != nil { + fqbnIn = sk.Metadata.CPU.Fqbn } if fqbnIn == "" { return nil, fmt.Errorf("no Fully Qualified Board Name provided") @@ -115,15 +115,9 @@ func getDebugProperties(req *debug.DebugConfigRequest, pm *packagemanager.Packag } } - var importPath *paths.Path + importPath := sk.BuildPath if importDir := req.GetImportDir(); importDir != "" { importPath = paths.New(importDir) - } else { - // TODO: Create a function to obtain importPath from sketch - importPath, err = sketch.BuildPath() - if err != nil { - return nil, fmt.Errorf("can't find build path for sketch: %v", err) - } } if !importPath.Exist() { return nil, fmt.Errorf("compiled sketch not found in %s", importPath) @@ -132,7 +126,7 @@ func getDebugProperties(req *debug.DebugConfigRequest, pm *packagemanager.Packag return nil, fmt.Errorf("expected compiled sketch in directory %s, but is a file instead", importPath) } toolProperties.SetPath("build.path", importPath) - toolProperties.Set("build.project_name", sketch.Name+".ino") + toolProperties.Set("build.project_name", sk.Name+".ino") // Set debug port property port := req.GetPort() diff --git a/commands/instances.go b/commands/instances.go index c2657daac9d..28a541a2285 100644 --- a/commands/instances.go +++ b/commands/instances.go @@ -23,7 +23,6 @@ import ( "os" "path" - "github.com/arduino/arduino-cli/arduino/builder" "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packageindex" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" @@ -31,6 +30,7 @@ import ( "github.com/arduino/arduino-cli/arduino/libraries/librariesindex" "github.com/arduino/arduino-cli/arduino/libraries/librariesmanager" "github.com/arduino/arduino-cli/arduino/security" + sk "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/arduino/utils" "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/configuration" @@ -842,29 +842,30 @@ func Upgrade(ctx context.Context, req *rpc.UpgradeRequest, downloadCB DownloadPr // LoadSketch collects and returns all files composing a sketch func LoadSketch(ctx context.Context, req *rpc.LoadSketchRequest) (*rpc.LoadSketchResponse, error) { - sketch, err := builder.SketchLoad(req.SketchPath, "") + // TODO: This a ToRpc function for the Sketch struct + sketch, err := sk.New(paths.New(req.SketchPath)) if err != nil { - return nil, fmt.Errorf("Error loading sketch %v: %v", req.SketchPath, err) + return nil, fmt.Errorf("error loading sketch %v: %v", req.SketchPath, err) } - otherSketchFiles := make([]string, len(sketch.OtherSketchFiles)) - for i, file := range sketch.OtherSketchFiles { - otherSketchFiles[i] = file.Path + otherSketchFiles := make([]string, sketch.OtherSketchFiles.Len()) + for i, file := range *sketch.OtherSketchFiles { + otherSketchFiles[i] = file.String() } - additionalFiles := make([]string, len(sketch.AdditionalFiles)) - for i, file := range sketch.AdditionalFiles { - additionalFiles[i] = file.Path + additionalFiles := make([]string, sketch.AdditionalFiles.Len()) + for i, file := range *sketch.AdditionalFiles { + additionalFiles[i] = file.String() } - rootFolderFiles := make([]string, len(sketch.RootFolderFiles)) - for i, file := range sketch.RootFolderFiles { - rootFolderFiles[i] = file.Path + rootFolderFiles := make([]string, sketch.RootFolderFiles.Len()) + for i, file := range *sketch.RootFolderFiles { + rootFolderFiles[i] = file.String() } return &rpc.LoadSketchResponse{ - MainFile: sketch.MainFile.Path, - LocationPath: sketch.LocationPath, + MainFile: sketch.MainFile.String(), + LocationPath: sketch.FullPath.String(), OtherSketchFiles: otherSketchFiles, AdditionalFiles: additionalFiles, RootFolderFiles: rootFolderFiles, diff --git a/commands/sketch/archive.go b/commands/sketch/archive.go index a388eee61dc..79e58973068 100644 --- a/commands/sketch/archive.go +++ b/commands/sketch/archive.go @@ -23,7 +23,7 @@ import ( "path/filepath" "strings" - "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" ) @@ -38,13 +38,13 @@ func ArchiveSketch(ctx context.Context, req *rpc.ArchiveSketchRequest) (*rpc.Arc sketchPath = paths.New(".") } - sketch, err := sketches.NewSketchFromPath(sketchPath) + s, err := sketch.New(sketchPath) if err != nil { return nil, err } - sketchPath = sketch.FullPath - sketchName = sketch.Name + sketchPath = s.FullPath + sketchName = s.Name archivePath := paths.New(req.ArchivePath) if archivePath == nil { diff --git a/commands/upload/upload.go b/commands/upload/upload.go index 0299d716fc7..859c9489860 100644 --- a/commands/upload/upload.go +++ b/commands/upload/upload.go @@ -23,12 +23,11 @@ import ( "path/filepath" "strings" - 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/arduino/sketch" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/executils" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" @@ -45,7 +44,7 @@ func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, er // TODO: make a generic function to extract sketch from request // and remove duplication in commands/compile.go sketchPath := paths.New(req.GetSketchPath()) - sketch, err := sketches.NewSketchFromPath(sketchPath) + sk, err := sketch.New(sketchPath) if err != nil && req.GetImportDir() == "" && req.GetImportFile() == "" { return nil, fmt.Errorf("opening sketch: %s", err) } @@ -54,7 +53,7 @@ func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, er err = runProgramAction( pm, - sketch, + sk, req.GetImportFile(), req.GetImportDir(), req.GetFqbn(), @@ -95,7 +94,7 @@ func UsingProgrammer(ctx context.Context, req *rpc.UploadUsingProgrammerRequest, } func runProgramAction(pm *packagemanager.PackageManager, - sketch *sketches.Sketch, + sk *sketch.Sketch, importFile, importDir, fqbnIn, port string, programmerID string, verbose, verify, burnBootloader bool, @@ -107,8 +106,8 @@ func runProgramAction(pm *packagemanager.PackageManager, } // FIXME: make a specification on how a port is specified via command line - if port == "" && sketch != nil && sketch.Metadata != nil { - deviceURI, err := url.Parse(sketch.Metadata.CPU.Port) + if port == "" && sk != nil && sk.Metadata != nil { + deviceURI, err := url.Parse(sk.Metadata.CPU.Port) if err != nil { return fmt.Errorf("invalid Device URL format: %s", err) } @@ -118,8 +117,8 @@ func runProgramAction(pm *packagemanager.PackageManager, } logrus.WithField("port", port).Tracef("Upload port") - if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { - fqbnIn = sketch.Metadata.CPU.Fqbn + if fqbnIn == "" && sk != nil && sk.Metadata != nil { + fqbnIn = sk.Metadata.CPU.Fqbn } if fqbnIn == "" { return fmt.Errorf("no Fully Qualified Board Name provided") @@ -276,7 +275,7 @@ func runProgramAction(pm *packagemanager.PackageManager, } if !burnBootloader { - importPath, sketchName, err := determineBuildPathAndSketchName(importFile, importDir, sketch, fqbn) + importPath, sketchName, err := determineBuildPathAndSketchName(importFile, importDir, sk, fqbn) if err != nil { return errors.Errorf("retrieving build artifacts: %s", err) } @@ -431,7 +430,7 @@ func runTool(recipeID string, props *properties.Map, outStream, errStream io.Wri return nil } -func determineBuildPathAndSketchName(importFile, importDir string, sketch *sketches.Sketch, fqbn *cores.FQBN) (*paths.Path, string, error) { +func determineBuildPathAndSketchName(importFile, importDir string, sk *sketch.Sketch, fqbn *cores.FQBN) (*paths.Path, string, error) { // In general, compiling a sketch will produce a set of files that are // named as the sketch but have different extensions, for example Sketch.ino // may produce: Sketch.ino.bin; Sketch.ino.hex; Sketch.ino.zip; etc... @@ -478,13 +477,13 @@ func determineBuildPathAndSketchName(importFile, importDir string, sketch *sketc } // Case 3: nothing given... - if sketch == nil { + if sk == nil { return nil, "", fmt.Errorf("no sketch or build directory/file specified") } // 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 + sketch.MainFileExtension, nil + return sk.BuildPath, sk.Name + sk.MainFile.Ext(), nil } func detectSketchNameFromBuildPath(buildPath *paths.Path) (string, error) { diff --git a/commands/upload/upload_test.go b/commands/upload/upload_test.go index 99495a1f568..7463700730b 100644 --- a/commands/upload/upload_test.go +++ b/commands/upload/upload_test.go @@ -21,10 +21,9 @@ import ( "strings" "testing" - "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/sketches" + "github.com/arduino/arduino-cli/arduino/sketch" paths "github.com/arduino/go-paths-helper" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" @@ -56,13 +55,13 @@ func TestDetermineBuildPathAndSketchName(t *testing.T) { type test struct { importFile string importDir string - sketch *sketches.Sketch + sketch *sketch.Sketch fqbn *cores.FQBN resBuildPath string resSketchName string } - blonk, err := sketches.NewSketchFromPath(paths.New("testdata/Blonk")) + blonk, err := sketch.New(paths.New("testdata/Blonk")) require.NoError(t, err) fqbn, err := cores.ParseFQBN("arduino:samd:mkr1000") @@ -78,7 +77,7 @@ func TestDetermineBuildPathAndSketchName(t *testing.T) { // 03: error: used both importPath and importFile {"testdata/build_path_2/Blink.ino.hex", "testdata/build_path_2", nil, nil, "", ""}, // 04: only sketch without FQBN - {"", "", blonk, nil, builder.GenBuildPath(blonk.FullPath).String(), "Blonk.ino"}, + {"", "", blonk, nil, sketch.GenBuildPath(blonk.FullPath).String(), "Blonk.ino"}, // 05: use importFile to detect build.path and project_name, sketch is ignored. {"testdata/build_path_2/Blink.ino.hex", "", blonk, nil, "testdata/build_path_2", "Blink.ino"}, // 06: use importPath as build.path and Blink as project name, ignore the sketch Blonk @@ -94,7 +93,7 @@ func TestDetermineBuildPathAndSketchName(t *testing.T) { // 11: error: used both importPath and importFile {"testdata/build_path_2/Blink.ino.hex", "testdata/build_path_2", nil, fqbn, "", ""}, // 12: use sketch to determine project name and sketch+fqbn to determine build path - {"", "", blonk, fqbn, builder.GenBuildPath(blonk.FullPath).String(), "Blonk.ino"}, + {"", "", blonk, fqbn, sketch.GenBuildPath(blonk.FullPath).String(), "Blonk.ino"}, // 13: use importFile to detect build.path and project_name, sketch+fqbn is ignored. {"testdata/build_path_2/Blink.ino.hex", "", blonk, fqbn, "testdata/build_path_2", "Blink.ino"}, // 14: use importPath as build.path and Blink as project name, ignore the sketch Blonk, ignore fqbn diff --git a/legacy/builder/builder.go b/legacy/builder/builder.go index 420c459e49b..1d49a70a210 100644 --- a/legacy/builder/builder.go +++ b/legacy/builder/builder.go @@ -21,7 +21,7 @@ import ( "strconv" "time" - bldr "github.com/arduino/arduino-cli/arduino/builder" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/legacy/builder/builder_utils" "github.com/arduino/arduino-cli/legacy/builder/constants" "github.com/arduino/arduino-cli/legacy/builder/phases" @@ -41,7 +41,7 @@ const DEFAULT_SOFTWARE = "ARDUINO" type Builder struct{} func (s *Builder) Run(ctx *types.Context) error { - if err := bldr.EnsureBuildPathExists(ctx.BuildPath.String()); err != nil { + if err := ctx.BuildPath.MkdirAll(); err != nil { return err } @@ -134,10 +134,10 @@ type Preprocess struct{} func (s *Preprocess) Run(ctx *types.Context) error { if ctx.BuildPath == nil { - ctx.BuildPath = bldr.GenBuildPath(ctx.SketchLocation) + ctx.BuildPath = sketch.GenBuildPath(ctx.SketchLocation) } - if err := bldr.EnsureBuildPathExists(ctx.BuildPath.String()); err != nil { + if err := ctx.BuildPath.MkdirAll(); err != nil { return err } @@ -170,7 +170,7 @@ type ParseHardwareAndDumpBuildProperties struct{} func (s *ParseHardwareAndDumpBuildProperties) Run(ctx *types.Context) error { if ctx.BuildPath == nil { - ctx.BuildPath = bldr.GenBuildPath(ctx.SketchLocation) + ctx.BuildPath = sketch.GenBuildPath(ctx.SketchLocation) } commands := []types.Command{ diff --git a/legacy/builder/container_add_prototypes.go b/legacy/builder/container_add_prototypes.go index 1a8c093b351..222661ef07b 100644 --- a/legacy/builder/container_add_prototypes.go +++ b/legacy/builder/container_add_prototypes.go @@ -32,7 +32,7 @@ func (s *ContainerAddPrototypes) Run(ctx *types.Context) error { targetFilePath := ctx.PreprocPath.Join(constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E) // Run preprocessor - sourceFile := ctx.SketchBuildPath.Join(ctx.Sketch.MainFile.Name.Base() + ".cpp") + sourceFile := ctx.SketchBuildPath.Join(ctx.Sketch.MainFile.Base() + ".cpp") if err := GCCPreprocRunner(ctx, sourceFile, targetFilePath, ctx.IncludeFolders); err != nil { return errors.WithStack(err) } @@ -53,7 +53,7 @@ func (s *ContainerAddPrototypes) Run(ctx *types.Context) error { } } - if err := bldr.SketchSaveItemCpp(ctx.Sketch.MainFile.Name.String(), []byte(ctx.Source), ctx.SketchBuildPath.String()); err != nil { + if err := bldr.SketchSaveItemCpp(ctx.Sketch.MainFile, []byte(ctx.Source), ctx.SketchBuildPath); err != nil { return errors.WithStack(err) } diff --git a/legacy/builder/container_find_includes.go b/legacy/builder/container_find_includes.go index 6477a5351ed..98c72bfce4a 100644 --- a/legacy/builder/container_find_includes.go +++ b/legacy/builder/container_find_includes.go @@ -120,7 +120,7 @@ func (s *ContainerFindIncludes) Run(ctx *types.Context) error { } sketch := ctx.Sketch - mergedfile, err := types.MakeSourceFile(ctx, sketch, paths.New(sketch.MainFile.Name.Base()+".cpp")) + mergedfile, err := types.MakeSourceFile(ctx, sketch, paths.New(sketch.MainFile.Base()+".cpp")) if err != nil { return errors.WithStack(err) } diff --git a/legacy/builder/container_merge_copy_sketch_files.go b/legacy/builder/container_merge_copy_sketch_files.go index d62f603f316..b98eaebb721 100644 --- a/legacy/builder/container_merge_copy_sketch_files.go +++ b/legacy/builder/container_merge_copy_sketch_files.go @@ -24,22 +24,18 @@ import ( type ContainerMergeCopySketchFiles struct{} func (s *ContainerMergeCopySketchFiles) Run(ctx *types.Context) error { - sk := types.SketchFromLegacy(ctx.Sketch) - if sk == nil { - return errors.New("unable to convert legacy sketch to the new type") - } - offset, source, err := bldr.SketchMergeSources(sk, ctx.SourceOverride) + offset, source, err := bldr.SketchMergeSources(ctx.Sketch, ctx.SourceOverride) if err != nil { return err } ctx.LineOffset = offset ctx.Source = source - if err := bldr.SketchSaveItemCpp(ctx.Sketch.MainFile.Name.String(), []byte(ctx.Source), ctx.SketchBuildPath.String()); err != nil { + if err := bldr.SketchSaveItemCpp(ctx.Sketch.MainFile, []byte(ctx.Source), ctx.SketchBuildPath); err != nil { return errors.WithStack(err) } - if err := bldr.SketchCopyAdditionalFiles(sk, ctx.SketchBuildPath.String(), ctx.SourceOverride); err != nil { + if err := bldr.SketchCopyAdditionalFiles(ctx.Sketch, ctx.SketchBuildPath, ctx.SourceOverride); err != nil { return errors.WithStack(err) } diff --git a/legacy/builder/container_setup.go b/legacy/builder/container_setup.go index 2ce501fcf4f..038f66d92b4 100644 --- a/legacy/builder/container_setup.go +++ b/legacy/builder/container_setup.go @@ -18,11 +18,9 @@ package builder import ( "fmt" - bldr "github.com/arduino/arduino-cli/arduino/builder" sk "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/legacy/builder/builder_utils" "github.com/arduino/arduino-cli/legacy/builder/types" - "github.com/arduino/go-paths-helper" "github.com/pkg/errors" ) @@ -63,9 +61,11 @@ func (s *ContainerSetupHardwareToolsLibsSketchAndProps) Run(ctx *types.Context) } // load sketch - sketch, err := bldr.SketchLoad(sketchLocation.String(), ctx.BuildPath.String()) - if e, ok := err.(*sk.InvalidSketchFoldernameError); ctx.IgnoreSketchFolderNameErrors && ok { + sketch, err := sk.New(sketchLocation) + if e, ok := err.(*sk.InvalidSketchFolderNameError); ctx.IgnoreSketchFolderNameErrors && ok { // ignore error + // This is only done by the arduino-builder since the Arduino Java IDE + // supports sketches with invalid names sketch = e.Sketch } else if err != nil { return errors.WithStack(err) @@ -73,8 +73,9 @@ func (s *ContainerSetupHardwareToolsLibsSketchAndProps) Run(ctx *types.Context) if sketch.MainFile == nil { return fmt.Errorf("main file missing from sketch") } - ctx.SketchLocation = paths.New(sketch.MainFile.Path) - ctx.Sketch = types.SketchToLegacy(sketch) + sketch.BuildPath = ctx.BuildPath + ctx.SketchLocation = sketch.MainFile + ctx.Sketch = sketch } ctx.Progress.CompleteStep() builder_utils.PrintProgressIfProgressEnabledAndMachineLogger(ctx) diff --git a/legacy/builder/create_cmake_rule.go b/legacy/builder/create_cmake_rule.go index a976819a790..875f76afdcb 100644 --- a/legacy/builder/create_cmake_rule.go +++ b/legacy/builder/create_cmake_rule.go @@ -176,7 +176,7 @@ func (s *ExportProjectCMake) Run(ctx *types.Context) error { // Generate the CMakeLists global file - projectName := strings.TrimSuffix(ctx.Sketch.MainFile.Name.Base(), ctx.Sketch.MainFile.Name.Ext()) + projectName := ctx.Sketch.Name cmakelist := "cmake_minimum_required(VERSION 3.5.0)\n" cmakelist += "INCLUDE(FindPkgConfig)\n" diff --git a/legacy/builder/ctags_runner.go b/legacy/builder/ctags_runner.go index b132fc8ad03..553e1466d70 100644 --- a/legacy/builder/ctags_runner.go +++ b/legacy/builder/ctags_runner.go @@ -56,7 +56,7 @@ func (s *CTagsRunner) Run(ctx *types.Context) error { parser := &ctags.CTagsParser{} - ctx.CTagsOfPreprocessedSource = parser.Parse(ctx.CTagsOutput, ctx.Sketch.MainFile.Name) + ctx.CTagsOfPreprocessedSource = parser.Parse(ctx.CTagsOutput, ctx.Sketch.MainFile) parser.FixCLinkageTagsDeclarations(ctx.CTagsOfPreprocessedSource) protos, line := parser.GeneratePrototypes() diff --git a/legacy/builder/filter_sketch_source.go b/legacy/builder/filter_sketch_source.go index 716b4b4a496..458da993020 100644 --- a/legacy/builder/filter_sketch_source.go +++ b/legacy/builder/filter_sketch_source.go @@ -33,9 +33,9 @@ type FilterSketchSource struct { func (s *FilterSketchSource) Run(ctx *types.Context) error { fileNames := paths.NewPathList() - fileNames.Add(ctx.Sketch.MainFile.Name) - for _, file := range ctx.Sketch.OtherSketchFiles { - fileNames = append(fileNames, file.Name) + fileNames.Add(ctx.Sketch.MainFile) + for _, file := range *ctx.Sketch.OtherSketchFiles { + fileNames = append(fileNames, file) } inSketch := false diff --git a/legacy/builder/merge_sketch_with_bootloader.go b/legacy/builder/merge_sketch_with_bootloader.go index 0fb350d9c9b..50b4a8809c1 100644 --- a/legacy/builder/merge_sketch_with_bootloader.go +++ b/legacy/builder/merge_sketch_with_bootloader.go @@ -42,7 +42,7 @@ func (s *MergeSketchWithBootloader) Run(ctx *types.Context) error { buildPath := ctx.BuildPath sketch := ctx.Sketch - sketchFileName := sketch.MainFile.Name.Base() + sketchFileName := sketch.MainFile.Base() sketchInBuildPath := buildPath.Join(sketchFileName + ".hex") sketchInSubfolder := buildPath.Join(constants.FOLDER_SKETCH, sketchFileName+".hex") diff --git a/legacy/builder/preprocess_sketch.go b/legacy/builder/preprocess_sketch.go index 10360f09527..c8dee8a91a4 100644 --- a/legacy/builder/preprocess_sketch.go +++ b/legacy/builder/preprocess_sketch.go @@ -43,7 +43,7 @@ var ArduinoPreprocessorProperties = properties.NewFromHashmap(map[string]string{ type PreprocessSketchArduino struct{} func (s *PreprocessSketchArduino) Run(ctx *types.Context) error { - sourceFile := ctx.SketchBuildPath.Join(ctx.Sketch.MainFile.Name.Base() + ".cpp") + sourceFile := ctx.SketchBuildPath.Join(ctx.Sketch.MainFile.Base() + ".cpp") commands := []types.Command{ &ArduinoPreprocessorRunner{}, } @@ -66,7 +66,7 @@ func (s *PreprocessSketchArduino) Run(ctx *types.Context) error { if ctx.CodeCompleteAt != "" { err = new(OutputCodeCompletions).Run(ctx) } else { - err = bldr.SketchSaveItemCpp(ctx.Sketch.MainFile.Name.String(), []byte(ctx.Source), ctx.SketchBuildPath.String()) + err = bldr.SketchSaveItemCpp(ctx.Sketch.MainFile, []byte(ctx.Source), ctx.SketchBuildPath) } return err diff --git a/legacy/builder/setup_build_properties.go b/legacy/builder/setup_build_properties.go index 1579180ceba..e102baea351 100644 --- a/legacy/builder/setup_build_properties.go +++ b/legacy/builder/setup_build_properties.go @@ -46,7 +46,7 @@ func (s *SetupBuildProperties) Run(ctx *types.Context) error { buildProperties.SetPath("build.path", ctx.BuildPath) } if ctx.Sketch != nil { - buildProperties.Set("build.project_name", ctx.Sketch.MainFile.Name.Base()) + buildProperties.Set("build.project_name", ctx.Sketch.MainFile.Base()) } buildProperties.Set("build.arch", strings.ToUpper(targetPlatform.Platform.Architecture)) diff --git a/legacy/builder/sketch_loader.go b/legacy/builder/sketch_loader.go index 276e5583f3d..42a5ce1a0e4 100644 --- a/legacy/builder/sketch_loader.go +++ b/legacy/builder/sketch_loader.go @@ -16,14 +16,8 @@ package builder import ( - "sort" - "strings" - - "github.com/arduino/arduino-cli/legacy/builder/constants" - "github.com/arduino/arduino-cli/legacy/builder/i18n" + sk "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/legacy/builder/types" - "github.com/arduino/arduino-cli/legacy/builder/utils" - "github.com/arduino/go-paths-helper" "github.com/pkg/errors" ) @@ -50,70 +44,12 @@ func (s *SketchLoader) Run(ctx *types.Context) error { ctx.SketchLocation = sketchLocation - allSketchFilePaths, err := collectAllSketchFiles(sketchLocation.Parent()) + sketch, err := sk.New(sketchLocation) if err != nil { return errors.WithStack(err) } - - logger := ctx.GetLogger() - - if !allSketchFilePaths.Contains(sketchLocation) { - return i18n.ErrorfWithLogger(logger, constants.MSG_CANT_FIND_SKETCH_IN_PATH, sketchLocation, sketchLocation.Parent()) - } - - sketch, err := makeSketch(sketchLocation, allSketchFilePaths, ctx.BuildPath, logger) - if err != nil { - return errors.WithStack(err) - } - ctx.SketchLocation = sketchLocation ctx.Sketch = sketch return nil } - -func collectAllSketchFiles(from *paths.Path) (paths.PathList, error) { - filePaths := []string{} - // Source files in the root are compiled, non-recursively. This - // is the only place where .ino files can be present. - rootExtensions := func(ext string) bool { return MAIN_FILE_VALID_EXTENSIONS[ext] || ADDITIONAL_FILE_VALID_EXTENSIONS[ext] } - err := utils.FindFilesInFolder(&filePaths, from.String(), rootExtensions, true /* recurse */) - if err != nil { - return nil, errors.WithStack(err) - } - - return paths.NewPathList(filePaths...), errors.WithStack(err) -} - -func makeSketch(sketchLocation *paths.Path, allSketchFilePaths paths.PathList, buildLocation *paths.Path, logger i18n.Logger) (*types.Sketch, error) { - sketchFilesMap := make(map[string]types.SketchFile) - for _, sketchFilePath := range allSketchFilePaths { - sketchFilesMap[sketchFilePath.String()] = types.SketchFile{Name: sketchFilePath} - } - - mainFile := sketchFilesMap[sketchLocation.String()] - delete(sketchFilesMap, sketchLocation.String()) - - additionalFiles := []types.SketchFile{} - otherSketchFiles := []types.SketchFile{} - mainFileDir := mainFile.Name.Parent() - for _, sketchFile := range sketchFilesMap { - ext := strings.ToLower(sketchFile.Name.Ext()) - if MAIN_FILE_VALID_EXTENSIONS[ext] { - if sketchFile.Name.Parent().EqualsTo(mainFileDir) { - otherSketchFiles = append(otherSketchFiles, sketchFile) - } - } else if ADDITIONAL_FILE_VALID_EXTENSIONS[ext] { - if buildLocation == nil || !strings.Contains(sketchFile.Name.Parent().String(), buildLocation.String()) { - additionalFiles = append(additionalFiles, sketchFile) - } - } else { - return nil, i18n.ErrorfWithLogger(logger, constants.MSG_UNKNOWN_SKETCH_EXT, sketchFile.Name) - } - } - - sort.Sort(types.SketchFileSortByName(additionalFiles)) - sort.Sort(types.SketchFileSortByName(otherSketchFiles)) - - return &types.Sketch{MainFile: mainFile, OtherSketchFiles: otherSketchFiles, AdditionalFiles: additionalFiles}, nil -} diff --git a/legacy/builder/test/Baladuino/Baladuino.preprocessed.txt b/legacy/builder/test/Baladuino/Baladuino.preprocessed.txt index 238739eb902..8636e91422f 100644 --- a/legacy/builder/test/Baladuino/Baladuino.preprocessed.txt +++ b/legacy/builder/test/Baladuino/Baladuino.preprocessed.txt @@ -1,5 +1,5 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} /* * The code is released under the GNU General Public License. * Developed by Kristian Lauszus, TKJ Electronics 2013 @@ -87,11 +87,11 @@ WII Wii(&Btd); // The Wii library can communicate with Wiimotes and the Nunchuck // This can also be done using the Android or Processing application #endif -#line 88 {{QuoteCppString .sketch.MainFile.Name}} +#line 88 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 204 {{QuoteCppString .sketch.MainFile.Name}} +#line 204 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 88 {{QuoteCppString .sketch.MainFile.Name}} +#line 88 {{QuoteCppString .sketch.MainFile}} void setup() { /* Initialize UART */ Serial.begin(115200); diff --git a/legacy/builder/test/CharWithEscapedDoubleQuote/CharWithEscapedDoubleQuote.preprocessed.txt b/legacy/builder/test/CharWithEscapedDoubleQuote/CharWithEscapedDoubleQuote.preprocessed.txt index 1f9e69a613b..e6363b45861 100644 --- a/legacy/builder/test/CharWithEscapedDoubleQuote/CharWithEscapedDoubleQuote.preprocessed.txt +++ b/legacy/builder/test/CharWithEscapedDoubleQuote/CharWithEscapedDoubleQuote.preprocessed.txt @@ -1,5 +1,5 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} #include // required to send and receive AT commands from the GPRS Shield #include // required for I2C communication with the RTC @@ -38,49 +38,49 @@ Code Exclusively for GPRS shield: // Default set of instructions for GPRS Shield power control // -#line 39 {{QuoteCppString .sketch.MainFile.Name}} +#line 39 {{QuoteCppString .sketch.MainFile}} void setPowerStateTo( int newState ); -#line 64 {{QuoteCppString .sketch.MainFile.Name}} +#line 64 {{QuoteCppString .sketch.MainFile}} int getPowerState(); -#line 75 {{QuoteCppString .sketch.MainFile.Name}} +#line 75 {{QuoteCppString .sketch.MainFile}} void powerUpOrDown(); -#line 90 {{QuoteCppString .sketch.MainFile.Name}} +#line 90 {{QuoteCppString .sketch.MainFile}} void clearBufferArray(); -#line 96 {{QuoteCppString .sketch.MainFile.Name}} +#line 96 {{QuoteCppString .sketch.MainFile}} void makeMissedCall( char num[] ); -#line 111 {{QuoteCppString .sketch.MainFile.Name}} +#line 111 {{QuoteCppString .sketch.MainFile}} void sendTextMessage( char number[], char messg[] ); -#line 129 {{QuoteCppString .sketch.MainFile.Name}} +#line 129 {{QuoteCppString .sketch.MainFile}} void analise(byte incoming[], int length); -#line 179 {{QuoteCppString .sketch.MainFile.Name}} +#line 179 {{QuoteCppString .sketch.MainFile}} byte decToBcd( byte b ); -#line 184 {{QuoteCppString .sketch.MainFile.Name}} +#line 184 {{QuoteCppString .sketch.MainFile}} boolean getBit( byte addr, int pos ); -#line 190 {{QuoteCppString .sketch.MainFile.Name}} +#line 190 {{QuoteCppString .sketch.MainFile}} void setBit( byte addr, int pos, boolean newBit ); -#line 204 {{QuoteCppString .sketch.MainFile.Name}} +#line 204 {{QuoteCppString .sketch.MainFile}} byte getByte( byte addr ); -#line 213 {{QuoteCppString .sketch.MainFile.Name}} +#line 213 {{QuoteCppString .sketch.MainFile}} boolean getBytes( byte addr, int amount ); -#line 230 {{QuoteCppString .sketch.MainFile.Name}} +#line 230 {{QuoteCppString .sketch.MainFile}} void setByte( byte addr, byte newByte ); -#line 235 {{QuoteCppString .sketch.MainFile.Name}} +#line 235 {{QuoteCppString .sketch.MainFile}} void setBytes( byte addr, byte newBytes[], int amount ); -#line 244 {{QuoteCppString .sketch.MainFile.Name}} +#line 244 {{QuoteCppString .sketch.MainFile}} void getTime(); -#line 260 {{QuoteCppString .sketch.MainFile.Name}} +#line 260 {{QuoteCppString .sketch.MainFile}} void setTime( byte newTime[ 7 ] ); -#line 267 {{QuoteCppString .sketch.MainFile.Name}} +#line 267 {{QuoteCppString .sketch.MainFile}} void getRTCTemperature(); -#line 277 {{QuoteCppString .sketch.MainFile.Name}} +#line 277 {{QuoteCppString .sketch.MainFile}} void gprsListen(); -#line 294 {{QuoteCppString .sketch.MainFile.Name}} +#line 294 {{QuoteCppString .sketch.MainFile}} void printTime(); -#line 317 {{QuoteCppString .sketch.MainFile.Name}} +#line 317 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 334 {{QuoteCppString .sketch.MainFile.Name}} +#line 334 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 39 {{QuoteCppString .sketch.MainFile.Name}} +#line 39 {{QuoteCppString .sketch.MainFile}} void setPowerStateTo( int newState ) { if( newState != 1 && newState != 0 ) { // tests for an invalid state. In this case no change is made to powerstate diff --git a/legacy/builder/test/IncludeBetweenMultilineComment/IncludeBetweenMultilineComment.preprocessed.txt b/legacy/builder/test/IncludeBetweenMultilineComment/IncludeBetweenMultilineComment.preprocessed.txt index 076ff1b3b28..a4890529793 100644 --- a/legacy/builder/test/IncludeBetweenMultilineComment/IncludeBetweenMultilineComment.preprocessed.txt +++ b/legacy/builder/test/IncludeBetweenMultilineComment/IncludeBetweenMultilineComment.preprocessed.txt @@ -1,15 +1,15 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} #include /* #include */ CapacitiveSensor cs_13_8 = CapacitiveSensor(13,8); -#line 6 {{QuoteCppString .sketch.MainFile.Name}} +#line 6 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 10 {{QuoteCppString .sketch.MainFile.Name}} +#line 10 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 6 {{QuoteCppString .sketch.MainFile.Name}} +#line 6 {{QuoteCppString .sketch.MainFile}} void setup() { Serial.begin(9600); diff --git a/legacy/builder/test/LineContinuations/LineContinuations.preprocessed.txt b/legacy/builder/test/LineContinuations/LineContinuations.preprocessed.txt index 227bf26d32a..6338d8366f3 100644 --- a/legacy/builder/test/LineContinuations/LineContinuations.preprocessed.txt +++ b/legacy/builder/test/LineContinuations/LineContinuations.preprocessed.txt @@ -1,16 +1,16 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} const char *foo = "\ hello \ world\n"; //" delete this comment line and the IDE parser will crash -#line 7 {{QuoteCppString .sketch.MainFile.Name}} +#line 7 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 11 {{QuoteCppString .sketch.MainFile.Name}} +#line 11 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 7 {{QuoteCppString .sketch.MainFile.Name}} +#line 7 {{QuoteCppString .sketch.MainFile}} void setup() { } diff --git a/legacy/builder/test/SketchWithIfDef/SketchWithIfDef.preprocessed.txt b/legacy/builder/test/SketchWithIfDef/SketchWithIfDef.preprocessed.txt index 9d943396d6c..4faa5fe83e3 100644 --- a/legacy/builder/test/SketchWithIfDef/SketchWithIfDef.preprocessed.txt +++ b/legacy/builder/test/SketchWithIfDef/SketchWithIfDef.preprocessed.txt @@ -1,5 +1,5 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} #define DEBUG 1 #define DISABLED 0 @@ -15,17 +15,17 @@ typedef int MyType; #include "empty_2.h" -#line 16 {{QuoteCppString .sketch.MainFile.Name}} +#line 16 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 21 {{QuoteCppString .sketch.MainFile.Name}} +#line 21 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 33 {{QuoteCppString .sketch.MainFile.Name}} +#line 33 {{QuoteCppString .sketch.MainFile}} void debug(); -#line 44 {{QuoteCppString .sketch.MainFile.Name}} +#line 44 {{QuoteCppString .sketch.MainFile}} void disabledIsDefined(); -#line 48 {{QuoteCppString .sketch.MainFile.Name}} +#line 48 {{QuoteCppString .sketch.MainFile}} int useMyType(MyType type); -#line 16 {{QuoteCppString .sketch.MainFile.Name}} +#line 16 {{QuoteCppString .sketch.MainFile}} void setup() { // put your setup code here, to run once: diff --git a/legacy/builder/test/SketchWithIfDef/SketchWithIfDef.resolved.directives.txt b/legacy/builder/test/SketchWithIfDef/SketchWithIfDef.resolved.directives.txt index bf79b2f49c8..c79f372330b 100644 --- a/legacy/builder/test/SketchWithIfDef/SketchWithIfDef.resolved.directives.txt +++ b/legacy/builder/test/SketchWithIfDef/SketchWithIfDef.resolved.directives.txt @@ -1,5 +1,5 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} #define DEBUG 1 #define DISABLED 0 diff --git a/legacy/builder/test/SketchWithStruct/SketchWithStruct.preprocessed.txt b/legacy/builder/test/SketchWithStruct/SketchWithStruct.preprocessed.txt index 4f15168af15..4dd1ae448a5 100644 --- a/legacy/builder/test/SketchWithStruct/SketchWithStruct.preprocessed.txt +++ b/legacy/builder/test/SketchWithStruct/SketchWithStruct.preprocessed.txt @@ -1,5 +1,5 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} /* START CODE */ struct A_NEW_TYPE { @@ -8,13 +8,13 @@ struct A_NEW_TYPE { int c; } foo; -#line 9 {{QuoteCppString .sketch.MainFile.Name}} +#line 9 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 13 {{QuoteCppString .sketch.MainFile.Name}} +#line 13 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 17 {{QuoteCppString .sketch.MainFile.Name}} +#line 17 {{QuoteCppString .sketch.MainFile}} void dostuff (A_NEW_TYPE * bar); -#line 9 {{QuoteCppString .sketch.MainFile.Name}} +#line 9 {{QuoteCppString .sketch.MainFile}} void setup() { } diff --git a/legacy/builder/test/StringWithComment/StringWithComment.preprocessed.txt b/legacy/builder/test/StringWithComment/StringWithComment.preprocessed.txt index 2fcb13c5ea4..23677ef8ec8 100644 --- a/legacy/builder/test/StringWithComment/StringWithComment.preprocessed.txt +++ b/legacy/builder/test/StringWithComment/StringWithComment.preprocessed.txt @@ -1,10 +1,10 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} +#line 1 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 10 {{QuoteCppString .sketch.MainFile.Name}} +#line 10 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} void setup() { // put your setup code here, to run once: // "comment with a double quote diff --git a/legacy/builder/test/ctags_runner_test.go b/legacy/builder/test/ctags_runner_test.go index 99434b4cf4d..d47d53845a7 100644 --- a/legacy/builder/test/ctags_runner_test.go +++ b/legacy/builder/test/ctags_runner_test.go @@ -216,50 +216,3 @@ func TestCTagsRunnerSketchWithNamespace(t *testing.T) { require.Equal(t, expectedOutput, strings.Replace(ctx.CTagsOutput, "\r\n", "\n", -1)) } - -func TestCTagsRunnerSketchWithTemplates(t *testing.T) { - DownloadCoresAndToolsAndLibraries(t) - - sketchLocation := Abs(t, paths.New("sketch_with_templates_and_shift", "sketch_with_templates_and_shift.cpp")) - - ctx := &types.Context{ - HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware"), - BuiltInToolsDirs: paths.NewPathList("downloaded_tools"), - BuiltInLibrariesDirs: paths.NewPathList("downloaded_libraries"), - OtherLibrariesDirs: paths.NewPathList("libraries"), - SketchLocation: sketchLocation, - FQBN: parseFQBN(t, "arduino:avr:leonardo"), - ArduinoAPIVersion: "10600", - Verbose: true, - } - - buildPath := SetupBuildPath(t, ctx) - defer buildPath.RemoveAll() - - commands := []types.Command{ - - &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, - - &builder.ContainerMergeCopySketchFiles{}, - - &builder.ContainerFindIncludes{}, - - &builder.PrintUsedLibrariesIfVerbose{}, - &builder.WarnAboutArchIncompatibleLibraries{}, - &builder.CTagsTargetFileSaver{Source: &ctx.Source, TargetFileName: "ctags_target.cpp"}, - &builder.CTagsRunner{}, - } - - for _, command := range commands { - err := command.Run(ctx) - NoError(t, err) - } - - quotedSketchLocation := strings.Replace(sketchLocation.String(), "\\", "\\\\", -1) - expectedOutput := "printGyro\t" + quotedSketchLocation + "\t/^void printGyro()$/;\"\tkind:function\tline:10\tsignature:()\treturntype:void\n" + - "bVar\t" + quotedSketchLocation + "\t/^c< 8 > bVar;$/;\"\tkind:variable\tline:15\n" + - "aVar\t" + quotedSketchLocation + "\t/^c< 1<<8 > aVar;$/;\"\tkind:variable\tline:16\n" + - "func\t" + quotedSketchLocation + "\t/^template func( c< 1< & aParam) {$/;\"\tkind:function\tline:18\tsignature:( c< 1< & aParam)\treturntype:template\n" - - require.Equal(t, expectedOutput, strings.Replace(ctx.CTagsOutput, "\r\n", "\n", -1)) -} diff --git a/legacy/builder/test/sketch1/merged_sketch.txt b/legacy/builder/test/sketch1/merged_sketch.txt index 6f21615ced6..a4446b1c1a7 100644 --- a/legacy/builder/test/sketch1/merged_sketch.txt +++ b/legacy/builder/test/sketch1/merged_sketch.txt @@ -1,5 +1,5 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} void setup() { } diff --git a/legacy/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt b/legacy/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt index 9604504bc00..e633c616300 100644 --- a/legacy/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt +++ b/legacy/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt @@ -1,5 +1,5 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} #include "config.h" #ifdef DEBUG @@ -12,11 +12,11 @@ #include -#line 13 {{QuoteCppString .sketch.MainFile.Name}} +#line 13 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 17 {{QuoteCppString .sketch.MainFile.Name}} +#line 17 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 13 {{QuoteCppString .sketch.MainFile.Name}} +#line 13 {{QuoteCppString .sketch.MainFile}} void setup() { } diff --git a/legacy/builder/test/sketch_with_ifdef/sketch.preprocessed.SAM.txt b/legacy/builder/test/sketch_with_ifdef/sketch.preprocessed.SAM.txt index 76e39303fa2..c3c0d7c06d1 100644 --- a/legacy/builder/test/sketch_with_ifdef/sketch.preprocessed.SAM.txt +++ b/legacy/builder/test/sketch_with_ifdef/sketch.preprocessed.SAM.txt @@ -1,17 +1,17 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} #if __SAM3X8E__ -#line 2 {{QuoteCppString .sketch.MainFile.Name}} +#line 2 {{QuoteCppString .sketch.MainFile}} void ifBranch(); -#line 9 {{QuoteCppString .sketch.MainFile.Name}} +#line 9 {{QuoteCppString .sketch.MainFile}} void f1(); -#line 10 {{QuoteCppString .sketch.MainFile.Name}} +#line 10 {{QuoteCppString .sketch.MainFile}} void f2(); -#line 12 {{QuoteCppString .sketch.MainFile.Name}} +#line 12 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 14 {{QuoteCppString .sketch.MainFile.Name}} +#line 14 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 2 {{QuoteCppString .sketch.MainFile.Name}} +#line 2 {{QuoteCppString .sketch.MainFile}} void ifBranch() { } #else diff --git a/legacy/builder/test/sketch_with_ifdef/sketch.preprocessed.txt b/legacy/builder/test/sketch_with_ifdef/sketch.preprocessed.txt index 85f2068e48c..7fcfe26c389 100644 --- a/legacy/builder/test/sketch_with_ifdef/sketch.preprocessed.txt +++ b/legacy/builder/test/sketch_with_ifdef/sketch.preprocessed.txt @@ -1,20 +1,20 @@ #include -#line 1 {{QuoteCppString .sketch.MainFile.Name}} +#line 1 {{QuoteCppString .sketch.MainFile}} #if __SAM3X8E__ void ifBranch() { } #else -#line 5 {{QuoteCppString .sketch.MainFile.Name}} +#line 5 {{QuoteCppString .sketch.MainFile}} void elseBranch(); -#line 9 {{QuoteCppString .sketch.MainFile.Name}} +#line 9 {{QuoteCppString .sketch.MainFile}} void f1(); -#line 10 {{QuoteCppString .sketch.MainFile.Name}} +#line 10 {{QuoteCppString .sketch.MainFile}} void f2(); -#line 12 {{QuoteCppString .sketch.MainFile.Name}} +#line 12 {{QuoteCppString .sketch.MainFile}} void setup(); -#line 14 {{QuoteCppString .sketch.MainFile.Name}} +#line 14 {{QuoteCppString .sketch.MainFile}} void loop(); -#line 5 {{QuoteCppString .sketch.MainFile.Name}} +#line 5 {{QuoteCppString .sketch.MainFile}} void elseBranch() { } #endif diff --git a/legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.cpp b/legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.cpp deleted file mode 100644 index f4f1ece849f..00000000000 --- a/legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.cpp +++ /dev/null @@ -1,19 +0,0 @@ -template<> class FastPin<0> : public _ARMPIN<0, 10, 1 << 10, 0> {};; - -template<> class FastPin<0> : public _ARMPIN<0, 10, 1 < 10, 0> {};; - -template class OtherType> class NestedTemplateClass -{ - OtherType f; -}; - -void printGyro() -{ -} - -template class c {}; -c< 8 > bVar; -c< 1<<8 > aVar; - -template func( c< 1< & aParam) { -} diff --git a/legacy/builder/types/context.go b/legacy/builder/types/context.go index 079733db662..e48a8beab35 100644 --- a/legacy/builder/types/context.go +++ b/legacy/builder/types/context.go @@ -25,6 +25,7 @@ import ( "github.com/arduino/arduino-cli/arduino/libraries" "github.com/arduino/arduino-cli/arduino/libraries/librariesmanager" "github.com/arduino/arduino-cli/arduino/libraries/librariesresolver" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/legacy/builder/i18n" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" @@ -68,7 +69,7 @@ type Context struct { BuiltInLibrariesDirs paths.PathList OtherLibrariesDirs paths.PathList LibraryDirs paths.PathList // List of paths pointing to individual library root folders - SketchLocation *paths.Path + SketchLocation *paths.Path // SketchLocation points to the main Sketch file WatchedLocations paths.PathList ArduinoAPIVersion string FQBN *cores.FQBN @@ -109,7 +110,7 @@ type Context struct { CollectedSourceFiles *UniqueSourceFileQueue - Sketch *Sketch + Sketch *sketch.Sketch Source string SourceGccMinusE string CodeCompletions string @@ -210,9 +211,9 @@ func (ctx *Context) ExtractBuildOptions() *properties.Map { opts.SetPath("sketchLocation", ctx.SketchLocation) var additionalFilesRelative []string if ctx.Sketch != nil { - for _, sketch := range ctx.Sketch.AdditionalFiles { + for _, f := range *ctx.Sketch.AdditionalFiles { absPath := ctx.SketchLocation.Parent() - relPath, err := sketch.Name.RelTo(absPath) + relPath, err := f.RelTo(absPath) if err != nil { continue // ignore } diff --git a/legacy/builder/types/types.go b/legacy/builder/types/types.go index 82a8122b13f..70ee1c34608 100644 --- a/legacy/builder/types/types.go +++ b/legacy/builder/types/types.go @@ -50,7 +50,7 @@ func MakeSourceFile(ctx *Context, origin interface{}, path *paths.Path) (SourceF // appended here. func buildRoot(ctx *Context, origin interface{}) *paths.Path { switch o := origin.(type) { - case *Sketch: + case *sketch.Sketch: return ctx.SketchBuildPath case *libraries.Library: return ctx.LibrariesBuildPath.Join(o.Name) @@ -64,7 +64,7 @@ func buildRoot(ctx *Context, origin interface{}) *paths.Path { // the full path to that source file. func sourceRoot(ctx *Context, origin interface{}) *paths.Path { switch o := origin.(type) { - case *Sketch: + case *sketch.Sketch: return ctx.SketchBuildPath case *libraries.Library: return o.SourceDir @@ -103,56 +103,6 @@ func (s SketchFileSortByName) Less(i, j int) bool { return s[i].Name.String() < s[j].Name.String() } -type Sketch struct { - MainFile SketchFile - OtherSketchFiles []SketchFile - AdditionalFiles []SketchFile -} - -func SketchToLegacy(sketch *sketch.Sketch) *Sketch { - s := &Sketch{} - s.MainFile = SketchFile{ - paths.New(sketch.MainFile.Path), - } - - for _, item := range sketch.OtherSketchFiles { - s.OtherSketchFiles = append(s.OtherSketchFiles, SketchFile{ - paths.New(item.Path), - }) - } - - for _, item := range sketch.AdditionalFiles { - s.AdditionalFiles = append(s.AdditionalFiles, SketchFile{ - paths.New(item.Path), - }) - } - - return s -} - -func SketchFromLegacy(s *Sketch) *sketch.Sketch { - others := []*sketch.Item{} - for _, f := range s.OtherSketchFiles { - i := sketch.NewItem(f.Name.String()) - others = append(others, i) - } - - additional := []*sketch.Item{} - for _, f := range s.AdditionalFiles { - i := sketch.NewItem(f.Name.String()) - additional = append(additional, i) - } - - return &sketch.Sketch{ - MainFile: &sketch.Item{ - Path: s.MainFile.Name.String(), - }, - LocationPath: s.MainFile.Name.Parent().String(), - OtherSketchFiles: others, - AdditionalFiles: additional, - } -} - type PlatforKeysRewrite struct { Rewrites []PlatforKeyRewrite } diff --git a/test/test_compile.py b/test/test_compile.py index 0d89ed92256..7414f4ad6c1 100644 --- a/test/test_compile.py +++ b/test/test_compile.py @@ -130,10 +130,7 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir): # Build sketch for arduino:avr:uno result = run_command("compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)) - # The assertion is a bit relaxed in this case because win behaves differently from macOs and linux - # returning a different error detailed message - assert "Error during sketch processing" in result.stderr - assert not result.ok + assert result.ok sketch_name = "CompileIntegrationTestSymlinkDirLoop" sketch_path = os.path.join(data_dir, sketch_name) @@ -152,10 +149,7 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir): # Build sketch for arduino:avr:uno result = run_command("compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)) - # The assertion is a bit relaxed also in this case because macOS behaves differently from win and linux: - # the cli does not follow recursively the symlink til breaking - assert "Error during sketch processing" in result.stderr - assert not result.ok + assert result.ok def test_compile_blacklisted_sketchname(run_command, data_dir): From 2f2e2a661e19eb5ca0025e898e456dfc3373fc72 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Mon, 12 Jul 2021 12:57:38 +0200 Subject: [PATCH 02/10] Add back removed legacy test --- legacy/builder/test/ctags_runner_test.go | 47 +++++++++++++++++++ .../sketch_with_templates_and_shift.ino | 19 ++++++++ 2 files changed, 66 insertions(+) create mode 100644 legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.ino diff --git a/legacy/builder/test/ctags_runner_test.go b/legacy/builder/test/ctags_runner_test.go index d47d53845a7..0f4e8d92ee1 100644 --- a/legacy/builder/test/ctags_runner_test.go +++ b/legacy/builder/test/ctags_runner_test.go @@ -216,3 +216,50 @@ func TestCTagsRunnerSketchWithNamespace(t *testing.T) { require.Equal(t, expectedOutput, strings.Replace(ctx.CTagsOutput, "\r\n", "\n", -1)) } + +func TestCTagsRunnerSketchWithTemplates(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + sketchLocation := Abs(t, paths.New("sketch_with_templates_and_shift", "sketch_with_templates_and_shift.ino")) + + ctx := &types.Context{ + HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware"), + BuiltInToolsDirs: paths.NewPathList("downloaded_tools"), + BuiltInLibrariesDirs: paths.NewPathList("downloaded_libraries"), + OtherLibrariesDirs: paths.NewPathList("libraries"), + SketchLocation: sketchLocation, + FQBN: parseFQBN(t, "arduino:avr:leonardo"), + ArduinoAPIVersion: "10600", + Verbose: true, + } + + buildPath := SetupBuildPath(t, ctx) + defer buildPath.RemoveAll() + + commands := []types.Command{ + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + + &builder.ContainerFindIncludes{}, + + &builder.PrintUsedLibrariesIfVerbose{}, + &builder.WarnAboutArchIncompatibleLibraries{}, + &builder.CTagsTargetFileSaver{Source: &ctx.Source, TargetFileName: "ctags_target.cpp"}, + &builder.CTagsRunner{}, + } + + for _, command := range commands { + err := command.Run(ctx) + NoError(t, err) + } + + quotedSketchLocation := strings.Replace(sketchLocation.String(), "\\", "\\\\", -1) + expectedOutput := "printGyro\t" + quotedSketchLocation + "\t/^void printGyro()$/;\"\tkind:function\tline:10\tsignature:()\treturntype:void\n" + + "bVar\t" + quotedSketchLocation + "\t/^c< 8 > bVar;$/;\"\tkind:variable\tline:15\n" + + "aVar\t" + quotedSketchLocation + "\t/^c< 1<<8 > aVar;$/;\"\tkind:variable\tline:16\n" + + "func\t" + quotedSketchLocation + "\t/^template func( c< 1< & aParam) {$/;\"\tkind:function\tline:18\tsignature:( c< 1< & aParam)\treturntype:template\n" + + require.Equal(t, expectedOutput, strings.Replace(ctx.CTagsOutput, "\r\n", "\n", -1)) +} diff --git a/legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.ino b/legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.ino new file mode 100644 index 00000000000..c0dac664ef2 --- /dev/null +++ b/legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.ino @@ -0,0 +1,19 @@ +template<> class FastPin<0> : public _ARMPIN<0, 10, 1 << 10, 0> {};; + +template<> class FastPin<0> : public _ARMPIN<0, 10, 1 < 10, 0> {};; + +template class OtherType> class NestedTemplateClass +{ + OtherType f; +}; + +void printGyro() +{ +} + +template class c {}; +c< 8 > bVar; +c< 1<<8 > aVar; + +template func( c< 1< & aParam) { +} From db9c761496d4d5180a730e422109163455cf595a Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Mon, 12 Jul 2021 12:59:06 +0200 Subject: [PATCH 03/10] Changed Sketch struct to not use pointers --- arduino/builder/sketch.go | 4 ++-- arduino/builder/sketch_test.go | 4 ++-- arduino/sketch/sketch.go | 18 +++++++++--------- commands/instances.go | 6 +++--- legacy/builder/filter_sketch_source.go | 2 +- legacy/builder/types/context.go | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arduino/builder/sketch.go b/arduino/builder/sketch.go index 7b192fab37a..14ae39d4fd9 100644 --- a/arduino/builder/sketch.go +++ b/arduino/builder/sketch.go @@ -88,7 +88,7 @@ func SketchMergeSources(sk *sketch.Sketch, overrides map[string]string) (int, st mergedSource += mainSrc + "\n" lineOffset++ - for _, file := range *sk.OtherSketchFiles { + for _, file := range sk.OtherSketchFiles { src, err := getSource(file) if err != nil { return 0, "", err @@ -107,7 +107,7 @@ func SketchCopyAdditionalFiles(sketch *sketch.Sketch, destPath *paths.Path, over return errors.Wrap(err, "unable to create a folder to save the sketch files") } - for _, file := range *sketch.AdditionalFiles { + for _, file := range sketch.AdditionalFiles { relpath, err := sketch.FullPath.RelTo(file) if err != nil { return errors.Wrap(err, "unable to compute relative path to the sketch for the item") diff --git a/arduino/builder/sketch_test.go b/arduino/builder/sketch_test.go index d7fd40b22c5..8ac9c324b2c 100644 --- a/arduino/builder/sketch_test.go +++ b/arduino/builder/sketch_test.go @@ -122,7 +122,7 @@ func TestCopyAdditionalFiles(t *testing.T) { require.Equal(t, s2.AdditionalFiles.Len(), 1) // save file info - info1, err := paths.New(s2.AdditionalFiles.AsStrings()[0]).Stat() + info1, err := s2.AdditionalFiles[0].Stat() require.Nil(t, err) // copy again @@ -130,6 +130,6 @@ func TestCopyAdditionalFiles(t *testing.T) { require.Nil(t, err) // verify file hasn't changed - info2, err := paths.New(s2.AdditionalFiles.AsStrings()[0]).Stat() + info2, err := s2.AdditionalFiles[0].Stat() require.Equal(t, info1.ModTime(), info2.ModTime()) } diff --git a/arduino/sketch/sketch.go b/arduino/sketch/sketch.go index 2991f2ad920..a2fe83d4f1d 100644 --- a/arduino/sketch/sketch.go +++ b/arduino/sketch/sketch.go @@ -34,9 +34,9 @@ type Sketch struct { MainFile *paths.Path FullPath *paths.Path // FullPath is the path to the Sketch folder BuildPath *paths.Path - OtherSketchFiles *paths.PathList // Sketch files that end in .ino other than main file - AdditionalFiles *paths.PathList - RootFolderFiles *paths.PathList // All files that are in the Sketch root + OtherSketchFiles paths.PathList // Sketch files that end in .ino other than main file + AdditionalFiles paths.PathList + RootFolderFiles paths.PathList // All files that are in the Sketch root Metadata *Metadata } @@ -80,9 +80,9 @@ func New(path *paths.Path) (*Sketch, error) { MainFile: mainFile, FullPath: path, BuildPath: GenBuildPath(path), - OtherSketchFiles: new(paths.PathList), - AdditionalFiles: new(paths.PathList), - RootFolderFiles: new(paths.PathList), + OtherSketchFiles: paths.PathList{}, + AdditionalFiles: paths.PathList{}, + RootFolderFiles: paths.PathList{}, } err := sketch.checkSketchCasing() @@ -139,9 +139,9 @@ func New(path *paths.Path) (*Sketch, error) { } } - sort.Sort(sketch.AdditionalFiles) - sort.Sort(sketch.OtherSketchFiles) - sort.Sort(sketch.RootFolderFiles) + sort.Sort(&sketch.AdditionalFiles) + sort.Sort(&sketch.OtherSketchFiles) + sort.Sort(&sketch.RootFolderFiles) if err := sketch.importMetadata(); err != nil { return nil, fmt.Errorf("importing sketch metadata: %s", err) diff --git a/commands/instances.go b/commands/instances.go index 28a541a2285..41d47432dbb 100644 --- a/commands/instances.go +++ b/commands/instances.go @@ -849,17 +849,17 @@ func LoadSketch(ctx context.Context, req *rpc.LoadSketchRequest) (*rpc.LoadSketc } otherSketchFiles := make([]string, sketch.OtherSketchFiles.Len()) - for i, file := range *sketch.OtherSketchFiles { + for i, file := range sketch.OtherSketchFiles { otherSketchFiles[i] = file.String() } additionalFiles := make([]string, sketch.AdditionalFiles.Len()) - for i, file := range *sketch.AdditionalFiles { + for i, file := range sketch.AdditionalFiles { additionalFiles[i] = file.String() } rootFolderFiles := make([]string, sketch.RootFolderFiles.Len()) - for i, file := range *sketch.RootFolderFiles { + for i, file := range sketch.RootFolderFiles { rootFolderFiles[i] = file.String() } diff --git a/legacy/builder/filter_sketch_source.go b/legacy/builder/filter_sketch_source.go index 458da993020..38649845aea 100644 --- a/legacy/builder/filter_sketch_source.go +++ b/legacy/builder/filter_sketch_source.go @@ -34,7 +34,7 @@ type FilterSketchSource struct { func (s *FilterSketchSource) Run(ctx *types.Context) error { fileNames := paths.NewPathList() fileNames.Add(ctx.Sketch.MainFile) - for _, file := range *ctx.Sketch.OtherSketchFiles { + for _, file := range ctx.Sketch.OtherSketchFiles { fileNames = append(fileNames, file) } diff --git a/legacy/builder/types/context.go b/legacy/builder/types/context.go index e48a8beab35..c475460dd0b 100644 --- a/legacy/builder/types/context.go +++ b/legacy/builder/types/context.go @@ -211,7 +211,7 @@ func (ctx *Context) ExtractBuildOptions() *properties.Map { opts.SetPath("sketchLocation", ctx.SketchLocation) var additionalFilesRelative []string if ctx.Sketch != nil { - for _, f := range *ctx.Sketch.AdditionalFiles { + for _, f := range ctx.Sketch.AdditionalFiles { absPath := ctx.SketchLocation.Parent() relPath, err := f.RelTo(absPath) if err != nil { From 8de0dec7a82f9688b523b0b98662899e8dd76acc Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Mon, 12 Jul 2021 12:59:26 +0200 Subject: [PATCH 04/10] Fix small comment --- arduino/sketch/sketch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arduino/sketch/sketch.go b/arduino/sketch/sketch.go index a2fe83d4f1d..be978dba72c 100644 --- a/arduino/sketch/sketch.go +++ b/arduino/sketch/sketch.go @@ -114,7 +114,7 @@ func New(path *paths.Path) (*Sketch, error) { ext := p.Ext() if _, found := globals.MainFileValidExtensions[ext]; found { if p.EqualsTo(mainFile) { - // The main file must be included in the lists of other files + // The main file must not be included in the lists of other files continue } // file is a valid sketch file, see if it's stored at the From 7d00b8348c17e771965d8b5d8c8c1a24c5998389 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Mon, 12 Jul 2021 12:59:55 +0200 Subject: [PATCH 05/10] Fix checkSketchCasing to work with .pde files too --- arduino/sketch/sketch.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arduino/sketch/sketch.go b/arduino/sketch/sketch.go index be978dba72c..f231402799c 100644 --- a/arduino/sketch/sketch.go +++ b/arduino/sketch/sketch.go @@ -226,7 +226,11 @@ func (s *Sketch) checkSketchCasing() error { } files.FilterOutDirs() - files.FilterPrefix(s.Name) + candidateFileNames := []string{} + for ext := range globals.MainFileValidExtensions { + candidateFileNames = append(candidateFileNames, fmt.Sprintf("%s%s", s.Name, ext)) + } + files.FilterPrefix(candidateFileNames...) if files.Len() == 0 { sketchFile := s.FullPath.Join(s.Name + globals.MainFileValidExtension) From ac517bece098ccccc79cf13fee21df4e6944a9f1 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Mon, 12 Jul 2021 17:22:44 +0200 Subject: [PATCH 06/10] Add tests loading Sketch with symlinks --- arduino/sketch/sketch_test.go | 36 +++++++++++++++++++ .../SketchWithSymlink/SketchWithSymlink.ino | 2 ++ .../SketchWithSymlink/some_folder/helper.h | 0 .../SketchWithSymlinkLoop.ino | 2 ++ .../some_folder/helper.h | 0 docsgen/go.mod | 1 + docsgen/go.sum | 2 ++ go.mod | 2 +- go.sum | 2 ++ test/test_compile.py | 10 ++++-- 10 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 arduino/sketch/testdata/SketchWithSymlink/SketchWithSymlink.ino create mode 100644 arduino/sketch/testdata/SketchWithSymlink/some_folder/helper.h create mode 100644 arduino/sketch/testdata/SketchWithSymlinkLoop/SketchWithSymlinkLoop.ino create mode 100644 arduino/sketch/testdata/SketchWithSymlinkLoop/some_folder/helper.h diff --git a/arduino/sketch/sketch_test.go b/arduino/sketch/sketch_test.go index dc53727010e..cf7c8ba457f 100644 --- a/arduino/sketch/sketch_test.go +++ b/arduino/sketch/sketch_test.go @@ -300,3 +300,39 @@ func TestCheckForPdeFiles(t *testing.T) { require.Len(t, files, 1) require.Equal(t, sketchPath.Parent().Join("SketchMultipleMainFiles.pde"), files[0]) } + +func TestNewSketchWithSymlink(t *testing.T) { + sketchPath, _ := paths.New("testdata", "SketchWithSymlink").Abs() + mainFilePath := sketchPath.Join("SketchWithSymlink.ino") + helperFilePath := sketchPath.Join("some_folder", "helper.h") + helperFileSymlinkPath := sketchPath.Join("src", "helper.h") + srcPath := sketchPath.Join("src") + + // Create a symlink in the Sketch folder + os.Symlink(sketchPath.Join("some_folder").String(), srcPath.String()) + defer srcPath.Remove() + + sketch, err := New(sketchPath) + require.NoError(t, err) + require.NotNil(t, sketch) + require.True(t, sketch.MainFile.EquivalentTo(mainFilePath)) + require.True(t, sketch.FullPath.EquivalentTo(sketchPath)) + require.Equal(t, sketch.OtherSketchFiles.Len(), 0) + require.Equal(t, sketch.AdditionalFiles.Len(), 2) + require.True(t, sketch.AdditionalFiles.Contains(helperFilePath)) + require.True(t, sketch.AdditionalFiles.Contains(helperFileSymlinkPath)) + require.Equal(t, sketch.RootFolderFiles.Len(), 0) +} + +func TestNewSketchWithSymlinkLoop(t *testing.T) { + sketchPath, _ := paths.New("testdata", "SketchWithSymlinkLoop").Abs() + someSymlinkPath := sketchPath.Join("some_folder", "some_symlink") + + // Create a recursive Sketch symlink + os.Symlink(sketchPath.String(), someSymlinkPath.String()) + defer someSymlinkPath.Remove() + + sketch, err := New(sketchPath) + require.Error(t, err) + require.Nil(t, sketch) +} diff --git a/arduino/sketch/testdata/SketchWithSymlink/SketchWithSymlink.ino b/arduino/sketch/testdata/SketchWithSymlink/SketchWithSymlink.ino new file mode 100644 index 00000000000..c34fafcb168 --- /dev/null +++ b/arduino/sketch/testdata/SketchWithSymlink/SketchWithSymlink.ino @@ -0,0 +1,2 @@ +void setup() { } +void loop() { } diff --git a/arduino/sketch/testdata/SketchWithSymlink/some_folder/helper.h b/arduino/sketch/testdata/SketchWithSymlink/some_folder/helper.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/arduino/sketch/testdata/SketchWithSymlinkLoop/SketchWithSymlinkLoop.ino b/arduino/sketch/testdata/SketchWithSymlinkLoop/SketchWithSymlinkLoop.ino new file mode 100644 index 00000000000..c34fafcb168 --- /dev/null +++ b/arduino/sketch/testdata/SketchWithSymlinkLoop/SketchWithSymlinkLoop.ino @@ -0,0 +1,2 @@ +void setup() { } +void loop() { } diff --git a/arduino/sketch/testdata/SketchWithSymlinkLoop/some_folder/helper.h b/arduino/sketch/testdata/SketchWithSymlinkLoop/some_folder/helper.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docsgen/go.mod b/docsgen/go.mod index f60719925ed..cf7fc2b74c3 100644 --- a/docsgen/go.mod +++ b/docsgen/go.mod @@ -6,5 +6,6 @@ replace github.com/arduino/arduino-cli => ../ require ( github.com/arduino/arduino-cli v0.0.0 + github.com/arduino/go-paths-helper v1.6.1 // indirect github.com/spf13/cobra v1.0.1-0.20200710201246-675ae5f5a98c ) diff --git a/docsgen/go.sum b/docsgen/go.sum index b1169c26e2d..8780728b9ba 100644 --- a/docsgen/go.sum +++ b/docsgen/go.sum @@ -16,6 +16,8 @@ github.com/arduino/go-paths-helper v1.0.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3 github.com/arduino/go-paths-helper v1.2.0/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck= github.com/arduino/go-paths-helper v1.6.0 h1:S7/d7DqB9XlnvF9KrgSiGmo2oWKmYW6O/DTjj3Bijx4= github.com/arduino/go-paths-helper v1.6.0/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4Qyx+RAFKaG9NuvU= +github.com/arduino/go-paths-helper v1.6.1 h1:lha+/BuuBsx0qTZ3gy6IO1kU23lObWdQ/UItkzVWQ+0= +github.com/arduino/go-paths-helper v1.6.1/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4Qyx+RAFKaG9NuvU= github.com/arduino/go-properties-orderedmap v1.3.0 h1:4No/vQopB36e7WUIk6H6TxiSEJPiMrVOCZylYmua39o= github.com/arduino/go-properties-orderedmap v1.3.0/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk= github.com/arduino/go-properties-orderedmap v1.5.0 h1:istmr13qQN3nneuU3lsqlMvI6jqB3u8QUfVU1tX/t/8= diff --git a/go.mod b/go.mod index 7511157650c..78ec3f823c0 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c - github.com/arduino/go-paths-helper v1.6.0 + github.com/arduino/go-paths-helper v1.6.1 github.com/arduino/go-properties-orderedmap v1.5.0 github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b diff --git a/go.sum b/go.sum index a063e734c4a..927dd77befc 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/arduino/go-paths-helper v1.5.0 h1:RVo189hD+GhUS1rQ3gixwK1nSbvVR8MGIGa github.com/arduino/go-paths-helper v1.5.0/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4Qyx+RAFKaG9NuvU= github.com/arduino/go-paths-helper v1.6.0 h1:S7/d7DqB9XlnvF9KrgSiGmo2oWKmYW6O/DTjj3Bijx4= github.com/arduino/go-paths-helper v1.6.0/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4Qyx+RAFKaG9NuvU= +github.com/arduino/go-paths-helper v1.6.1 h1:lha+/BuuBsx0qTZ3gy6IO1kU23lObWdQ/UItkzVWQ+0= +github.com/arduino/go-paths-helper v1.6.1/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4Qyx+RAFKaG9NuvU= github.com/arduino/go-properties-orderedmap v1.3.0 h1:4No/vQopB36e7WUIk6H6TxiSEJPiMrVOCZylYmua39o= github.com/arduino/go-properties-orderedmap v1.3.0/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk= github.com/arduino/go-properties-orderedmap v1.5.0 h1:istmr13qQN3nneuU3lsqlMvI6jqB3u8QUfVU1tX/t/8= diff --git a/test/test_compile.py b/test/test_compile.py index 7414f4ad6c1..8fd8996154c 100644 --- a/test/test_compile.py +++ b/test/test_compile.py @@ -130,7 +130,10 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir): # Build sketch for arduino:avr:uno result = run_command("compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)) - assert result.ok + # The assertion is a bit relaxed in this case because win behaves differently from macOs and linux + # returning a different error detailed message + assert "Error during build: opening sketch" in result.stderr + assert not result.ok sketch_name = "CompileIntegrationTestSymlinkDirLoop" sketch_path = os.path.join(data_dir, sketch_name) @@ -149,7 +152,10 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir): # Build sketch for arduino:avr:uno result = run_command("compile -b {fqbn} {sketch_path}".format(fqbn=fqbn, sketch_path=sketch_path)) - assert result.ok + # The assertion is a bit relaxed in this case because win behaves differently from macOs and linux + # returning a different error detailed message + assert "Error during build: opening sketch" in result.stderr + assert not result.ok def test_compile_blacklisted_sketchname(run_command, data_dir): From 07f3ae5b88f69f8fc18d6828204605088cea00c2 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Mon, 12 Jul 2021 18:20:08 +0200 Subject: [PATCH 07/10] Update UPGRADING.md --- docs/UPGRADING.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index 8d3d6cdbfa3..01d80cec118 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -4,6 +4,95 @@ Here you can find a list of migration guides to handle breaking changes between ## Unreleased +### Change public library interface + +#### `github.com/arduino/arduino-cli/arduino/builder` package + +`GenBuildPath()` function has been moved to `github.com/arduino/arduino-cli/arduino/sketch` package. The signature is +unchanged. + +`EnsureBuildPathExists` function from has been completely removed, in its place use +`github.com/arduino/go-paths-helper.MkDirAll()`. + +`SketchSaveItemCpp` function signature is changed from `path string, contents []byte, destPath string` to +`path *paths.Path, contents []byte, destPath *paths.Path`. `paths` is `github.com/arduino/go-paths-helper`. + +`SketchLoad` function has been removed, in its place use `New` from `github.com/arduino/arduino-cli/arduino/sketch` +package. + +```diff +- SketchLoad("/some/path", "") ++ sketch.New(paths.New("some/path)) +} +``` + +If you need to set a custom build path you must instead set it after creating the Sketch. + +```diff +- SketchLoad("/some/path", "/my/build/path") ++ s, err := sketch.New(paths.New("some/path)) ++ s.BuildPath = paths.new("/my/build/path") +} +``` + +`SketchCopyAdditionalFiles` function signature is changed from +`sketch *sketch.Sketch, destPath string, overrides map[string]string` to +`sketch *sketch.Sketch, destPath *paths.Path, overrides map[string]string`. + +#### `github.com/arduino/arduino-cli/arduino/sketch` package + +`Item` struct has been removed, use `go-paths-helper.Path` in its place. + +`NewItem` has been removed too, use `go-paths-helper.New` in its place. + +`GetSourceBytes` has been removed, in its place use `go-paths-helper.Path.ReadFile`. `GetSourceStr` too has been +removed, in its place: + +```diff +- s, err := item.GetSourceStr() ++ data, err := file.ReadFile() ++ s := string(data) +} +``` + +`ItemByPath` type and its member functions have been removed, use `go-paths-helper.PathList` in its place. + +`Sketch.LocationPath` has been renamed to `FullPath` and its type changed from `string` to `go-paths-helper.Path`. + +`Sketch.MainFile` type has changed from `*Item` to `go-paths-helper.Path`. `Sketch.OtherSketchFiles`, +`Sketch.AdditionalFiles` and `Sketch.RootFolderFiles` type has changed from `[]*Item` to `go-paths-helper.PathList`. + +`New` signature has been changed from `sketchFolderPath, mainFilePath, buildPath string, allFilesPaths []string` to +`path *go-paths-helper.Path`. + +`CheckSketchCasing` function is now private, the check is done internally by `New`. + +`InvalidSketchFoldernameError` has been renamed `InvalidSketchFolderNameError`. + +#### `github.com/arduino/arduino-cli/arduino/sketches` package + +`Sketch` struct has been merged with `sketch.Sketch` struct. + +`Metadata` and `BoardMetadata` structs have been moved to `github.com/arduino/arduino-cli/arduino/sketch` package. + +`NewSketchFromPath` has been deleted, use `sketch.New` in its place. + +`ImportMetadata` is now private called internally by `sketch.New`. + +`ExportMetadata` has been moved to `github.com/arduino/arduino-cli/arduino/sketch` package. + +`BuildPath` has been removed, use `sketch.Sketch.BuildPath` in its place. + +`CheckForPdeFiles` has been moved to `github.com/arduino/arduino-cli/arduino/sketch` package. + +#### `github.com/arduino/arduino-cli/legacy/builder/types` package + +`Sketch` has been removed, use `sketch.Sketch` in its place. + +`SketchToLegacy` and `SketchFromLegacy` have been removed, nothing replaces them. + +`Context.Sketch` types has been changed from `Sketch` to `sketch.Sketch`. + ### Change of behaviour of gRPC `Init` function Previously the `Init` function was used to both create a new `CoreInstance` and initialize it, so that the internal From 9cac5aabd058a145b7bfe2a8a27adbba69476e84 Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Tue, 13 Jul 2021 09:55:51 +0200 Subject: [PATCH 08/10] Clarify a code comment --- commands/instances.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/instances.go b/commands/instances.go index 41d47432dbb..cc8fd1ed92f 100644 --- a/commands/instances.go +++ b/commands/instances.go @@ -842,7 +842,7 @@ func Upgrade(ctx context.Context, req *rpc.UpgradeRequest, downloadCB DownloadPr // LoadSketch collects and returns all files composing a sketch func LoadSketch(ctx context.Context, req *rpc.LoadSketchRequest) (*rpc.LoadSketchResponse, error) { - // TODO: This a ToRpc function for the Sketch struct + // TODO: This should be a ToRpc function for the Sketch struct sketch, err := sk.New(paths.New(req.SketchPath)) if err != nil { return nil, fmt.Errorf("error loading sketch %v: %v", req.SketchPath, err) From bf30333a078d63cef0033b4931253458e01196cc Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Tue, 13 Jul 2021 10:04:43 +0200 Subject: [PATCH 09/10] Add some more tests for Sketches with symlinks --- arduino/sketch/sketch_test.go | 55 ++++++++++++++++++- .../SketchWithMultipleSymlinkLoops.ino | 2 + .../src/UpGoer1 | 1 + .../src/UpGoer2 | 1 + 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/SketchWithMultipleSymlinkLoops.ino create mode 120000 arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer1 create mode 120000 arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer2 diff --git a/arduino/sketch/sketch_test.go b/arduino/sketch/sketch_test.go index cf7c8ba457f..9c336d3900a 100644 --- a/arduino/sketch/sketch_test.go +++ b/arduino/sketch/sketch_test.go @@ -19,6 +19,7 @@ import ( "fmt" "os" "testing" + "time" "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/assert" @@ -332,7 +333,59 @@ func TestNewSketchWithSymlinkLoop(t *testing.T) { os.Symlink(sketchPath.String(), someSymlinkPath.String()) defer someSymlinkPath.Remove() - sketch, err := New(sketchPath) + // The failure condition is New() never returning, testing for which requires setting up a timeout. + done := make(chan bool) + var sketch *Sketch + var err error + go func() { + sketch, err = New(sketchPath) + done <- true + }() + + assert.Eventually( + t, + func() bool { + select { + case <-done: + return true + default: + return false + } + }, + 20*time.Second, + 10*time.Millisecond, + "Infinite symlink loop while loading sketch", + ) + require.Error(t, err) + require.Nil(t, sketch) +} + +func TestSketchWithMultipleSymlinkLoops(t *testing.T) { + sketchPath, _ := paths.New("testdata", "SketchWithMultipleSymlinkLoops").Abs() + + // The failure condition is New() never returning, testing for which requires setting up a timeout. + done := make(chan bool) + var sketch *Sketch + var err error + go func() { + sketch, err = New(sketchPath) + done <- true + }() + + assert.Eventually( + t, + func() bool { + select { + case <-done: + return true + default: + return false + } + }, + 20*time.Second, + 10*time.Millisecond, + "Infinite symlink loop while loading sketch", + ) require.Error(t, err) require.Nil(t, sketch) } diff --git a/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/SketchWithMultipleSymlinkLoops.ino b/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/SketchWithMultipleSymlinkLoops.ino new file mode 100644 index 00000000000..cb344de719a --- /dev/null +++ b/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/SketchWithMultipleSymlinkLoops.ino @@ -0,0 +1,2 @@ +void setup(){} +void loop(){} diff --git a/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer1 b/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer1 new file mode 120000 index 00000000000..a96aa0ea9d8 --- /dev/null +++ b/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer1 @@ -0,0 +1 @@ +.. \ No newline at end of file diff --git a/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer2 b/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer2 new file mode 120000 index 00000000000..a96aa0ea9d8 --- /dev/null +++ b/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer2 @@ -0,0 +1 @@ +.. \ No newline at end of file From 9618e9d8eda538166b75b929d2d0549fa05b1e4f Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Tue, 13 Jul 2021 11:07:19 +0200 Subject: [PATCH 10/10] Fix Sketch symlinks tests for Windows --- arduino/sketch/sketch_test.go | 17 +++++++++++++---- .../SketchWithMultipleSymlinkLoops/src/UpGoer1 | 1 - .../SketchWithMultipleSymlinkLoops/src/UpGoer2 | 1 - 3 files changed, 13 insertions(+), 6 deletions(-) delete mode 120000 arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer1 delete mode 120000 arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer2 diff --git a/arduino/sketch/sketch_test.go b/arduino/sketch/sketch_test.go index 9c336d3900a..f203491b250 100644 --- a/arduino/sketch/sketch_test.go +++ b/arduino/sketch/sketch_test.go @@ -330,13 +330,13 @@ func TestNewSketchWithSymlinkLoop(t *testing.T) { someSymlinkPath := sketchPath.Join("some_folder", "some_symlink") // Create a recursive Sketch symlink - os.Symlink(sketchPath.String(), someSymlinkPath.String()) + err := os.Symlink(sketchPath.String(), someSymlinkPath.String()) + require.NoErrorf(t, err, "This test must be run as administrator on Windows to have symlink creation privilege.") defer someSymlinkPath.Remove() // The failure condition is New() never returning, testing for which requires setting up a timeout. done := make(chan bool) var sketch *Sketch - var err error go func() { sketch, err = New(sketchPath) done <- true @@ -361,12 +361,21 @@ func TestNewSketchWithSymlinkLoop(t *testing.T) { } func TestSketchWithMultipleSymlinkLoops(t *testing.T) { - sketchPath, _ := paths.New("testdata", "SketchWithMultipleSymlinkLoops").Abs() + sketchPath := paths.New("testdata", "SketchWithMultipleSymlinkLoops") + srcPath := sketchPath.Join("src") + srcPath.Mkdir() + defer srcPath.RemoveAll() + + firstSymlinkPath := srcPath.Join("UpGoer1") + secondSymlinkPath := srcPath.Join("UpGoer2") + err := os.Symlink("..", firstSymlinkPath.String()) + require.NoErrorf(t, err, "This test must be run as administrator on Windows to have symlink creation privilege.") + err = os.Symlink("..", secondSymlinkPath.String()) + require.NoErrorf(t, err, "This test must be run as administrator on Windows to have symlink creation privilege.") // The failure condition is New() never returning, testing for which requires setting up a timeout. done := make(chan bool) var sketch *Sketch - var err error go func() { sketch, err = New(sketchPath) done <- true diff --git a/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer1 b/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer1 deleted file mode 120000 index a96aa0ea9d8..00000000000 --- a/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer1 +++ /dev/null @@ -1 +0,0 @@ -.. \ No newline at end of file diff --git a/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer2 b/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer2 deleted file mode 120000 index a96aa0ea9d8..00000000000 --- a/arduino/sketch/testdata/SketchWithMultipleSymlinkLoops/src/UpGoer2 +++ /dev/null @@ -1 +0,0 @@ -.. \ No newline at end of file