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..14ae39d4fd9 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..8ac9c324b2c 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 := s2.AdditionalFiles[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 := s2.AdditionalFiles[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..f231402799c 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: paths.PathList{}, + AdditionalFiles: paths.PathList{}, + RootFolderFiles: 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 not 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 } -// CheckSketchCasing returns an error if the casing of the sketch folder and the main file are different. +// 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. // Correct: // MySketch/MySketch.ino // Wrong: @@ -152,33 +219,67 @@ 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) + candidateFileNames := []string{} + for ext := range globals.MainFileValidExtensions { + candidateFileNames = append(candidateFileNames, fmt.Sprintf("%s%s", s.Name, ext)) + } + files.FilterPrefix(candidateFileNames...) 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..f203491b250 100644 --- a/arduino/sketch/sketch_test.go +++ b/arduino/sketch/sketch_test.go @@ -17,158 +17,384 @@ package sketch import ( "fmt" - "path/filepath" - "sort" + "os" "testing" + "time" "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/assert" "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) + require.NotNil(t, sketch) + require.NoError(t, err) + 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() - sketch, err := New(sketchPath.String(), mainFilePath, "", []string{mainFilePath, templateFile}) + 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]) +} + +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.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.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 + 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 + 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") + 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 + 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/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/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/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/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..cc8fd1ed92f 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 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) + return nil, fmt.Errorf("error loading sketch %v: %v", req.SketchPath, err) } - otherSketchFiles := make([]string, len(sketch.OtherSketchFiles)) + otherSketchFiles := make([]string, sketch.OtherSketchFiles.Len()) for i, file := range sketch.OtherSketchFiles { - otherSketchFiles[i] = file.Path + otherSketchFiles[i] = file.String() } - additionalFiles := make([]string, len(sketch.AdditionalFiles)) + additionalFiles := make([]string, sketch.AdditionalFiles.Len()) for i, file := range sketch.AdditionalFiles { - additionalFiles[i] = file.Path + additionalFiles[i] = file.String() } - rootFolderFiles := make([]string, len(sketch.RootFolderFiles)) + rootFolderFiles := make([]string, sketch.RootFolderFiles.Len()) for i, file := range sketch.RootFolderFiles { - rootFolderFiles[i] = file.Path + 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/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 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/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..38649845aea 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) + fileNames.Add(ctx.Sketch.MainFile) for _, file := range ctx.Sketch.OtherSketchFiles { - fileNames = append(fileNames, file.Name) + 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..0f4e8d92ee1 100644 --- a/legacy/builder/test/ctags_runner_test.go +++ b/legacy/builder/test/ctags_runner_test.go @@ -220,7 +220,7 @@ func TestCTagsRunnerSketchWithNamespace(t *testing.T) { func TestCTagsRunnerSketchWithTemplates(t *testing.T) { DownloadCoresAndToolsAndLibraries(t) - sketchLocation := Abs(t, paths.New("sketch_with_templates_and_shift", "sketch_with_templates_and_shift.cpp")) + 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"), 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.ino similarity index 97% rename from legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.cpp rename to legacy/builder/test/sketch_with_templates_and_shift/sketch_with_templates_and_shift.ino index f4f1ece849f..c0dac664ef2 100644 --- 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.ino @@ -1,6 +1,6 @@ -template<> class FastPin<0> : public _ARMPIN<0, 10, 1 << 10, 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 FastPin<0> : public _ARMPIN<0, 10, 1 < 10, 0> {};; template class OtherType> class NestedTemplateClass { diff --git a/legacy/builder/types/context.go b/legacy/builder/types/context.go index 079733db662..c475460dd0b 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..8fd8996154c 100644 --- a/test/test_compile.py +++ b/test/test_compile.py @@ -132,7 +132,7 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir): 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 "Error during build: opening sketch" in result.stderr assert not result.ok sketch_name = "CompileIntegrationTestSymlinkDirLoop" @@ -152,9 +152,9 @@ 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 + # 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 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy