diff --git a/src/arduino.cc/builder/collect_all_source_files_from_folders_with_sources.go b/src/arduino.cc/builder/collect_all_source_files_from_folders_with_sources.go index efd51c18..b9bc589f 100644 --- a/src/arduino.cc/builder/collect_all_source_files_from_folders_with_sources.go +++ b/src/arduino.cc/builder/collect_all_source_files_from_folders_with_sources.go @@ -30,14 +30,9 @@ package builder import ( - "arduino.cc/builder/gohasissues" "arduino.cc/builder/i18n" "arduino.cc/builder/types" "arduino.cc/builder/utils" - "io/ioutil" - "os" - "path/filepath" - "strings" ) type CollectAllSourceFilesFromFoldersWithSources struct{} @@ -45,16 +40,12 @@ type CollectAllSourceFilesFromFoldersWithSources struct{} func (s *CollectAllSourceFilesFromFoldersWithSources) Run(ctx *types.Context) error { foldersWithSources := ctx.FoldersWithSourceFiles sourceFiles := ctx.CollectedSourceFiles + extensions := func(ext string) bool { return ADDITIONAL_FILE_VALID_EXTENSIONS_NO_HEADERS[ext] } filePaths := []string{} for !foldersWithSources.Empty() { sourceFolder := foldersWithSources.Pop().(types.SourceFolder) - var err error - if sourceFolder.Recurse { - err = collectByWalk(&filePaths, sourceFolder.Folder) - } else { - err = collectByReadDir(&filePaths, sourceFolder.Folder) - } + err := utils.FindFilesInFolder(&filePaths, sourceFolder.Folder, extensions, sourceFolder.Recurse) if err != nil { return i18n.WrapError(err) } @@ -66,32 +57,3 @@ func (s *CollectAllSourceFilesFromFoldersWithSources) Run(ctx *types.Context) er return nil } - -func collectByWalk(filePaths *[]string, folder string) error { - checkExtensionFunc := func(filePath string) bool { - name := filepath.Base(filePath) - ext := strings.ToLower(filepath.Ext(filePath)) - return !strings.HasPrefix(name, ".") && ADDITIONAL_FILE_VALID_EXTENSIONS_NO_HEADERS[ext] - } - walkFunc := utils.CollectAllReadableFiles(filePaths, checkExtensionFunc) - err := gohasissues.Walk(folder, walkFunc) - return i18n.WrapError(err) -} - -func collectByReadDir(filePaths *[]string, folder string) error { - if _, err := os.Stat(folder); err != nil && os.IsNotExist(err) { - return nil - } - - files, err := ioutil.ReadDir(folder) - if err != nil { - return i18n.WrapError(err) - } - for _, file := range files { - ext := strings.ToLower(filepath.Ext(file.Name())) - if ADDITIONAL_FILE_VALID_EXTENSIONS_NO_HEADERS[ext] { - *filePaths = append(*filePaths, filepath.Join(folder, file.Name())) - } - } - return nil -} diff --git a/src/arduino.cc/builder/constants/constants.go b/src/arduino.cc/builder/constants/constants.go index 90bff350..8253049d 100644 --- a/src/arduino.cc/builder/constants/constants.go +++ b/src/arduino.cc/builder/constants/constants.go @@ -204,6 +204,7 @@ const RECIPE_S_PATTERN = "recipe.S.o.pattern" const REWRITING_DISABLED = "disabled" const REWRITING = "rewriting" const SPACE = " " +const SKETCH_FOLDER_SRC = "src" const TOOL_NAME = "name" const TOOL_URL = "url" const TOOL_VERSION = "version" diff --git a/src/arduino.cc/builder/phases/sketch_builder.go b/src/arduino.cc/builder/phases/sketch_builder.go index dcdc4d47..d1a3fc48 100644 --- a/src/arduino.cc/builder/phases/sketch_builder.go +++ b/src/arduino.cc/builder/phases/sketch_builder.go @@ -34,6 +34,9 @@ import ( "arduino.cc/builder/i18n" "arduino.cc/builder/types" "arduino.cc/builder/utils" + "arduino.cc/builder/constants" + "path/filepath" + "os" ) type SketchBuilder struct{} @@ -53,11 +56,20 @@ func (s *SketchBuilder) Run(ctx *types.Context) error { } var objectFiles []string - objectFiles, err = builder_utils.CompileFiles(objectFiles, sketchBuildPath, true, sketchBuildPath, buildProperties, includes, verbose, warningsLevel, logger) + objectFiles, err = builder_utils.CompileFiles(objectFiles, sketchBuildPath, false, sketchBuildPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { return i18n.WrapError(err) } + // The "src/" subdirectory of a sketch is compiled recursively + sketchSrcPath := filepath.Join(sketchBuildPath, constants.SKETCH_FOLDER_SRC) + if info, err := os.Stat(sketchSrcPath); err == nil && info.IsDir() { + objectFiles, err = builder_utils.CompileFiles(objectFiles, sketchSrcPath, true, sketchSrcPath, buildProperties, includes, verbose, warningsLevel, logger) + if err != nil { + return i18n.WrapError(err) + } + } + ctx.SketchObjectFiles = objectFiles return nil diff --git a/src/arduino.cc/builder/sketch_loader.go b/src/arduino.cc/builder/sketch_loader.go index dba7ce3c..994af90f 100644 --- a/src/arduino.cc/builder/sketch_loader.go +++ b/src/arduino.cc/builder/sketch_loader.go @@ -31,7 +31,6 @@ package builder import ( "arduino.cc/builder/constants" - "arduino.cc/builder/gohasissues" "arduino.cc/builder/i18n" "arduino.cc/builder/types" "arduino.cc/builder/utils" @@ -89,13 +88,21 @@ func (s *SketchLoader) Run(ctx *types.Context) error { func collectAllSketchFiles(from string) ([]string, error) { filePaths := []string{} - checkExtensionFunc := func(filePath string) bool { - name := filepath.Base(filePath) - ext := strings.ToLower(filepath.Ext(filePath)) - return !strings.HasPrefix(name, ".") && MAIN_FILE_VALID_EXTENSIONS[ext] || ADDITIONAL_FILE_VALID_EXTENSIONS[ext] + // 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, rootExtensions, /* recurse */ false) + if err != nil { + return nil, i18n.WrapError(err) + } + + // The "src/" subdirectory of a sketch is compiled recursively + // (but .ino files are *not* compiled) + srcPath := filepath.Join(from, constants.SKETCH_FOLDER_SRC) + if info, err := os.Stat(srcPath); err == nil && info.IsDir() { + srcExtensions := func(ext string) bool { return ADDITIONAL_FILE_VALID_EXTENSIONS[ext] } + err = utils.FindFilesInFolder(&filePaths, srcPath, srcExtensions, /* recurse */ true) } - walkFunc := utils.CollectAllReadableFiles(&filePaths, checkExtensionFunc) - err := gohasissues.Walk(from, walkFunc) return filePaths, i18n.WrapError(err) } diff --git a/src/arduino.cc/builder/test/additional_sketch_files_copier_test.go b/src/arduino.cc/builder/test/additional_sketch_files_copier_test.go index 85d39cb9..c7b1ede3 100644 --- a/src/arduino.cc/builder/test/additional_sketch_files_copier_test.go +++ b/src/arduino.cc/builder/test/additional_sketch_files_copier_test.go @@ -83,9 +83,9 @@ func TestCopyOtherFiles(t *testing.T) { sort.Sort(ByFileInfoName(files)) require.Equal(t, "header.h", files[0].Name()) require.Equal(t, "s_file.S", files[1].Name()) - require.Equal(t, "subfolder", files[2].Name()) + require.Equal(t, "src", files[2].Name()) - files, err1 = gohasissues.ReadDir(filepath.Join(buildPath, constants.FOLDER_SKETCH, "subfolder")) + files, err1 = gohasissues.ReadDir(filepath.Join(buildPath, constants.FOLDER_SKETCH, "src")) NoError(t, err1) require.Equal(t, 1, len(files)) require.Equal(t, "helper.h", files[0].Name()) diff --git a/src/arduino.cc/builder/test/builder_test.go b/src/arduino.cc/builder/test/builder_test.go index 5aeb8f4c..3244c705 100644 --- a/src/arduino.cc/builder/test/builder_test.go +++ b/src/arduino.cc/builder/test/builder_test.go @@ -373,3 +373,32 @@ func TestBuilderSketchBuildPathContainsUnusedPreviouslyCompiledLibrary(t *testin _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_LIBRARIES, "Bridge")) NoError(t, err) } + +func TestBuilderWithBuildPathInSketchDir(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + ctx := &types.Context{ + HardwareFolders: []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"}, + ToolsFolders: []string{"downloaded_tools"}, + BuiltInLibrariesFolders: []string{"downloaded_libraries"}, + OtherLibrariesFolders: []string{"libraries"}, + SketchLocation: filepath.Join("sketch1", "sketch.ino"), + FQBN: "arduino:avr:uno", + ArduinoAPIVersion: "10600", + Verbose: true, + } + + var err error + ctx.BuildPath, err = filepath.Abs(filepath.Join("sketch1", "build")) + NoError(t, err) + defer os.RemoveAll(ctx.BuildPath) + + command := builder.Builder{} + err = command.Run(ctx) + NoError(t, err) + + // Run build twice, to verify the build still works when the + // build directory is present at the start + err = command.Run(ctx) + NoError(t, err) +} diff --git a/src/arduino.cc/builder/test/collect_all_source_files_from_folders_with_sources_test.go b/src/arduino.cc/builder/test/collect_all_source_files_from_folders_with_sources_test.go index 6b92d840..ce9ab58f 100644 --- a/src/arduino.cc/builder/test/collect_all_source_files_from_folders_with_sources_test.go +++ b/src/arduino.cc/builder/test/collect_all_source_files_from_folders_with_sources_test.go @@ -60,7 +60,7 @@ func TestCollectAllSourceFilesFromFoldersWithSources(t *testing.T) { require.Equal(t, 0, len(*foldersWithSources)) sort.Strings(*sourceFiles) - require.Equal(t, Abs(t, filepath.Join("sketch_with_config", "includes", "de bug.cpp")), sourceFiles.Pop()) + require.Equal(t, Abs(t, filepath.Join("sketch_with_config", "src", "includes", "de bug.cpp")), sourceFiles.Pop()) require.Equal(t, 0, len(*sourceFiles)) } @@ -106,7 +106,6 @@ func TestCollectAllSourceFilesFromFoldersWithSourcesOfOldLibrary(t *testing.T) { foldersWithSources := &types.UniqueSourceFolderQueue{} foldersWithSources.Push(types.SourceFolder{Folder: Abs(t, filepath.Join("libraries", "ShouldNotRecurseWithOldLibs")), Recurse: false}) foldersWithSources.Push(types.SourceFolder{Folder: Abs(t, filepath.Join("libraries", "ShouldNotRecurseWithOldLibs", "utility")), Recurse: false}) - foldersWithSources.Push(types.SourceFolder{Folder: Abs(t, "non existent folder"), Recurse: false}) ctx.FoldersWithSourceFiles = foldersWithSources commands := []types.Command{ diff --git a/src/arduino.cc/builder/test/sketch1/subfolder/helper.h b/src/arduino.cc/builder/test/sketch1/src/helper.h similarity index 100% rename from src/arduino.cc/builder/test/sketch1/subfolder/helper.h rename to src/arduino.cc/builder/test/sketch1/src/helper.h diff --git a/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.ino b/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.ino index 4aa85179..08390371 100644 --- a/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.ino +++ b/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.ino @@ -1,7 +1,7 @@ #include "config.h" #ifdef DEBUG -#include "includes/de bug.h" +#include "src/includes/de bug.h" #endif #ifdef UNDEF diff --git a/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt b/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt index 89ddbf6f..0216d1d0 100644 --- a/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt @@ -4,7 +4,7 @@ #include "config.h" #ifdef DEBUG -#include "includes/de bug.h" +#include "src/includes/de bug.h" #endif #ifdef UNDEF diff --git a/src/arduino.cc/builder/test/sketch_with_config/includes/de bug.cpp b/src/arduino.cc/builder/test/sketch_with_config/src/includes/de bug.cpp similarity index 100% rename from src/arduino.cc/builder/test/sketch_with_config/includes/de bug.cpp rename to src/arduino.cc/builder/test/sketch_with_config/src/includes/de bug.cpp diff --git a/src/arduino.cc/builder/test/sketch_with_config/includes/de bug.h b/src/arduino.cc/builder/test/sketch_with_config/src/includes/de bug.h similarity index 100% rename from src/arduino.cc/builder/test/sketch_with_config/includes/de bug.h rename to src/arduino.cc/builder/test/sketch_with_config/src/includes/de bug.h diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/sketch_with_subfolders.ino b/src/arduino.cc/builder/test/sketch_with_subfolders/sketch_with_subfolders.ino index 738378f1..e950b47e 100644 --- a/src/arduino.cc/builder/test/sketch_with_subfolders/sketch_with_subfolders.ino +++ b/src/arduino.cc/builder/test/sketch_with_subfolders/sketch_with_subfolders.ino @@ -1,4 +1,4 @@ -#include "subfolder/other.h" +#include "src/subfolder/other.h" MyClass myClass; @@ -7,4 +7,4 @@ void setup() { } void loop() { -} \ No newline at end of file +} diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/src/subfolder/dont_load_me.ino b/src/arduino.cc/builder/test/sketch_with_subfolders/src/subfolder/dont_load_me.ino new file mode 100644 index 00000000..1d32675e --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_subfolders/src/subfolder/dont_load_me.ino @@ -0,0 +1 @@ +#error "Whattya looking at?" diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.cpp b/src/arduino.cc/builder/test/sketch_with_subfolders/src/subfolder/other.cpp similarity index 100% rename from src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.cpp rename to src/arduino.cc/builder/test/sketch_with_subfolders/src/subfolder/other.cpp diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.h b/src/arduino.cc/builder/test/sketch_with_subfolders/src/subfolder/other.h similarity index 100% rename from src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.h rename to src/arduino.cc/builder/test/sketch_with_subfolders/src/subfolder/other.h diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/dont_load_me.cpp b/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/dont_load_me.cpp new file mode 100644 index 00000000..1d32675e --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/dont_load_me.cpp @@ -0,0 +1 @@ +#error "Whattya looking at?" diff --git a/src/arduino.cc/builder/types/types.go b/src/arduino.cc/builder/types/types.go index b9750197..2d7a1e46 100644 --- a/src/arduino.cc/builder/types/types.go +++ b/src/arduino.cc/builder/types/types.go @@ -34,6 +34,7 @@ import ( "arduino.cc/builder/props" "path/filepath" "strconv" + "os" ) type SketchFile struct { @@ -201,7 +202,9 @@ func LibraryToSourceFolder(library *Library) []SourceFolder { sourceFolders = append(sourceFolders, SourceFolder{Folder: library.SrcFolder, Recurse: recurse}) if library.Layout == LIBRARY_FLAT { utility := filepath.Join(library.SrcFolder, constants.LIBRARY_FOLDER_UTILITY) - sourceFolders = append(sourceFolders, SourceFolder{Folder: utility, Recurse: false}) + if info, err := os.Stat(utility); err == nil && info.IsDir() { + sourceFolders = append(sourceFolders, SourceFolder{Folder: utility, Recurse: false}) + } } return sourceFolders } diff --git a/src/arduino.cc/builder/utils/utils.go b/src/arduino.cc/builder/utils/utils.go index 16a11d18..350f4f95 100644 --- a/src/arduino.cc/builder/utils/utils.go +++ b/src/arduino.cc/builder/utils/utils.go @@ -304,30 +304,48 @@ func FilterOutFoldersByNames(folders []os.FileInfo, names ...string) []os.FileIn return filtered } -type CheckFilePathFunc func(filePath string) bool +type CheckExtensionFunc func(ext string) bool -func CollectAllReadableFiles(collector *[]string, test CheckFilePathFunc) filepath.WalkFunc { - walkFunc := func(currentPath string, info os.FileInfo, err error) error { +func FindFilesInFolder(files *[]string, folder string, extensions CheckExtensionFunc, recurse bool) error { + walkFunc := func(path string, info os.FileInfo, err error) error { if err != nil { return err } - if info.IsDir() { + // Skip source control and hidden files and directories + if IsSCCSOrHiddenFile(info) { + if info.IsDir() { + return filepath.SkipDir + } return nil } - if !test(currentPath) { + + // Skip directories unless recurse is on, or this is the + // root directory + if info.IsDir() { + if recurse || path == folder { + return nil + } else { + return filepath.SkipDir + } + } + + // Check (lowercased) extension against list of extensions + if extensions != nil && !extensions(strings.ToLower(filepath.Ext(path))) { return nil } - currentFile, err := os.Open(currentPath) + + // See if the file is readable by opening it + currentFile, err := os.Open(path) if err != nil { return nil } currentFile.Close() - *collector = append(*collector, currentPath) + *files = append(*files, path) return nil } - return walkFunc + return gohasissues.Walk(folder, walkFunc) } func AppendIfNotPresent(target []string, elements ...string) []string {