diff --git a/arduino/builder/build_options_manager.go b/arduino/builder/build_options_manager.go new file mode 100644 index 00000000000..3079ecf9ea6 --- /dev/null +++ b/arduino/builder/build_options_manager.go @@ -0,0 +1,182 @@ +// 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 ( + "encoding/json" + "path/filepath" + "strings" + + "github.com/arduino/arduino-cli/arduino/builder/logger" + "github.com/arduino/arduino-cli/arduino/builder/utils" + "github.com/arduino/arduino-cli/arduino/cores" + "github.com/arduino/arduino-cli/arduino/sketch" + "github.com/arduino/go-paths-helper" + properties "github.com/arduino/go-properties-orderedmap" + "github.com/pkg/errors" +) + +// BuildOptionsManager fixdoc +type BuildOptionsManager struct { + currentOptions *properties.Map + currentBuildOptionsJSON []byte + + hardwareDirs paths.PathList + builtInToolsDirs paths.PathList + otherLibrariesDirs paths.PathList + builtInLibrariesDirs *paths.Path + buildPath *paths.Path + runtimePlatformPath *paths.Path + buildCorePath *paths.Path + sketch *sketch.Sketch + customBuildProperties []string + compilerOptimizationFlags string + clean bool + builderLogger *logger.BuilderLogger +} + +// NewBuildOptionsManager fixdoc +func NewBuildOptionsManager( + hardwareDirs, builtInToolsDirs, otherLibrariesDirs paths.PathList, + builtInLibrariesDirs, buildPath *paths.Path, + sketch *sketch.Sketch, + customBuildProperties []string, + fqbn *cores.FQBN, + clean bool, + compilerOptimizationFlags string, + runtimePlatformPath, buildCorePath *paths.Path, + buildLogger *logger.BuilderLogger, +) *BuildOptionsManager { + opts := properties.NewMap() + + opts.Set("hardwareFolders", strings.Join(hardwareDirs.AsStrings(), ",")) + opts.Set("builtInToolsFolders", strings.Join(builtInToolsDirs.AsStrings(), ",")) + opts.Set("otherLibrariesFolders", strings.Join(otherLibrariesDirs.AsStrings(), ",")) + opts.SetPath("sketchLocation", sketch.FullPath) + opts.Set("fqbn", fqbn.String()) + opts.Set("customBuildProperties", strings.Join(customBuildProperties, ",")) + opts.Set("compiler.optimization_flags", compilerOptimizationFlags) + + if builtInLibrariesDirs != nil { + opts.Set("builtInLibrariesFolders", builtInLibrariesDirs.String()) + } + + absPath := sketch.FullPath.Parent() + var additionalFilesRelative []string + for _, f := range sketch.AdditionalFiles { + relPath, err := f.RelTo(absPath) + if err != nil { + continue // ignore + } + additionalFilesRelative = append(additionalFilesRelative, relPath.String()) + } + opts.Set("additionalFiles", strings.Join(additionalFilesRelative, ",")) + + return &BuildOptionsManager{ + currentOptions: opts, + hardwareDirs: hardwareDirs, + builtInToolsDirs: builtInToolsDirs, + otherLibrariesDirs: otherLibrariesDirs, + builtInLibrariesDirs: builtInLibrariesDirs, + buildPath: buildPath, + runtimePlatformPath: runtimePlatformPath, + buildCorePath: buildCorePath, + sketch: sketch, + customBuildProperties: customBuildProperties, + compilerOptimizationFlags: compilerOptimizationFlags, + clean: clean, + builderLogger: buildLogger, + } +} + +// WipeBuildPath fixdoc +func (m *BuildOptionsManager) WipeBuildPath() error { + buildOptionsJSON, err := json.MarshalIndent(m.currentOptions, "", " ") + if err != nil { + return errors.WithStack(err) + } + m.currentBuildOptionsJSON = buildOptionsJSON + + if err := m.wipeBuildPath(); err != nil { + return errors.WithStack(err) + } + return m.buildPath.Join("build.options.json").WriteFile(buildOptionsJSON) +} + +func (m *BuildOptionsManager) wipeBuildPath() error { + wipe := func() error { + // FIXME: this should go outside legacy and behind a `logrus` call so users can + // control when this should be printed. + // logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_BUILD_OPTIONS_CHANGED + constants.MSG_REBUILD_ALL) + if err := m.buildPath.RemoveAll(); err != nil { + return errors.WithMessage(err, tr("cleaning build path")) + } + if err := m.buildPath.MkdirAll(); err != nil { + return errors.WithMessage(err, tr("cleaning build path")) + } + return nil + } + + if m.clean { + return wipe() + } + + // Load previous build options map + var buildOptionsJSONPrevious []byte + var _err error + if buildOptionsFile := m.buildPath.Join("build.options.json"); buildOptionsFile.Exist() { + buildOptionsJSONPrevious, _err = buildOptionsFile.ReadFile() + if _err != nil { + return errors.WithStack(_err) + } + } + + if len(buildOptionsJSONPrevious) == 0 { + return nil + } + + var prevOpts *properties.Map + if err := json.Unmarshal(buildOptionsJSONPrevious, &prevOpts); err != nil || prevOpts == nil { + m.builderLogger.Info(tr("%[1]s invalid, rebuilding all", "build.options.json")) + return wipe() + } + + // If SketchLocation path is different but filename is the same, consider it equal + if filepath.Base(m.currentOptions.Get("sketchLocation")) == filepath.Base(prevOpts.Get("sketchLocation")) { + m.currentOptions.Remove("sketchLocation") + prevOpts.Remove("sketchLocation") + } + + // If options are not changed check if core has + if m.currentOptions.Equals(prevOpts) { + // check if any of the files contained in the core folders has changed + // since the json was generated - like platform.txt or similar + // if so, trigger a "safety" wipe + targetCoreFolder := m.runtimePlatformPath + coreFolder := m.buildCorePath + realCoreFolder := coreFolder.Parent().Parent() + jsonPath := m.buildPath.Join("build.options.json") + coreUnchanged, _ := utils.DirContentIsOlderThan(realCoreFolder, jsonPath, ".txt") + if coreUnchanged && targetCoreFolder != nil && !realCoreFolder.EqualsTo(targetCoreFolder) { + coreUnchanged, _ = utils.DirContentIsOlderThan(targetCoreFolder, jsonPath, ".txt") + } + if coreUnchanged { + return nil + } + } + + return wipe() +} diff --git a/arduino/builder/builder.go b/arduino/builder/builder.go index 32bd35d7e68..a856106d574 100644 --- a/arduino/builder/builder.go +++ b/arduino/builder/builder.go @@ -16,21 +16,81 @@ package builder import ( + "errors" + "fmt" + + "github.com/arduino/arduino-cli/arduino/builder/compilation" + "github.com/arduino/arduino-cli/arduino/builder/logger" + "github.com/arduino/arduino-cli/arduino/builder/progress" + "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" ) +// ErrSketchCannotBeLocatedInBuildPath fixdoc +var ErrSketchCannotBeLocatedInBuildPath = errors.New("sketch cannot be located in build path") + // Builder is a Sketch builder. type Builder struct { sketch *sketch.Sketch buildProperties *properties.Map + buildPath *paths.Path + sketchBuildPath *paths.Path + coreBuildPath *paths.Path + librariesBuildPath *paths.Path + // Parallel processes jobs int + // Custom build properties defined by user (line by line as "key=value" pairs) + customBuildProperties []string + // core related coreBuildCachePath *paths.Path + + logger *logger.BuilderLogger + clean bool + + // Source code overrides (filename -> content map). + // The provided source data is used instead of reading it from disk. + // The keys of the map are paths relative to sketch folder. + sourceOverrides map[string]string + + // Set to true to skip build and produce only Compilation Database + onlyUpdateCompilationDatabase bool + // Compilation Database to build/update + compilationDatabase *compilation.Database + + // Progress of all various steps + Progress *progress.Struct + + // Sizer results + executableSectionsSize ExecutablesFileSections + + // C++ Parsing + lineOffset int + + targetPlatform *cores.PlatformRelease + actualPlatform *cores.PlatformRelease + + buildArtifacts *BuildArtifacts + + *BuildOptionsManager +} + +// BuildArtifacts contains the result of various build +type BuildArtifacts struct { + // populated by BuildCore + coreArchiveFilePath *paths.Path + coreObjectsFiles paths.PathList + + // populated by BuildLibraries + librariesObjectFiles paths.PathList + + // populated by BuildSketch + sketchObjectFiles paths.PathList } // NewBuilder creates a sketch Builder. @@ -41,7 +101,17 @@ func NewBuilder( optimizeForDebug bool, coreBuildCachePath *paths.Path, jobs int, -) *Builder { + requestBuildProperties []string, + hardwareDirs, builtInToolsDirs, otherLibrariesDirs paths.PathList, + builtInLibrariesDirs *paths.Path, + fqbn *cores.FQBN, + clean bool, + sourceOverrides map[string]string, + onlyUpdateCompilationDatabase bool, + targetPlatform, actualPlatform *cores.PlatformRelease, + logger *logger.BuilderLogger, + progressStats *progress.Struct, +) (*Builder, error) { buildProperties := properties.NewMap() if boardBuildProperties != nil { buildProperties.Merge(boardBuildProperties) @@ -64,12 +134,68 @@ func NewBuilder( } } - return &Builder{ - sketch: sk, - buildProperties: buildProperties, - coreBuildCachePath: coreBuildCachePath, - jobs: jobs, + // Add user provided custom build properties + customBuildProperties, err := properties.LoadFromSlice(requestBuildProperties) + if err != nil { + return nil, fmt.Errorf("invalid build properties: %w", err) + } + buildProperties.Merge(customBuildProperties) + customBuildPropertiesArgs := append(requestBuildProperties, "build.warn_data_percentage=75") + + sketchBuildPath, err := buildPath.Join("sketch").Abs() + if err != nil { + return nil, err } + librariesBuildPath, err := buildPath.Join("libraries").Abs() + if err != nil { + return nil, err + } + coreBuildPath, err := buildPath.Join("core").Abs() + if err != nil { + return nil, err + } + + if buildPath.Canonical().EqualsTo(sk.FullPath.Canonical()) { + return nil, ErrSketchCannotBeLocatedInBuildPath + } + + if progressStats == nil { + progressStats = progress.New(nil) + } + + return &Builder{ + sketch: sk, + buildProperties: buildProperties, + buildPath: buildPath, + sketchBuildPath: sketchBuildPath, + coreBuildPath: coreBuildPath, + librariesBuildPath: librariesBuildPath, + jobs: jobs, + customBuildProperties: customBuildPropertiesArgs, + coreBuildCachePath: coreBuildCachePath, + logger: logger, + clean: clean, + sourceOverrides: sourceOverrides, + onlyUpdateCompilationDatabase: onlyUpdateCompilationDatabase, + compilationDatabase: compilation.NewDatabase(buildPath.Join("compile_commands.json")), + Progress: progressStats, + executableSectionsSize: []ExecutableSectionSize{}, + buildArtifacts: &BuildArtifacts{}, + targetPlatform: targetPlatform, + actualPlatform: actualPlatform, + BuildOptionsManager: NewBuildOptionsManager( + hardwareDirs, builtInToolsDirs, otherLibrariesDirs, + builtInLibrariesDirs, buildPath, + sk, + customBuildPropertiesArgs, + fqbn, + clean, + buildProperties.Get("compiler.optimization_flags"), + buildProperties.GetPath("runtime.platform.path"), + buildProperties.GetPath("build.core.path"), // TODO can we buildCorePath ? + logger, + ), + }, nil } // GetBuildProperties returns the build properties for running this build @@ -77,7 +203,34 @@ func (b *Builder) GetBuildProperties() *properties.Map { return b.buildProperties } -// Jobs number of parallel processes -func (b *Builder) Jobs() int { - return b.jobs +// GetBuildPath returns the build path +func (b *Builder) GetBuildPath() *paths.Path { + return b.buildPath +} + +// GetSketchBuildPath returns the sketch build path +func (b *Builder) GetSketchBuildPath() *paths.Path { + return b.sketchBuildPath +} + +// GetLibrariesBuildPath returns the libraries build path +func (b *Builder) GetLibrariesBuildPath() *paths.Path { + return b.librariesBuildPath +} + +// ExecutableSectionsSize fixdoc +func (b *Builder) ExecutableSectionsSize() ExecutablesFileSections { + return b.executableSectionsSize +} + +// SaveCompilationDatabase fixdoc +func (b *Builder) SaveCompilationDatabase() { + if b.compilationDatabase != nil { + b.compilationDatabase.SaveToFile() + } +} + +// TargetPlatform fixdoc +func (b *Builder) TargetPlatform() *cores.PlatformRelease { + return b.targetPlatform } diff --git a/arduino/builder/core.go b/arduino/builder/core.go index 9bec697cb96..2fcbb682a7c 100644 --- a/arduino/builder/core.go +++ b/arduino/builder/core.go @@ -22,80 +22,45 @@ import ( "os" "strings" - "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/cpp" - "github.com/arduino/arduino-cli/arduino/builder/logger" - "github.com/arduino/arduino-cli/arduino/builder/progress" "github.com/arduino/arduino-cli/arduino/builder/utils" - "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/buildcache" f "github.com/arduino/arduino-cli/internal/algorithms" - rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" ) -// CoreBuildCachePath fixdoc -func (b *Builder) CoreBuildCachePath() *paths.Path { - return b.coreBuildCachePath -} - -// CoreBuilder fixdoc -func CoreBuilder( - buildPath, coreBuildPath, coreBuildCachePath *paths.Path, - buildProperties *properties.Map, - actualPlatform *cores.PlatformRelease, - onlyUpdateCompilationDatabase, clean bool, - compilationDatabase *compilation.Database, - jobs int, - builderLogger *logger.BuilderLogger, - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (paths.PathList, *paths.Path, error) { - if err := coreBuildPath.MkdirAll(); err != nil { - return nil, nil, errors.WithStack(err) +// BuildCore fixdoc +func (b *Builder) BuildCore() error { + if err := b.coreBuildPath.MkdirAll(); err != nil { + return errors.WithStack(err) } - if coreBuildCachePath != nil { - if _, err := coreBuildCachePath.RelTo(buildPath); err != nil { - builderLogger.Info(tr("Couldn't deeply cache core build: %[1]s", err)) - builderLogger.Info(tr("Running normal build of the core...")) - coreBuildCachePath = nil - } else if err := coreBuildCachePath.MkdirAll(); err != nil { - return nil, nil, errors.WithStack(err) + if b.coreBuildCachePath != nil { + if _, err := b.coreBuildCachePath.RelTo(b.buildPath); err != nil { + b.logger.Info(tr("Couldn't deeply cache core build: %[1]s", err)) + b.logger.Info(tr("Running normal build of the core...")) + // TODO decide if we want to override this or not. (It's only used by the + // compileCore function). + b.coreBuildCachePath = nil + } else if err := b.coreBuildCachePath.MkdirAll(); err != nil { + return errors.WithStack(err) } } - archiveFile, objectFiles, err := compileCore( - onlyUpdateCompilationDatabase, clean, - actualPlatform, - coreBuildPath, coreBuildCachePath, - buildProperties, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, - ) + archiveFile, objectFiles, err := b.compileCore() if err != nil { - return nil, nil, errors.WithStack(err) + return errors.WithStack(err) } - - return objectFiles, archiveFile, nil + b.buildArtifacts.coreObjectsFiles = objectFiles + b.buildArtifacts.coreArchiveFilePath = archiveFile + return nil } -func compileCore( - onlyUpdateCompilationDatabase, clean bool, - actualPlatform *cores.PlatformRelease, - buildPath, buildCachePath *paths.Path, - buildProperties *properties.Map, - compilationDatabase *compilation.Database, - jobs int, - builderLogger *logger.BuilderLogger, - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (*paths.Path, paths.PathList, error) { - coreFolder := buildProperties.GetPath("build.core.path") - variantFolder := buildProperties.GetPath("build.variant.path") - targetCoreFolder := buildProperties.GetPath("runtime.platform.path") +func (b *Builder) compileCore() (*paths.Path, paths.PathList, error) { + coreFolder := b.buildProperties.GetPath("build.core.path") + variantFolder := b.buildProperties.GetPath("build.variant.path") + targetCoreFolder := b.buildProperties.GetPath("runtime.platform.path") includes := []string{coreFolder.String()} if variantFolder != nil && variantFolder.IsDir() { @@ -107,12 +72,12 @@ func compileCore( variantObjectFiles := paths.NewPathList() if variantFolder != nil && variantFolder.IsDir() { variantObjectFiles, err = utils.CompileFilesRecursive( - variantFolder, buildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, + variantFolder, b.coreBuildPath, b.buildProperties, includes, + b.onlyUpdateCompilationDatabase, + b.compilationDatabase, + b.jobs, + b.logger, + b.Progress, ) if err != nil { return nil, nil, errors.WithStack(err) @@ -120,21 +85,21 @@ func compileCore( } var targetArchivedCore *paths.Path - if buildCachePath != nil { + if b.coreBuildCachePath != nil { realCoreFolder := coreFolder.Parent().Parent() - archivedCoreName := GetCachedCoreArchiveDirName( - buildProperties.Get("build.fqbn"), - buildProperties.Get("compiler.optimization_flags"), + archivedCoreName := getCachedCoreArchiveDirName( + b.buildProperties.Get("build.fqbn"), + b.buildProperties.Get("compiler.optimization_flags"), realCoreFolder, ) - targetArchivedCore = buildCachePath.Join(archivedCoreName, "core.a") + targetArchivedCore = b.coreBuildCachePath.Join(archivedCoreName, "core.a") - if _, err := buildcache.New(buildCachePath).GetOrCreate(archivedCoreName); errors.Is(err, buildcache.CreateDirErr) { + if _, err := buildcache.New(b.coreBuildCachePath).GetOrCreate(archivedCoreName); errors.Is(err, buildcache.CreateDirErr) { return nil, nil, fmt.Errorf(tr("creating core cache folder: %s", err)) } var canUseArchivedCore bool - if onlyUpdateCompilationDatabase || clean { + if b.onlyUpdateCompilationDatabase || b.clean { canUseArchivedCore = false } else if isOlder, err := utils.DirContentIsOlderThan(realCoreFolder, targetArchivedCore); err != nil || !isOlder { // Recreate the archive if ANY of the core files (including platform.txt) has changed @@ -150,48 +115,48 @@ func compileCore( if canUseArchivedCore { // use archived core - if builderLogger.Verbose() { - builderLogger.Info(tr("Using precompiled core: %[1]s", targetArchivedCore)) + if b.logger.Verbose() { + b.logger.Info(tr("Using precompiled core: %[1]s", targetArchivedCore)) } return targetArchivedCore, variantObjectFiles, nil } } coreObjectFiles, err := utils.CompileFilesRecursive( - coreFolder, buildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, + coreFolder, b.coreBuildPath, b.buildProperties, includes, + b.onlyUpdateCompilationDatabase, + b.compilationDatabase, + b.jobs, + b.logger, + b.Progress, ) if err != nil { return nil, nil, errors.WithStack(err) } archiveFile, verboseInfo, err := utils.ArchiveCompiledFiles( - buildPath, paths.New("core.a"), coreObjectFiles, buildProperties, - onlyUpdateCompilationDatabase, builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), + b.coreBuildPath, paths.New("core.a"), coreObjectFiles, b.buildProperties, + b.onlyUpdateCompilationDatabase, b.logger.Verbose(), b.logger.Stdout(), b.logger.Stderr(), ) - if builderLogger.Verbose() { - builderLogger.Info(string(verboseInfo)) + if b.logger.Verbose() { + b.logger.Info(string(verboseInfo)) } if err != nil { return nil, nil, errors.WithStack(err) } // archive core.a - if targetArchivedCore != nil && !onlyUpdateCompilationDatabase { + if targetArchivedCore != nil && !b.onlyUpdateCompilationDatabase { err := archiveFile.CopyTo(targetArchivedCore) - if builderLogger.Verbose() { + if b.logger.Verbose() { if err == nil { - builderLogger.Info(tr("Archiving built core (caching) in: %[1]s", targetArchivedCore)) + b.logger.Info(tr("Archiving built core (caching) in: %[1]s", targetArchivedCore)) } else if os.IsNotExist(err) { - builderLogger.Info(tr("Unable to cache built core, please tell %[1]s maintainers to follow %[2]s", - actualPlatform, + b.logger.Info(tr("Unable to cache built core, please tell %[1]s maintainers to follow %[2]s", + b.actualPlatform, "https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-build-the-corea-archive-file")) } else { - builderLogger.Info(tr("Error archiving built core (caching) in %[1]s: %[2]s", targetArchivedCore, err)) + b.logger.Info(tr("Error archiving built core (caching) in %[1]s: %[2]s", targetArchivedCore, err)) } } } @@ -199,9 +164,9 @@ func compileCore( return archiveFile, variantObjectFiles, nil } -// GetCachedCoreArchiveDirName returns the directory name to be used to store +// getCachedCoreArchiveDirName returns the directory name to be used to store // the global cached core.a. -func GetCachedCoreArchiveDirName(fqbn string, optimizationFlags string, coreFolder *paths.Path) string { +func getCachedCoreArchiveDirName(fqbn string, optimizationFlags string, coreFolder *paths.Path) string { fqbnToUnderscore := strings.ReplaceAll(fqbn, ":", "_") fqbnToUnderscore = strings.ReplaceAll(fqbnToUnderscore, "=", "_") if absCoreFolder, err := coreFolder.Abs(); err == nil { diff --git a/legacy/builder/create_cmake_rule.go b/arduino/builder/export_cmake.go similarity index 89% rename from legacy/builder/create_cmake_rule.go rename to arduino/builder/export_cmake.go index d24b31df8ad..de7bdf6db88 100644 --- a/legacy/builder/create_cmake_rule.go +++ b/arduino/builder/export_cmake.go @@ -30,22 +30,16 @@ import ( "github.com/arduino/arduino-cli/arduino/builder/utils" "github.com/arduino/arduino-cli/arduino/globals" "github.com/arduino/arduino-cli/arduino/libraries" - "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/arduino-cli/legacy/builder/constants" ) var lineMatcher = regexp.MustCompile(`^#line\s\d+\s"`) -func ExportProjectCMake( +// ExportProjectCMake fixdoc +func (b *Builder) ExportProjectCMake( sketchError bool, // Was there an error while compiling the sketch? - buildPath, sketchBuildPath *paths.Path, importedLibraries libraries.List, - buildProperties *properties.Map, - sketch *sketch.Sketch, includeFolders paths.PathList, - lineOffset int, - onlyUpdateCompilationDatabase bool, -) ([]byte, []byte, error) { +) error { // copies the contents of the file named src to the file named // by dst. The file will be created if it does not already exist. If the // destination file exists, all it's contents will be replaced by the contents @@ -182,12 +176,12 @@ func ExportProjectCMake( var validStaticLibExtensions = []string{".a"} // If sketch error or cannot export Cmake project - if sketchError || buildProperties.Get("compiler.export_cmake") == "" { - return nil, nil, nil + if sketchError || b.buildProperties.Get("compiler.export_cmake") == "" { + return nil } // Create new cmake subFolder - clean if the folder is already there - cmakeFolder := buildPath.Join("_cmake") + cmakeFolder := b.buildPath.Join("_cmake") if _, err := cmakeFolder.Stat(); err == nil { cmakeFolder.RemoveAll() } @@ -207,7 +201,7 @@ func ExportProjectCMake( for _, library := range importedLibraries { // Copy used libraries in the correct folder libDir := libBaseFolder.Join(library.DirName) - mcu := buildProperties.Get("build.mcu") + mcu := b.buildProperties.Get("build.mcu") copyDir(library.InstallDir.String(), libDir.String(), validExportExtensions) // Read cmake options if available @@ -238,28 +232,20 @@ func ExportProjectCMake( } // Copy core + variant in use + preprocessed sketch in the correct folders - err := copyDir(buildProperties.Get("build.core.path"), coreFolder.String(), validExportExtensions) + err := copyDir(b.buildProperties.Get("build.core.path"), coreFolder.String(), validExportExtensions) if err != nil { fmt.Println(err) } - err = copyDir(buildProperties.Get("build.variant.path"), coreFolder.Join("variant").String(), validExportExtensions) + err = copyDir(b.buildProperties.Get("build.variant.path"), coreFolder.Join("variant").String(), validExportExtensions) if err != nil { fmt.Println(err) } - normalOutput, verboseOutput, err := PreprocessSketch( - sketch, - buildPath, - includeFolders, - lineOffset, - buildProperties, - onlyUpdateCompilationDatabase, - ) - if err != nil { - return normalOutput, verboseOutput, err + if err := b.PreprocessSketch(includeFolders); err != nil { + return err } - err = copyDir(sketchBuildPath.String(), cmakeFolder.Join("sketch").String(), validExportExtensions) + err = copyDir(b.sketchBuildPath.String(), cmakeFolder.Join("sketch").String(), validExportExtensions) if err != nil { fmt.Println(err) } @@ -294,9 +280,9 @@ func ExportProjectCMake( var dynamicLibsFromGccMinusL []string var linkDirectories []string - extractCompileFlags(buildProperties, constants.RECIPE_C_COMBINE_PATTERN, &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories) - extractCompileFlags(buildProperties, "recipe.c.o.pattern", &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories) - extractCompileFlags(buildProperties, "recipe.cpp.o.pattern", &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories) + extractCompileFlags(b.buildProperties, "recipe.c.combine.pattern", &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories) + extractCompileFlags(b.buildProperties, "recipe.c.o.pattern", &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories) + extractCompileFlags(b.buildProperties, "recipe.cpp.o.pattern", &defines, &dynamicLibsFromGccMinusL, &linkerflags, &linkDirectories) // Extract folders with .h in them for adding in include list headerFiles, _ := utils.FindFilesInFolder(cmakeFolder, true, validHeaderExtensions...) @@ -307,7 +293,7 @@ func ExportProjectCMake( // Generate the CMakeLists global file - projectName := sketch.Name + projectName := b.sketch.Name cmakelist := "cmake_minimum_required(VERSION 3.5.0)\n" cmakelist += "INCLUDE(FindPkgConfig)\n" @@ -364,7 +350,7 @@ func ExportProjectCMake( cmakeFile.WriteFile([]byte(cmakelist)) - return normalOutput, verboseOutput, nil + return nil } func extractCompileFlags(buildProperties *properties.Map, recipe string, defines, dynamicLibs, linkerflags, linkDirectories *[]string) { diff --git a/arduino/builder/libraries.go b/arduino/builder/libraries.go index af2e899840d..f5b6a46957b 100644 --- a/arduino/builder/libraries.go +++ b/arduino/builder/libraries.go @@ -17,18 +17,16 @@ package builder import ( "strings" + "time" - "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/cpp" - "github.com/arduino/arduino-cli/arduino/builder/logger" - "github.com/arduino/arduino-cli/arduino/builder/progress" "github.com/arduino/arduino-cli/arduino/builder/utils" "github.com/arduino/arduino-cli/arduino/libraries" f "github.com/arduino/arduino-cli/internal/algorithms" - rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" + "golang.org/x/exp/slices" ) // nolint @@ -37,38 +35,21 @@ var ( FpuCflag = "fpu" ) -// LibrariesBuilder fixdoc -func LibrariesBuilder( - librariesBuildPath *paths.Path, - buildProperties *properties.Map, - includesFolders paths.PathList, - importedLibraries libraries.List, - onlyUpdateCompilationDatabase bool, - compilationDatabase *compilation.Database, - jobs int, - builderLogger *logger.BuilderLogger, - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (paths.PathList, error) { +// BuildLibraries fixdoc +func (b *Builder) BuildLibraries(includesFolders paths.PathList, importedLibraries libraries.List) error { includes := f.Map(includesFolders.AsStrings(), cpp.WrapWithHyphenI) libs := importedLibraries - if err := librariesBuildPath.MkdirAll(); err != nil { - return nil, errors.WithStack(err) + if err := b.librariesBuildPath.MkdirAll(); err != nil { + return errors.WithStack(err) } - librariesObjectFiles, err := compileLibraries( - libs, librariesBuildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, - ) + librariesObjectFiles, err := b.compileLibraries(libs, includes) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } - - return librariesObjectFiles, nil + b.buildArtifacts.librariesObjectFiles = librariesObjectFiles + return nil } func directoryContainsFile(folder *paths.Path) bool { @@ -79,10 +60,9 @@ func directoryContainsFile(folder *paths.Path) bool { return false } -func findExpectedPrecompiledLibFolder( +func (b *Builder) findExpectedPrecompiledLibFolder( library *libraries.Library, buildProperties *properties.Map, - builderLogger *logger.BuilderLogger, ) *paths.Path { mcu := buildProperties.Get("build.mcu") // Add fpu specifications if they exist @@ -109,79 +89,52 @@ func findExpectedPrecompiledLibFolder( } } - builderLogger.Info(tr("Library %[1]s has been declared precompiled:", library.Name)) + b.logger.Info(tr("Library %[1]s has been declared precompiled:", library.Name)) // Try directory with full fpuSpecs first, if available if len(fpuSpecs) > 0 { fpuSpecs = strings.TrimRight(fpuSpecs, "-") fullPrecompDir := library.SourceDir.Join(mcu).Join(fpuSpecs) if fullPrecompDir.Exist() && directoryContainsFile(fullPrecompDir) { - builderLogger.Info(tr("Using precompiled library in %[1]s", fullPrecompDir)) + b.logger.Info(tr("Using precompiled library in %[1]s", fullPrecompDir)) return fullPrecompDir } - builderLogger.Info(tr(`Precompiled library in "%[1]s" not found`, fullPrecompDir)) + b.logger.Info(tr(`Precompiled library in "%[1]s" not found`, fullPrecompDir)) } precompDir := library.SourceDir.Join(mcu) if precompDir.Exist() && directoryContainsFile(precompDir) { - builderLogger.Info(tr("Using precompiled library in %[1]s", precompDir)) + b.logger.Info(tr("Using precompiled library in %[1]s", precompDir)) return precompDir } - builderLogger.Info(tr(`Precompiled library in "%[1]s" not found`, precompDir)) + b.logger.Info(tr(`Precompiled library in "%[1]s" not found`, precompDir)) return nil } -func compileLibraries( - libraries libraries.List, buildPath *paths.Path, buildProperties *properties.Map, includes []string, - onlyUpdateCompilationDatabase bool, - compilationDatabase *compilation.Database, - jobs int, - builderLogger *logger.BuilderLogger, - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (paths.PathList, error) { - progress.AddSubSteps(len(libraries)) - defer progress.RemoveSubSteps() +func (b *Builder) compileLibraries(libraries libraries.List, includes []string) (paths.PathList, error) { + b.Progress.AddSubSteps(len(libraries)) + defer b.Progress.RemoveSubSteps() objectFiles := paths.NewPathList() for _, library := range libraries { - libraryObjectFiles, err := compileLibrary( - library, buildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, - ) + libraryObjectFiles, err := b.compileLibrary(library, includes) if err != nil { return nil, errors.WithStack(err) } objectFiles.AddAll(libraryObjectFiles) - progress.CompleteStep() - // PushProgress - if progressCB != nil { - progressCB(&rpc.TaskProgress{ - Percent: progress.Progress, - Completed: progress.Progress >= 100.0, - }) - } + b.Progress.CompleteStep() + b.Progress.PushProgress() } return objectFiles, nil } -func compileLibrary( - library *libraries.Library, buildPath *paths.Path, buildProperties *properties.Map, includes []string, - onlyUpdateCompilationDatabase bool, - compilationDatabase *compilation.Database, - jobs int, - builderLogger *logger.BuilderLogger, - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (paths.PathList, error) { - if builderLogger.Verbose() { - builderLogger.Info(tr(`Compiling library "%[1]s"`, library.Name)) +func (b *Builder) compileLibrary(library *libraries.Library, includes []string) (paths.PathList, error) { + if b.logger.Verbose() { + b.logger.Info(tr(`Compiling library "%[1]s"`, library.Name)) } - libraryBuildPath := buildPath.Join(library.DirName) + libraryBuildPath := b.librariesBuildPath.Join(library.DirName) if err := libraryBuildPath.MkdirAll(); err != nil { return nil, errors.WithStack(err) @@ -190,15 +143,14 @@ func compileLibrary( objectFiles := paths.NewPathList() if library.Precompiled { - coreSupportPrecompiled := buildProperties.ContainsKey("compiler.libraries.ldflags") - precompiledPath := findExpectedPrecompiledLibFolder( + coreSupportPrecompiled := b.buildProperties.ContainsKey("compiler.libraries.ldflags") + precompiledPath := b.findExpectedPrecompiledLibFolder( library, - buildProperties, - builderLogger, + b.buildProperties, ) if !coreSupportPrecompiled { - builderLogger.Info(tr("The platform does not support '%[1]s' for precompiled libraries.", "compiler.libraries.ldflags")) + b.logger.Info(tr("The platform does not support '%[1]s' for precompiled libraries.", "compiler.libraries.ldflags")) } else if precompiledPath != nil { // Find all libraries in precompiledPath libs, err := precompiledPath.ReadDir() @@ -217,8 +169,8 @@ func compileLibrary( } } - currLDFlags := buildProperties.Get("compiler.libraries.ldflags") - buildProperties.Set("compiler.libraries.ldflags", currLDFlags+" \"-L"+precompiledPath.String()+"\" "+libsCmd+" ") + currLDFlags := b.buildProperties.Get("compiler.libraries.ldflags") + b.buildProperties.Set("compiler.libraries.ldflags", currLDFlags+" \"-L"+precompiledPath.String()+"\" "+libsCmd+" ") // TODO: This codepath is just taken for .a with unusual names that would // be ignored by -L / -l methods. @@ -239,24 +191,24 @@ func compileLibrary( if library.Layout == libraries.RecursiveLayout { libObjectFiles, err := utils.CompileFilesRecursive( - library.SourceDir, libraryBuildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, + library.SourceDir, libraryBuildPath, b.buildProperties, includes, + b.onlyUpdateCompilationDatabase, + b.compilationDatabase, + b.jobs, + b.logger, + b.Progress, ) if err != nil { return nil, errors.WithStack(err) } if library.DotALinkage { archiveFile, verboseInfo, err := utils.ArchiveCompiledFiles( - libraryBuildPath, paths.New(library.DirName+".a"), libObjectFiles, buildProperties, - onlyUpdateCompilationDatabase, builderLogger.Verbose(), - builderLogger.Stdout(), builderLogger.Stderr(), + libraryBuildPath, paths.New(library.DirName+".a"), libObjectFiles, b.buildProperties, + b.onlyUpdateCompilationDatabase, b.logger.Verbose(), + b.logger.Stdout(), b.logger.Stderr(), ) - if builderLogger.Verbose() { - builderLogger.Info(string(verboseInfo)) + if b.logger.Verbose() { + b.logger.Info(string(verboseInfo)) } if err != nil { return nil, errors.WithStack(err) @@ -270,12 +222,12 @@ func compileLibrary( includes = append(includes, cpp.WrapWithHyphenI(library.UtilityDir.String())) } libObjectFiles, err := utils.CompileFiles( - library.SourceDir, libraryBuildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, + library.SourceDir, libraryBuildPath, b.buildProperties, includes, + b.onlyUpdateCompilationDatabase, + b.compilationDatabase, + b.jobs, + b.logger, + b.Progress, ) if err != nil { return nil, errors.WithStack(err) @@ -285,12 +237,12 @@ func compileLibrary( if library.UtilityDir != nil { utilityBuildPath := libraryBuildPath.Join("utility") utilityObjectFiles, err := utils.CompileFiles( - library.UtilityDir, utilityBuildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, + library.UtilityDir, utilityBuildPath, b.buildProperties, includes, + b.onlyUpdateCompilationDatabase, + b.compilationDatabase, + b.jobs, + b.logger, + b.Progress, ) if err != nil { return nil, errors.WithStack(err) @@ -301,3 +253,88 @@ func compileLibrary( return objectFiles, nil } + +// RemoveUnusedCompiledLibraries fixdoc +func (b *Builder) RemoveUnusedCompiledLibraries(importedLibraries libraries.List) error { + if b.librariesBuildPath.NotExist() { + return nil + } + + toLibraryNames := func(libraries []*libraries.Library) []string { + libraryNames := []string{} + for _, library := range libraries { + libraryNames = append(libraryNames, library.Name) + } + return libraryNames + } + + files, err := b.librariesBuildPath.ReadDir() + if err != nil { + return errors.WithStack(err) + } + + libraryNames := toLibraryNames(importedLibraries) + for _, file := range files { + if file.IsDir() { + if !slices.Contains(libraryNames, file.Base()) { + if err := file.RemoveAll(); err != nil { + return errors.WithStack(err) + } + } + } + } + + return nil +} + +// WarnAboutArchIncompatibleLibraries fixdoc +func (b *Builder) WarnAboutArchIncompatibleLibraries(importedLibraries libraries.List) { + archs := []string{b.targetPlatform.Platform.Architecture} + overrides, _ := b.buildProperties.GetOk("architecture.override_check") + if overrides != "" { + archs = append(archs, strings.Split(overrides, ",")...) + } + + for _, importedLibrary := range importedLibraries { + if !importedLibrary.SupportsAnyArchitectureIn(archs...) { + b.logger.Info( + tr("WARNING: library %[1]s claims to run on %[2]s architecture(s) and may be incompatible with your current board which runs on %[3]s architecture(s).", + importedLibrary.Name, + strings.Join(importedLibrary.Architectures, ", "), + strings.Join(archs, ", "))) + } + } +} + +// PrintUsedLibraries fixdoc +// TODO here we can completly remove this part as it's duplicated in what we can +// read in the gRPC response +func (b *Builder) PrintUsedLibraries(importedLibraries libraries.List) { + if !b.logger.Verbose() || len(importedLibraries) == 0 { + return + } + + for _, library := range importedLibraries { + legacy := "" + if library.IsLegacy { + legacy = tr("(legacy)") + } + if library.Version.String() == "" { + b.logger.Info( + tr("Using library %[1]s in folder: %[2]s %[3]s", + library.Name, + library.InstallDir, + legacy)) + } else { + b.logger.Info( + tr("Using library %[1]s at version %[2]s in folder: %[3]s %[4]s", + library.Name, + library.Version, + library.InstallDir, + legacy)) + } + } + + // TODO Why is this here? + time.Sleep(100 * time.Millisecond) +} diff --git a/arduino/builder/linker.go b/arduino/builder/linker.go index 528e159d0aa..a4a2eba3bec 100644 --- a/arduino/builder/linker.go +++ b/arduino/builder/linker.go @@ -16,61 +16,41 @@ package builder import ( - "bytes" "strings" - "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/utils" f "github.com/arduino/arduino-cli/internal/algorithms" "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" ) -// Linker fixdoc -func Linker( - onlyUpdateCompilationDatabase bool, - sketchObjectFiles, librariesObjectFiles, coreObjectsFiles paths.PathList, - coreArchiveFilePath, buildPath *paths.Path, - buildProperties *properties.Map, - builderLogger *logger.BuilderLogger, -) ([]byte, error) { - verboseInfo := &bytes.Buffer{} - if onlyUpdateCompilationDatabase { - if builderLogger.Verbose() { - verboseInfo.WriteString(tr("Skip linking of final executable.")) +// Link fixdoc +func (b *Builder) Link() error { + if b.onlyUpdateCompilationDatabase { + if b.logger.Verbose() { + b.logger.Info(tr("Skip linking of final executable.")) } - return verboseInfo.Bytes(), nil + return nil } - objectFilesSketch := sketchObjectFiles - objectFilesLibraries := librariesObjectFiles - objectFilesCore := coreObjectsFiles - objectFiles := paths.NewPathList() - objectFiles.AddAll(objectFilesSketch) - objectFiles.AddAll(objectFilesLibraries) - objectFiles.AddAll(objectFilesCore) + objectFiles.AddAll(b.buildArtifacts.sketchObjectFiles) + objectFiles.AddAll(b.buildArtifacts.librariesObjectFiles) + objectFiles.AddAll(b.buildArtifacts.coreObjectsFiles) - coreDotARelPath, err := buildPath.RelTo(coreArchiveFilePath) + coreDotARelPath, err := b.buildPath.RelTo(b.buildArtifacts.coreArchiveFilePath) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } - verboseInfoOut, err := link(objectFiles, coreDotARelPath, coreArchiveFilePath, buildProperties, builderLogger) - verboseInfo.Write(verboseInfoOut) - if err != nil { - return verboseInfo.Bytes(), errors.WithStack(err) + if err := b.link(objectFiles, coreDotARelPath, b.buildArtifacts.coreArchiveFilePath); err != nil { + return errors.WithStack(err) } - return verboseInfo.Bytes(), nil + return nil } -func link( - objectFiles paths.PathList, coreDotARelPath *paths.Path, coreArchiveFilePath *paths.Path, buildProperties *properties.Map, - builderLogger *logger.BuilderLogger, -) ([]byte, error) { - verboseBuffer := &bytes.Buffer{} +func (b *Builder) link(objectFiles paths.PathList, coreDotARelPath *paths.Path, coreArchiveFilePath *paths.Path) error { wrapWithDoubleQuotes := func(value string) string { return "\"" + value + "\"" } objectFileList := strings.Join(f.Map(objectFiles.AsStrings(), wrapWithDoubleQuotes), " ") @@ -83,7 +63,7 @@ func link( // it may happen that a subdir/spi.o inside the archive may be overwritten by a anotherdir/spi.o // because thery are both named spi.o. - properties := buildProperties.Clone() + properties := b.buildProperties.Clone() archives := paths.NewPathList() for _, object := range objectFiles { if object.HasSuffix(".a") { @@ -102,14 +82,14 @@ func link( command, err := utils.PrepareCommandForRecipe(properties, "recipe.ar.pattern", false) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } - if verboseInfo, _, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */); err != nil { - if builderLogger.Verbose() { - verboseBuffer.WriteString(string(verboseInfo)) + if verboseInfo, _, _, err := utils.ExecCommand(b.logger.Verbose(), b.logger.Stdout(), b.logger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */); err != nil { + if b.logger.Verbose() { + b.logger.Info(string(verboseInfo)) } - return verboseBuffer.Bytes(), errors.WithStack(err) + return errors.WithStack(err) } } @@ -117,21 +97,21 @@ func link( objectFileList = "-Wl,--whole-archive " + objectFileList + " -Wl,--no-whole-archive" } - properties := buildProperties.Clone() + properties := b.buildProperties.Clone() properties.Set("compiler.c.elf.flags", properties.Get("compiler.c.elf.flags")) - properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+builderLogger.WarningsLevel())) + properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+b.logger.WarningsLevel())) properties.Set("archive_file", coreDotARelPath.String()) properties.Set("archive_file_path", coreArchiveFilePath.String()) properties.Set("object_files", objectFileList) command, err := utils.PrepareCommandForRecipe(properties, "recipe.c.combine.pattern", false) if err != nil { - return verboseBuffer.Bytes(), err + return err } - verboseInfo, _, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */) - if builderLogger.Verbose() { - verboseBuffer.WriteString(string(verboseInfo)) + verboseInfo, _, _, err := utils.ExecCommand(b.logger.Verbose(), b.logger.Stdout(), b.logger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */) + if b.logger.Verbose() { + b.logger.Info(string(verboseInfo)) } - return verboseBuffer.Bytes(), err + return err } diff --git a/legacy/builder/load_previous_build_options.go b/arduino/builder/preprocess_sketch.go similarity index 56% rename from legacy/builder/load_previous_build_options.go rename to arduino/builder/preprocess_sketch.go index 63dd83804e4..cf6adb208a2 100644 --- a/legacy/builder/load_previous_build_options.go +++ b/arduino/builder/preprocess_sketch.go @@ -1,6 +1,6 @@ // This file is part of arduino-cli. // -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// Copyright 2023 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. @@ -16,21 +16,21 @@ package builder import ( - "github.com/arduino/arduino-cli/legacy/builder/constants" + "github.com/arduino/arduino-cli/arduino/builder/preprocessor" "github.com/arduino/go-paths-helper" - "github.com/pkg/errors" ) -func LoadPreviousBuildOptionsMap(buildPath *paths.Path) (string, error) { - buildOptionsFile := buildPath.Join(constants.BUILD_OPTIONS_FILE) - - if buildOptionsFile.NotExist() { - return "", nil +// PreprocessSketch fixdoc +func (b *Builder) PreprocessSketch(includes paths.PathList) error { + // In the future we might change the preprocessor + normalOutput, verboseOutput, err := preprocessor.PreprocessSketchWithCtags( + b.sketch, b.buildPath, includes, b.lineOffset, + b.buildProperties, b.onlyUpdateCompilationDatabase, + ) + if b.logger.Verbose() { + b.logger.WriteStdout(verboseOutput) } + b.logger.WriteStdout(normalOutput) - buildOptionsJsonPrevious, err := buildOptionsFile.ReadFile() - if err != nil { - return "", errors.WithStack(err) - } - return string(buildOptionsJsonPrevious), nil + return err } diff --git a/arduino/builder/progress/progress.go b/arduino/builder/progress/progress.go index 2bdfaeb7539..a3fa9b09d9b 100644 --- a/arduino/builder/progress/progress.go +++ b/arduino/builder/progress/progress.go @@ -15,11 +15,19 @@ package progress +import rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + // Struct fixdoc type Struct struct { Progress float32 StepAmount float32 Parent *Struct + callback rpc.TaskProgressCB +} + +// New fixdoc +func New(callback rpc.TaskProgressCB) *Struct { + return &Struct{callback: callback} } // AddSubSteps fixdoc @@ -46,3 +54,13 @@ func (p *Struct) RemoveSubSteps() { func (p *Struct) CompleteStep() { p.Progress += p.StepAmount } + +// PushProgress fixdoc +func (p *Struct) PushProgress() { + if p.callback != nil { + p.callback(&rpc.TaskProgress{ + Percent: p.Progress, + Completed: p.Progress >= 100.0, + }) + } +} diff --git a/legacy/builder/recipe_runner.go b/arduino/builder/recipe.go similarity index 72% rename from legacy/builder/recipe_runner.go rename to arduino/builder/recipe.go index 8af310bd4d3..1102e8d7568 100644 --- a/legacy/builder/recipe_runner.go +++ b/arduino/builder/recipe.go @@ -20,23 +20,21 @@ import ( "sort" "strings" - "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/utils" properties "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) -func RecipeByPrefixSuffixRunner( +// RunRecipe fixdoc +func (b *Builder) RunRecipe( prefix, suffix string, - skipIfOnlyUpdatingCompilationDatabase, onlyUpdateCompilationDatabase bool, - buildProps *properties.Map, - builderLogger *logger.BuilderLogger, + skipIfOnlyUpdatingCompilationDatabase bool, ) error { logrus.Debugf(fmt.Sprintf("Looking for recipes like %s", prefix+"*"+suffix)) // TODO is it necessary to use Clone? - buildProperties := buildProps.Clone() + buildProperties := b.buildProperties.Clone() recipes := findRecipes(buildProperties, prefix, suffix) // TODO is it necessary to use Clone? @@ -49,16 +47,16 @@ func RecipeByPrefixSuffixRunner( return errors.WithStack(err) } - if onlyUpdateCompilationDatabase && skipIfOnlyUpdatingCompilationDatabase { - if builderLogger.Verbose() { - builderLogger.Info(tr("Skipping: %[1]s", strings.Join(command.GetArgs(), " "))) + if b.onlyUpdateCompilationDatabase && skipIfOnlyUpdatingCompilationDatabase { + if b.logger.Verbose() { + b.logger.Info(tr("Skipping: %[1]s", strings.Join(command.GetArgs(), " "))) } return nil } - verboseInfo, _, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */) - if builderLogger.Verbose() { - builderLogger.Info(string(verboseInfo)) + verboseInfo, _, _, err := utils.ExecCommand(b.logger.Verbose(), b.logger.Stdout(), b.logger.Stderr(), command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */) + if b.logger.Verbose() { + b.logger.Info(string(verboseInfo)) } if err != nil { return errors.WithStack(err) diff --git a/arduino/builder/sizer/sizer.go b/arduino/builder/sizer.go similarity index 70% rename from arduino/builder/sizer/sizer.go rename to arduino/builder/sizer.go index 7533a8d740e..7f461f8292e 100644 --- a/arduino/builder/sizer/sizer.go +++ b/arduino/builder/sizer.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package sizer +package builder import ( "encoding/json" @@ -21,16 +21,12 @@ import ( "regexp" "strconv" - "github.com/arduino/arduino-cli/arduino/builder/logger" "github.com/arduino/arduino-cli/arduino/builder/utils" - "github.com/arduino/arduino-cli/i18n" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" ) -var tr = i18n.Tr - // ExecutableSectionSize represents a section of the executable output file type ExecutableSectionSize struct { Name string `json:"name"` @@ -55,31 +51,35 @@ func (s ExecutablesFileSections) ToRPCExecutableSectionSizeArray() []*rpc.Execut } // Size fixdoc -func Size( - onlyUpdateCompilationDatabase, sketchError bool, - buildProperties *properties.Map, - builderLogger *logger.BuilderLogger, -) (ExecutablesFileSections, error) { - if onlyUpdateCompilationDatabase || sketchError { - return nil, nil +func (b *Builder) Size(sketchError bool) error { + if b.onlyUpdateCompilationDatabase || sketchError { + return nil + } + + check := b.checkSize + if b.buildProperties.ContainsKey("recipe.advanced_size.pattern") { + check = b.checkSizeAdvanced } - if buildProperties.ContainsKey("recipe.advanced_size.pattern") { - return checkSizeAdvanced(buildProperties, builderLogger) + result, err := check() + if err != nil { + return err } - return checkSize(buildProperties, builderLogger) + b.executableSectionsSize = result + + return nil } -func checkSizeAdvanced(buildProperties *properties.Map, builderLogger *logger.BuilderLogger) (ExecutablesFileSections, error) { - command, err := utils.PrepareCommandForRecipe(buildProperties, "recipe.advanced_size.pattern", false) +func (b *Builder) checkSizeAdvanced() (ExecutablesFileSections, error) { + command, err := utils.PrepareCommandForRecipe(b.buildProperties, "recipe.advanced_size.pattern", false) if err != nil { return nil, errors.New(tr("Error while determining sketch size: %s", err)) } - verboseInfo, out, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.Capture /* stdout */, utils.Show /* stderr */) - if builderLogger.Verbose() { - builderLogger.Info(string(verboseInfo)) + verboseInfo, out, _, err := utils.ExecCommand(b.logger.Verbose(), b.logger.Stdout(), b.logger.Stderr(), command, utils.Capture /* stdout */, utils.Show /* stderr */) + if b.logger.Verbose() { + b.logger.Info(string(verboseInfo)) } if err != nil { return nil, errors.New(tr("Error while determining sketch size: %s", err)) @@ -107,21 +107,21 @@ func checkSizeAdvanced(buildProperties *properties.Map, builderLogger *logger.Bu executableSectionsSize := resp.Sections switch resp.Severity { case "error": - builderLogger.Warn(resp.Output) + b.logger.Warn(resp.Output) return executableSectionsSize, errors.New(resp.ErrorMessage) case "warning": - builderLogger.Warn(resp.Output) + b.logger.Warn(resp.Output) case "info": - builderLogger.Info(resp.Output) + b.logger.Info(resp.Output) default: return executableSectionsSize, fmt.Errorf("invalid '%s' severity from sketch sizer: it must be 'error', 'warning' or 'info'", resp.Severity) } return executableSectionsSize, nil } -func checkSize(buildProperties *properties.Map, builderLogger *logger.BuilderLogger) (ExecutablesFileSections, error) { - properties := buildProperties.Clone() - properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+builderLogger.WarningsLevel())) +func (b *Builder) checkSize() (ExecutablesFileSections, error) { + properties := b.buildProperties.Clone() + properties.Set("compiler.warning_flags", properties.Get("compiler.warning_flags."+b.logger.WarningsLevel())) maxTextSizeString := properties.Get("upload.maximum_size") maxDataSizeString := properties.Get("upload.maximum_data_size") @@ -143,25 +143,25 @@ func checkSize(buildProperties *properties.Map, builderLogger *logger.BuilderLog } } - textSize, dataSize, _, err := execSizeRecipe(properties, builderLogger) + textSize, dataSize, _, err := b.execSizeRecipe(properties) if err != nil { - builderLogger.Warn(tr("Couldn't determine program size")) + b.logger.Warn(tr("Couldn't determine program size")) return nil, nil } - builderLogger.Info(tr("Sketch uses %[1]s bytes (%[3]s%%) of program storage space. Maximum is %[2]s bytes.", + b.logger.Info(tr("Sketch uses %[1]s bytes (%[3]s%%) of program storage space. Maximum is %[2]s bytes.", strconv.Itoa(textSize), strconv.Itoa(maxTextSize), strconv.Itoa(textSize*100/maxTextSize))) if dataSize >= 0 { if maxDataSize > 0 { - builderLogger.Info(tr("Global variables use %[1]s bytes (%[3]s%%) of dynamic memory, leaving %[4]s bytes for local variables. Maximum is %[2]s bytes.", + b.logger.Info(tr("Global variables use %[1]s bytes (%[3]s%%) of dynamic memory, leaving %[4]s bytes for local variables. Maximum is %[2]s bytes.", strconv.Itoa(dataSize), strconv.Itoa(maxDataSize), strconv.Itoa(dataSize*100/maxDataSize), strconv.Itoa(maxDataSize-dataSize))) } else { - builderLogger.Info(tr("Global variables use %[1]s bytes of dynamic memory.", strconv.Itoa(dataSize))) + b.logger.Info(tr("Global variables use %[1]s bytes of dynamic memory.", strconv.Itoa(dataSize))) } } @@ -181,12 +181,12 @@ func checkSize(buildProperties *properties.Map, builderLogger *logger.BuilderLog } if textSize > maxTextSize { - builderLogger.Warn(tr("Sketch too big; see %[1]s for tips on reducing it.", "https://support.arduino.cc/hc/en-us/articles/360013825179")) + b.logger.Warn(tr("Sketch too big; see %[1]s for tips on reducing it.", "https://support.arduino.cc/hc/en-us/articles/360013825179")) return executableSectionsSize, errors.New(tr("text section exceeds available space in board")) } if maxDataSize > 0 && dataSize > maxDataSize { - builderLogger.Warn(tr("Not enough memory; see %[1]s for tips on reducing your footprint.", "https://support.arduino.cc/hc/en-us/articles/360013825179")) + b.logger.Warn(tr("Not enough memory; see %[1]s for tips on reducing your footprint.", "https://support.arduino.cc/hc/en-us/articles/360013825179")) return executableSectionsSize, errors.New(tr("data section exceeds available space in board")) } @@ -196,23 +196,23 @@ func checkSize(buildProperties *properties.Map, builderLogger *logger.BuilderLog return executableSectionsSize, err } if maxDataSize > 0 && dataSize > maxDataSize*warnDataPercentage/100 { - builderLogger.Warn(tr("Low memory available, stability problems may occur.")) + b.logger.Warn(tr("Low memory available, stability problems may occur.")) } } return executableSectionsSize, nil } -func execSizeRecipe(properties *properties.Map, builderLogger *logger.BuilderLogger) (textSize int, dataSize int, eepromSize int, resErr error) { +func (b *Builder) execSizeRecipe(properties *properties.Map) (textSize int, dataSize int, eepromSize int, resErr error) { command, err := utils.PrepareCommandForRecipe(properties, "recipe.size.pattern", false) if err != nil { resErr = fmt.Errorf(tr("Error while determining sketch size: %s"), err) return } - verboseInfo, out, _, err := utils.ExecCommand(builderLogger.Verbose(), builderLogger.Stdout(), builderLogger.Stderr(), command, utils.Capture /* stdout */, utils.Show /* stderr */) - if builderLogger.Verbose() { - builderLogger.Info(string(verboseInfo)) + verboseInfo, out, _, err := utils.ExecCommand(b.logger.Verbose(), b.logger.Stdout(), b.logger.Stderr(), command, utils.Capture /* stdout */, utils.Show /* stderr */) + if b.logger.Verbose() { + b.logger.Info(string(verboseInfo)) } if err != nil { resErr = fmt.Errorf(tr("Error while determining sketch size: %s"), err) diff --git a/arduino/builder/sizer/sizer_test.go b/arduino/builder/sizer_test.go similarity index 99% rename from arduino/builder/sizer/sizer_test.go rename to arduino/builder/sizer_test.go index 42c3b323d42..79514ae6862 100644 --- a/arduino/builder/sizer/sizer_test.go +++ b/arduino/builder/sizer_test.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package sizer +package builder import ( "testing" diff --git a/arduino/builder/sketch.go b/arduino/builder/sketch.go index 79779d5b4cc..dbab5b521bc 100644 --- a/arduino/builder/sketch.go +++ b/arduino/builder/sketch.go @@ -18,19 +18,18 @@ package builder import ( "bytes" "fmt" + "math" "regexp" + "strconv" + "strings" - "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/cpp" - "github.com/arduino/arduino-cli/arduino/builder/logger" - "github.com/arduino/arduino-cli/arduino/builder/progress" "github.com/arduino/arduino-cli/arduino/builder/utils" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/i18n" f "github.com/arduino/arduino-cli/internal/algorithms" - rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" + "github.com/marcinbor85/gohex" "github.com/pkg/errors" ) @@ -48,26 +47,28 @@ func (b *Builder) Sketch() *sketch.Sketch { // PrepareSketchBuildPath copies the sketch source files in the build path. // The .ino files are merged together to create a .cpp file (by the way, the // .cpp file still needs to be Arduino-preprocessed to compile). -func (b *Builder) PrepareSketchBuildPath(sourceOverrides map[string]string, buildPath *paths.Path) (int, error) { - if err := buildPath.MkdirAll(); err != nil { - return 0, errors.Wrap(err, tr("unable to create a folder to save the sketch")) +func (b *Builder) PrepareSketchBuildPath() error { + if err := b.sketchBuildPath.MkdirAll(); err != nil { + return errors.Wrap(err, tr("unable to create a folder to save the sketch")) } - offset, mergedSource, err := b.sketchMergeSources(sourceOverrides) + offset, mergedSource, err := b.sketchMergeSources(b.sourceOverrides) if err != nil { - return 0, err + return err } - destFile := buildPath.Join(b.sketch.MainFile.Base() + ".cpp") + destFile := b.sketchBuildPath.Join(b.sketch.MainFile.Base() + ".cpp") if err := destFile.WriteFile([]byte(mergedSource)); err != nil { - return 0, err + return err } - if err := b.sketchCopyAdditionalFiles(buildPath, sourceOverrides); err != nil { - return 0, err + if err := b.sketchCopyAdditionalFiles(b.sketchBuildPath, b.sourceOverrides); err != nil { + return err } - return offset, nil + b.lineOffset = offset + + return nil } // sketchMergeSources merges all the .ino source files included in a sketch to produce @@ -179,51 +180,168 @@ func writeIfDifferent(source []byte, destPath *paths.Path) error { return nil } -// SketchBuilder fixdoc -func SketchBuilder( - sketchBuildPath *paths.Path, - buildProperties *properties.Map, - includesFolders paths.PathList, - onlyUpdateCompilationDatabase bool, - compilationDatabase *compilation.Database, - jobs int, - builderLogger *logger.BuilderLogger, - progress *progress.Struct, progressCB rpc.TaskProgressCB, -) (paths.PathList, error) { +// BuildSketch fixdoc +func (b *Builder) BuildSketch(includesFolders paths.PathList) error { includes := f.Map(includesFolders.AsStrings(), cpp.WrapWithHyphenI) - if err := sketchBuildPath.MkdirAll(); err != nil { - return nil, errors.WithStack(err) + if err := b.sketchBuildPath.MkdirAll(); err != nil { + return errors.WithStack(err) } sketchObjectFiles, err := utils.CompileFiles( - sketchBuildPath, sketchBuildPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, + b.sketchBuildPath, b.sketchBuildPath, b.buildProperties, includes, + b.onlyUpdateCompilationDatabase, + b.compilationDatabase, + b.jobs, + b.builderLogger, + b.Progress, ) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } // The "src/" subdirectory of a sketch is compiled recursively - sketchSrcPath := sketchBuildPath.Join("src") + sketchSrcPath := b.sketchBuildPath.Join("src") if sketchSrcPath.IsDir() { srcObjectFiles, err := utils.CompileFilesRecursive( - sketchSrcPath, sketchSrcPath, buildProperties, includes, - onlyUpdateCompilationDatabase, - compilationDatabase, - jobs, - builderLogger, - progress, progressCB, + sketchSrcPath, sketchSrcPath, b.buildProperties, includes, + b.onlyUpdateCompilationDatabase, + b.compilationDatabase, + b.jobs, + b.builderLogger, + b.Progress, ) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } sketchObjectFiles.AddAll(srcObjectFiles) } - return sketchObjectFiles, nil + b.buildArtifacts.sketchObjectFiles = sketchObjectFiles + return nil +} + +// MergeSketchWithBootloader fixdoc +func (b *Builder) MergeSketchWithBootloader() error { + if b.onlyUpdateCompilationDatabase { + return nil + } + + if !b.buildProperties.ContainsKey("bootloader.noblink") && !b.buildProperties.ContainsKey("bootloader.file") { + return nil + } + + sketchFileName := b.sketch.MainFile.Base() + sketchInBuildPath := b.buildPath.Join(sketchFileName + ".hex") + sketchInSubfolder := b.buildPath.Join("sketch", sketchFileName+".hex") + + var builtSketchPath *paths.Path + if sketchInBuildPath.Exist() { + builtSketchPath = sketchInBuildPath + } else if sketchInSubfolder.Exist() { + builtSketchPath = sketchInSubfolder + } else { + return nil + } + + bootloader := "" + if bootloaderNoBlink, ok := b.buildProperties.GetOk("bootloader.noblink"); ok { + bootloader = bootloaderNoBlink + } else { + bootloader = b.buildProperties.Get("bootloader.file") + } + bootloader = b.buildProperties.ExpandPropsInString(bootloader) + + bootloaderPath := b.buildProperties.GetPath("runtime.platform.path").Join("bootloaders", bootloader) + if bootloaderPath.NotExist() { + if b.logger.Verbose() { + b.logger.Warn(tr("Bootloader file specified but missing: %[1]s", bootloaderPath)) + } + return nil + } + + mergedSketchPath := builtSketchPath.Parent().Join(sketchFileName + ".with_bootloader.hex") + + // Ignore merger errors for the first iteration + maximumBinSize := 16000000 + if uploadMaxSize, ok := b.buildProperties.GetOk("upload.maximum_size"); ok { + maximumBinSize, _ = strconv.Atoi(uploadMaxSize) + maximumBinSize *= 2 + } + err := merge(builtSketchPath, bootloaderPath, mergedSketchPath, maximumBinSize) + if err != nil && b.logger.Verbose() { + b.logger.Info(err.Error()) + } + + return nil +} + +func merge(builtSketchPath, bootloaderPath, mergedSketchPath *paths.Path, maximumBinSize int) error { + if bootloaderPath.Ext() == ".bin" { + bootloaderPath = paths.New(strings.TrimSuffix(bootloaderPath.String(), ".bin") + ".hex") + } + + memBoot := gohex.NewMemory() + if bootFile, err := bootloaderPath.Open(); err == nil { + defer bootFile.Close() + if err := memBoot.ParseIntelHex(bootFile); err != nil { + return errors.New(bootFile.Name() + " " + err.Error()) + } + } else { + return err + } + + memSketch := gohex.NewMemory() + if buildFile, err := builtSketchPath.Open(); err == nil { + defer buildFile.Close() + if err := memSketch.ParseIntelHex(buildFile); err != nil { + return errors.New(buildFile.Name() + " " + err.Error()) + } + } else { + return err + } + + memMerged := gohex.NewMemory() + initialAddress := uint32(math.MaxUint32) + lastAddress := uint32(0) + + for _, segment := range memBoot.GetDataSegments() { + if err := memMerged.AddBinary(segment.Address, segment.Data); err != nil { + continue + } + if segment.Address < initialAddress { + initialAddress = segment.Address + } + if segment.Address+uint32(len(segment.Data)) > lastAddress { + lastAddress = segment.Address + uint32(len(segment.Data)) + } + } + for _, segment := range memSketch.GetDataSegments() { + if err := memMerged.AddBinary(segment.Address, segment.Data); err != nil { + continue + } + if segment.Address < initialAddress { + initialAddress = segment.Address + } + if segment.Address+uint32(len(segment.Data)) > lastAddress { + lastAddress = segment.Address + uint32(len(segment.Data)) + } + } + + if mergeFile, err := mergedSketchPath.Create(); err == nil { + defer mergeFile.Close() + memMerged.DumpIntelHex(mergeFile, 16) + } else { + return err + } + + // Write out a .bin if the addresses doesn't go too far away from origin + // (and consequently produce a very large bin) + size := lastAddress - initialAddress + if size > uint32(maximumBinSize) { + return nil + } + mergedSketchPathBin := paths.New(strings.TrimSuffix(mergedSketchPath.String(), ".hex") + ".bin") + data := memMerged.ToBinary(initialAddress, size, 0xFF) + return mergedSketchPathBin.WriteFile(data) } diff --git a/arduino/builder/sketch_test.go b/arduino/builder/sketch_test.go index 6aaedaaa0fc..1ae684e12ed 100644 --- a/arduino/builder/sketch_test.go +++ b/arduino/builder/sketch_test.go @@ -48,7 +48,8 @@ func TestMergeSketchSources(t *testing.T) { } mergedSources := strings.ReplaceAll(string(mergedBytes), "%s", pathToGoldenSource) - b := NewBuilder(sk, nil, nil, false, nil, 0) + b := Builder{sketch: sk} + offset, source, err := b.sketchMergeSources(nil) require.Nil(t, err) require.Equal(t, 2, offset) @@ -61,7 +62,8 @@ func TestMergeSketchSourcesArduinoIncluded(t *testing.T) { require.NotNil(t, sk) // ensure not to include Arduino.h when it's already there - b := NewBuilder(sk, nil, nil, false, nil, 0) + b := Builder{sketch: sk} + _, source, err := b.sketchMergeSources(nil) require.Nil(t, err) require.Equal(t, 1, strings.Count(source, "")) @@ -76,11 +78,12 @@ func TestCopyAdditionalFiles(t *testing.T) { sk1, err := sketch.New(paths.New("testdata", t.Name())) require.Nil(t, err) require.Equal(t, sk1.AdditionalFiles.Len(), 1) - b1 := NewBuilder(sk1, nil, nil, false, nil, 0) + + b := Builder{sketch: sk1} // 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 = b1.sketchCopyAdditionalFiles(tmp, nil) + err = b.sketchCopyAdditionalFiles(tmp, nil) require.Nil(t, err) fakeIno := tmp.Join(fmt.Sprintf("%s.ino", tmp.Base())) require.Nil(t, fakeIno.WriteFile([]byte{})) @@ -95,7 +98,7 @@ func TestCopyAdditionalFiles(t *testing.T) { require.Nil(t, err) // copy again - err = b1.sketchCopyAdditionalFiles(tmp, nil) + err = b.sketchCopyAdditionalFiles(tmp, nil) require.Nil(t, err) // verify file hasn't changed diff --git a/arduino/builder/utils/utils.go b/arduino/builder/utils/utils.go index ea3f80c5326..f0ae458512a 100644 --- a/arduino/builder/utils/utils.go +++ b/arduino/builder/utils/utils.go @@ -33,7 +33,6 @@ import ( "github.com/arduino/arduino-cli/executils" "github.com/arduino/arduino-cli/i18n" f "github.com/arduino/arduino-cli/internal/algorithms" - rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" @@ -358,7 +357,7 @@ func CompileFiles( compilationDatabase *compilation.Database, jobs int, builderLogger *logger.BuilderLogger, - progress *progress.Struct, progressCB rpc.TaskProgressCB, + progress *progress.Struct, ) (paths.PathList, error) { return compileFiles( onlyUpdateCompilationDatabase, @@ -368,7 +367,7 @@ func CompileFiles( false, buildPath, buildProperties, includes, builderLogger, - progress, progressCB, + progress, ) } @@ -381,7 +380,7 @@ func CompileFilesRecursive( compilationDatabase *compilation.Database, jobs int, builderLogger *logger.BuilderLogger, - progress *progress.Struct, progressCB rpc.TaskProgressCB, + progress *progress.Struct, ) (paths.PathList, error) { return compileFiles( onlyUpdateCompilationDatabase, @@ -391,7 +390,7 @@ func CompileFilesRecursive( true, buildPath, buildProperties, includes, builderLogger, - progress, progressCB, + progress, ) } @@ -406,7 +405,6 @@ func compileFiles( includes []string, builderLogger *logger.BuilderLogger, progress *progress.Struct, - progressCB rpc.TaskProgressCB, ) (paths.PathList, error) { validExtensions := []string{} for ext := range globals.SourceFilesValidExtensions { @@ -483,13 +481,7 @@ func compileFiles( queue <- source progress.CompleteStep() - // PushProgress - if progressCB != nil { - progressCB(&rpc.TaskProgress{ - Percent: progress.Progress, - Completed: progress.Progress >= 100.0, - }) - } + progress.PushProgress() } close(queue) wg.Wait() diff --git a/arduino/builder/utils/utils_test.go b/arduino/builder/utils/utils_test.go index 3dd4c1a2142..1c31160f5d0 100644 --- a/arduino/builder/utils/utils_test.go +++ b/arduino/builder/utils/utils_test.go @@ -16,8 +16,11 @@ package utils import ( + "os" "testing" + "time" + "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" ) @@ -39,3 +42,133 @@ func TestPrintableCommand(t *testing.T) { result := printableCommand(parts) require.Equal(t, correct, result) } + +func tempFile(t *testing.T, prefix string) *paths.Path { + file, err := os.CreateTemp("", prefix) + file.Close() + require.NoError(t, err) + return paths.New(file.Name()) +} + +func TestObjFileIsUpToDateObjMissing(t *testing.T) { + sourceFile := tempFile(t, "source") + defer sourceFile.RemoveAll() + + upToDate, err := ObjFileIsUpToDate(sourceFile, nil, nil) + require.NoError(t, err) + require.False(t, upToDate) +} + +func TestObjFileIsUpToDateDepMissing(t *testing.T) { + sourceFile := tempFile(t, "source") + defer sourceFile.RemoveAll() + + objFile := tempFile(t, "obj") + defer objFile.RemoveAll() + + upToDate, err := ObjFileIsUpToDate(sourceFile, objFile, nil) + require.NoError(t, err) + require.False(t, upToDate) +} + +func TestObjFileIsUpToDateObjOlder(t *testing.T) { + objFile := tempFile(t, "obj") + defer objFile.RemoveAll() + depFile := tempFile(t, "dep") + defer depFile.RemoveAll() + + time.Sleep(time.Second) + + sourceFile := tempFile(t, "source") + defer sourceFile.RemoveAll() + + upToDate, err := ObjFileIsUpToDate(sourceFile, objFile, depFile) + require.NoError(t, err) + require.False(t, upToDate) +} + +func TestObjFileIsUpToDateObjNewer(t *testing.T) { + sourceFile := tempFile(t, "source") + defer sourceFile.RemoveAll() + + time.Sleep(time.Second) + + objFile := tempFile(t, "obj") + defer objFile.RemoveAll() + depFile := tempFile(t, "dep") + defer depFile.RemoveAll() + + upToDate, err := ObjFileIsUpToDate(sourceFile, objFile, depFile) + require.NoError(t, err) + require.True(t, upToDate) +} + +func TestObjFileIsUpToDateDepIsNewer(t *testing.T) { + sourceFile := tempFile(t, "source") + defer sourceFile.RemoveAll() + + time.Sleep(time.Second) + + objFile := tempFile(t, "obj") + defer objFile.RemoveAll() + depFile := tempFile(t, "dep") + defer depFile.RemoveAll() + + time.Sleep(time.Second) + + headerFile := tempFile(t, "header") + defer headerFile.RemoveAll() + + data := objFile.String() + ": \\\n\t" + sourceFile.String() + " \\\n\t" + headerFile.String() + depFile.WriteFile([]byte(data)) + + upToDate, err := ObjFileIsUpToDate(sourceFile, objFile, depFile) + require.NoError(t, err) + require.False(t, upToDate) +} + +func TestObjFileIsUpToDateDepIsOlder(t *testing.T) { + sourceFile := tempFile(t, "source") + defer sourceFile.RemoveAll() + + headerFile := tempFile(t, "header") + defer headerFile.RemoveAll() + + time.Sleep(time.Second) + + objFile := tempFile(t, "obj") + defer objFile.RemoveAll() + depFile := tempFile(t, "dep") + defer depFile.RemoveAll() + + res := objFile.String() + ": \\\n\t" + sourceFile.String() + " \\\n\t" + headerFile.String() + depFile.WriteFile([]byte(res)) + + upToDate, err := ObjFileIsUpToDate(sourceFile, objFile, depFile) + require.NoError(t, err) + require.True(t, upToDate) +} + +func TestObjFileIsUpToDateDepIsWrong(t *testing.T) { + sourceFile := tempFile(t, "source") + defer sourceFile.RemoveAll() + + time.Sleep(time.Second) + + objFile := tempFile(t, "obj") + defer objFile.RemoveAll() + depFile := tempFile(t, "dep") + defer depFile.RemoveAll() + + time.Sleep(time.Second) + + headerFile := tempFile(t, "header") + defer headerFile.RemoveAll() + + res := sourceFile.String() + ": \\\n\t" + sourceFile.String() + " \\\n\t" + headerFile.String() + depFile.WriteFile([]byte(res)) + + upToDate, err := ObjFileIsUpToDate(sourceFile, objFile, depFile) + require.NoError(t, err) + require.False(t, upToDate) +} diff --git a/commands/compile/compile.go b/commands/compile/compile.go index 36bba118f92..5dcd028c34c 100644 --- a/commands/compile/compile.go +++ b/commands/compile/compile.go @@ -17,6 +17,7 @@ package compile import ( "context" + "errors" "fmt" "io" "sort" @@ -24,9 +25,9 @@ import ( "github.com/arduino/arduino-cli/arduino" bldr "github.com/arduino/arduino-cli/arduino/builder" - "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/detector" "github.com/arduino/arduino-cli/arduino/builder/logger" + "github.com/arduino/arduino-cli/arduino/builder/progress" "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/libraries/librariesmanager" "github.com/arduino/arduino-cli/arduino/sketch" @@ -37,11 +38,9 @@ import ( "github.com/arduino/arduino-cli/i18n" "github.com/arduino/arduino-cli/internal/inventory" "github.com/arduino/arduino-cli/legacy/builder" - "github.com/arduino/arduino-cli/legacy/builder/constants" "github.com/arduino/arduino-cli/legacy/builder/types" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" "github.com/sirupsen/logrus" ) @@ -100,7 +99,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream if err != nil { return nil, &arduino.InvalidFQBNError{Cause: err} } - targetPackage, targetPlatform, targetBoard, boardBuildProperties, buildPlatform, err := pme.ResolveFQBN(fqbn) + _, targetPlatform, targetBoard, boardBuildProperties, buildPlatform, err := pme.ResolveFQBN(fqbn) if err != nil { if targetPlatform == nil { return nil, &arduino.PlatformNotFoundError{ @@ -171,84 +170,51 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream coreBuildCachePath = buildCachePath.Join("core") } - sketchBuilder := bldr.NewBuilder( - sk, - boardBuildProperties, - buildPath, - req.GetOptimizeForDebug(), - coreBuildCachePath, - int(req.GetJobs()), - ) - - buildProperties := sketchBuilder.GetBuildProperties() - - // Add user provided custom build properties - customBuildPropertiesArgs := append(req.GetBuildProperties(), "build.warn_data_percentage=75") - if customBuildProperties, err := properties.LoadFromSlice(req.GetBuildProperties()); err == nil { - buildProperties.Merge(customBuildProperties) - } else { - return nil, &arduino.InvalidArgumentError{Message: tr("Invalid build properties"), Cause: err} - } - - requiredTools, err := pme.FindToolsRequiredForBuild(targetPlatform, buildPlatform) - if err != nil { + if _, err := pme.FindToolsRequiredForBuild(targetPlatform, buildPlatform); err != nil { return nil, err } builderCtx := &types.Context{} - builderCtx.Builder = sketchBuilder - builderCtx.PackageManager = pme - builderCtx.TargetBoard = targetBoard - builderCtx.TargetPlatform = targetPlatform - builderCtx.TargetPackage = targetPackage - builderCtx.ActualPlatform = buildPlatform - builderCtx.RequiredTools = requiredTools - builderCtx.BuildProperties = buildProperties - builderCtx.CustomBuildProperties = customBuildPropertiesArgs - builderCtx.FQBN = fqbn - builderCtx.BuildPath = buildPath - builderCtx.ProgressCB = progressCB - - // FIXME: This will be redundant when arduino-builder will be part of the cli - builderCtx.HardwareDirs = configuration.HardwareDirectories(configuration.Settings) - builderCtx.BuiltInToolsDirs = configuration.BuiltinToolsDirectories(configuration.Settings) - builderCtx.OtherLibrariesDirs = paths.NewPathList(req.GetLibraries()...) - builderCtx.OtherLibrariesDirs.Add(configuration.LibrariesDir(configuration.Settings)) - - builderCtx.CompilationDatabase = compilation.NewDatabase( - builderCtx.BuildPath.Join("compile_commands.json"), - ) - - builderCtx.BuiltInLibrariesDirs = configuration.IDEBuiltinLibrariesDir(configuration.Settings) - - builderCtx.Clean = req.GetClean() - builderCtx.OnlyUpdateCompilationDatabase = req.GetCreateCompilationDatabaseOnly() - builderCtx.SourceOverride = req.GetSourceOverride() + actualPlatform := buildPlatform + builtinLibrariesDir := configuration.IDEBuiltinLibrariesDir(configuration.Settings) + otherLibrariesDirs := paths.NewPathList(req.GetLibraries()...) + otherLibrariesDirs.Add(configuration.LibrariesDir(configuration.Settings)) builderLogger := logger.New(outStream, errStream, req.GetVerbose(), req.GetWarnings()) builderCtx.BuilderLogger = builderLogger - sketchBuildPath, err := buildPath.Join(constants.FOLDER_SKETCH).Abs() - if err != nil { - return r, &arduino.CompileFailedError{Message: err.Error()} - } - librariesBuildPath, err := buildPath.Join(constants.FOLDER_LIBRARIES).Abs() - if err != nil { - return r, &arduino.CompileFailedError{Message: err.Error()} - } - coreBuildPath, err := buildPath.Join(constants.FOLDER_CORE).Abs() + sketchBuilder, err := bldr.NewBuilder( + sk, + boardBuildProperties, + buildPath, + req.GetOptimizeForDebug(), + coreBuildCachePath, + int(req.GetJobs()), + req.GetBuildProperties(), + configuration.HardwareDirectories(configuration.Settings), + configuration.BuiltinToolsDirectories(configuration.Settings), + otherLibrariesDirs, + builtinLibrariesDir, + fqbn, + req.GetClean(), + req.GetSourceOverride(), + req.GetCreateCompilationDatabaseOnly(), + actualPlatform, targetPlatform, + builderLogger, + progress.New(progressCB), + ) if err != nil { - return r, &arduino.CompileFailedError{Message: err.Error()} - } - builderCtx.SketchBuildPath = sketchBuildPath - builderCtx.LibrariesBuildPath = librariesBuildPath - builderCtx.CoreBuildPath = coreBuildPath - - if builderCtx.BuildPath.Canonical().EqualsTo(sk.FullPath.Canonical()) { - return r, &arduino.CompileFailedError{ - Message: tr("Sketch cannot be located in build path. Please specify a different build path"), + if strings.Contains(err.Error(), "invalid build properties") { + return nil, &arduino.InvalidArgumentError{Message: tr("Invalid build properties"), Cause: err} } + if errors.Is(err, bldr.ErrSketchCannotBeLocatedInBuildPath) { + return r, &arduino.CompileFailedError{ + Message: tr("Sketch cannot be located in build path. Please specify a different build path"), + } + } + return r, &arduino.CompileFailedError{Message: err.Error()} } + builderCtx.Builder = sketchBuilder var libsManager *librariesmanager.LibrariesManager if pme.GetProfile() != nil { @@ -258,8 +224,8 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream libraryDir := paths.NewPathList(req.Library...) libsManager, libsResolver, verboseOut, err := detector.LibrariesLoader( useCachedLibrariesResolution, libsManager, - builderCtx.BuiltInLibrariesDirs, libraryDir, builderCtx.OtherLibrariesDirs, - builderCtx.ActualPlatform, builderCtx.TargetPlatform, + builtinLibrariesDir, libraryDir, otherLibrariesDirs, + actualPlatform, targetPlatform, ) if err != nil { return r, &arduino.CompileFailedError{Message: err.Error()} @@ -277,13 +243,13 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream ) defer func() { - if p := builderCtx.BuildPath; p != nil { + if p := sketchBuilder.GetBuildPath(); p != nil { r.BuildPath = p.String() } }() defer func() { - buildProperties := builderCtx.BuildProperties + buildProperties := sketchBuilder.GetBuildProperties() if buildProperties == nil { return } @@ -327,7 +293,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream // if it's a regular build, go on... if req.GetVerbose() { - core := buildProperties.Get("build.core") + core := sketchBuilder.GetBuildProperties().Get("build.core") if core == "" { core = "arduino" } @@ -346,7 +312,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream if !targetBoard.Properties.ContainsKey("build.board") { outStream.Write([]byte( tr("Warning: Board %[1]s doesn't define a %[2]s preference. Auto-set to: %[3]s", - targetBoard.String(), "'build.board'", buildProperties.Get("build.board")) + "\n")) + targetBoard.String(), "'build.board'", sketchBuilder.GetBuildProperties().Get("build.board")) + "\n")) } if err := builder.RunBuilder(builderCtx); err != nil { @@ -362,12 +328,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream exportBinaries = false } if exportBinaries { - err := builder.RecipeByPrefixSuffixRunner( - "recipe.hooks.savehex.presavehex", ".pattern", false, - builderCtx.OnlyUpdateCompilationDatabase, - builderCtx.BuildProperties, - builderLogger, - ) + err := sketchBuilder.RunRecipe("recipe.hooks.savehex.presavehex", ".pattern", false) if err != nil { return r, err } @@ -386,11 +347,11 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream } // Copy all "sketch.ino.*" artifacts to the export directory - baseName, ok := builderCtx.BuildProperties.GetOk("build.project_name") // == "sketch.ino" + baseName, ok := sketchBuilder.GetBuildProperties().GetOk("build.project_name") // == "sketch.ino" if !ok { return r, &arduino.MissingPlatformPropertyError{Property: "build.project_name"} } - buildFiles, err := builderCtx.BuildPath.ReadDir() + buildFiles, err := sketchBuilder.GetBuildPath().ReadDir() if err != nil { return r, &arduino.PermissionDeniedError{Message: tr("Error reading build directory"), Cause: err} } @@ -406,17 +367,13 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream } } - err = builder.RecipeByPrefixSuffixRunner( - "recipe.hooks.savehex.postsavehex", ".pattern", false, - builderCtx.OnlyUpdateCompilationDatabase, - builderCtx.BuildProperties, builderLogger, - ) + err = sketchBuilder.RunRecipe("recipe.hooks.savehex.postsavehex", ".pattern", false) if err != nil { return r, err } } - r.ExecutableSectionsSize = builderCtx.ExecutableSectionsSize.ToRPCExecutableSectionSizeArray() + r.ExecutableSectionsSize = sketchBuilder.ExecutableSectionsSize().ToRPCExecutableSectionSizeArray() logrus.Tracef("Compile %s for %s successful", sk.Name, fqbnIn) diff --git a/internal/integrationtest/compile_4/compile_test.go b/internal/integrationtest/compile_4/compile_test.go index 09125b5e2e1..4210eaa931f 100644 --- a/internal/integrationtest/compile_4/compile_test.go +++ b/internal/integrationtest/compile_4/compile_test.go @@ -387,6 +387,7 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl // Simulate a library use in libraries build path require.NoError(t, buildPath.Join("libraries", "SPI").MkdirAll()) + require.NoError(t, buildPath.Join("libraries", "dummy_file").WriteFile([]byte{})) // Build again... _, err = tryBuild(t, env, cli, "arduino:avr:leonardo", &buildOptions{NoClean: true}) @@ -394,6 +395,7 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl require.False(t, buildPath.Join("libraries", "SPI").Exist()) require.True(t, buildPath.Join("libraries", "Bridge").Exist()) + require.True(t, buildPath.Join("libraries", "dummy_file").Exist()) }) t.Run("Preprocess", func(t *testing.T) { diff --git a/legacy/builder/builder.go b/legacy/builder/builder.go index c36335aa799..cf9551b0d99 100644 --- a/legacy/builder/builder.go +++ b/legacy/builder/builder.go @@ -19,14 +19,8 @@ import ( "reflect" "time" - "github.com/arduino/arduino-cli/arduino/builder" - "github.com/arduino/arduino-cli/arduino/builder/preprocessor" - "github.com/arduino/arduino-cli/arduino/builder/sizer" - "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/i18n" "github.com/arduino/arduino-cli/legacy/builder/types" - "github.com/arduino/go-paths-helper" - properties "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -38,11 +32,11 @@ const DEFAULT_DEBUG_LEVEL = 5 type Builder struct{} func (s *Builder) Run(ctx *types.Context) error { - if err := ctx.BuildPath.MkdirAll(); err != nil { + if err := ctx.Builder.GetBuildPath().MkdirAll(); err != nil { return err } - var _err, mainErr error + var mainErr error commands := []types.Command{ containerBuildOptions(ctx), @@ -51,8 +45,7 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - ctx.LineOffset, _err = ctx.Builder.PrepareSketchBuildPath(ctx.SourceOverride, ctx.SketchBuildPath) - return _err + return ctx.Builder.PrepareSketchBuildPath() }), logIfVerbose(false, tr("Detecting libraries used...")), @@ -70,21 +63,7 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - sketchObjectFiles, err := builder.SketchBuilder( - ctx.SketchBuildPath, - ctx.BuildProperties, - ctx.SketchLibrariesDetector.IncludeFolders(), - ctx.OnlyUpdateCompilationDatabase, - ctx.CompilationDatabase, - ctx.Builder.Jobs(), - ctx.BuilderLogger, - &ctx.Progress, ctx.ProgressCB, - ) - if err != nil { - return err - } - ctx.SketchObjectFiles = sketchObjectFiles - return nil + return ctx.Builder.BuildSketch(ctx.SketchLibrariesDetector.IncludeFolders()) }), types.BareCommand(func(ctx *types.Context) error { @@ -97,30 +76,13 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - return UnusedCompiledLibrariesRemover( - ctx.LibrariesBuildPath, + return ctx.Builder.RemoveUnusedCompiledLibraries( ctx.SketchLibrariesDetector.ImportedLibraries(), ) }), types.BareCommand(func(ctx *types.Context) error { - librariesObjectFiles, err := builder.LibrariesBuilder( - ctx.LibrariesBuildPath, - ctx.BuildProperties, - ctx.SketchLibrariesDetector.IncludeFolders(), - ctx.SketchLibrariesDetector.ImportedLibraries(), - ctx.OnlyUpdateCompilationDatabase, - ctx.CompilationDatabase, - ctx.Builder.Jobs(), - ctx.BuilderLogger, - &ctx.Progress, ctx.ProgressCB, - ) - if err != nil { - return err - } - ctx.LibrariesObjectFiles = librariesObjectFiles - - return nil + return ctx.Builder.BuildLibraries(ctx.SketchLibrariesDetector.IncludeFolders(), ctx.SketchLibrariesDetector.ImportedLibraries()) }), types.BareCommand(func(ctx *types.Context) error { return recipeByPrefixSuffixRunner(ctx, "recipe.hooks.libraries.postbuild", ".pattern", true) @@ -132,21 +94,7 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - objectFiles, archiveFile, err := builder.CoreBuilder( - ctx.BuildPath, ctx.CoreBuildPath, ctx.Builder.CoreBuildCachePath(), - ctx.BuildProperties, - ctx.ActualPlatform, - ctx.OnlyUpdateCompilationDatabase, ctx.Clean, - ctx.CompilationDatabase, - ctx.Builder.Jobs(), - ctx.BuilderLogger, - &ctx.Progress, ctx.ProgressCB, - ) - - ctx.CoreObjectsFiles = objectFiles - ctx.CoreArchiveFilePath = archiveFile - - return err + return ctx.Builder.BuildCore() }), types.BareCommand(func(ctx *types.Context) error { @@ -159,20 +107,7 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - verboseInfoOut, err := builder.Linker( - ctx.OnlyUpdateCompilationDatabase, - ctx.SketchObjectFiles, - ctx.LibrariesObjectFiles, - ctx.CoreObjectsFiles, - ctx.CoreArchiveFilePath, - ctx.BuildPath, - ctx.BuildProperties, - ctx.BuilderLogger, - ) - if ctx.BuilderLogger.Verbose() { - ctx.BuilderLogger.Info(string(verboseInfoOut)) - } - return err + return ctx.Builder.Link() }), types.BareCommand(func(ctx *types.Context) error { @@ -190,11 +125,7 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - return MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, - ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - ctx.BuilderLogger, - ) + return ctx.Builder.MergeSketchWithBootloader() }), types.BareCommand(func(ctx *types.Context) error { @@ -202,8 +133,8 @@ func (s *Builder) Run(ctx *types.Context) error { }), } - ctx.Progress.AddSubSteps(len(commands) + 5) - defer ctx.Progress.RemoveSubSteps() + ctx.Builder.Progress.AddSubSteps(len(commands) + 5) + defer ctx.Builder.Progress.RemoveSubSteps() for _, command := range commands { PrintRingNameIfDebug(ctx, command) @@ -212,13 +143,11 @@ func (s *Builder) Run(ctx *types.Context) error { mainErr = errors.WithStack(err) break } - ctx.Progress.CompleteStep() - ctx.PushProgress() + ctx.Builder.Progress.CompleteStep() + ctx.Builder.Progress.PushProgress() } - if ctx.CompilationDatabase != nil { - ctx.CompilationDatabase.SaveToFile() - } + ctx.Builder.SaveCompilationDatabase() var otherErr error commands = []types.Command{ @@ -228,38 +157,20 @@ func (s *Builder) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - infoOut, _ := PrintUsedLibrariesIfVerbose(ctx.BuilderLogger.Verbose(), ctx.SketchLibrariesDetector.ImportedLibraries()) - ctx.BuilderLogger.Info(string(infoOut)) + ctx.Builder.PrintUsedLibraries(ctx.SketchLibrariesDetector.ImportedLibraries()) return nil }), types.BareCommand(func(ctx *types.Context) error { - normalOutput, verboseOutput, err := ExportProjectCMake( + return ctx.Builder.ExportProjectCMake( mainErr != nil, - ctx.BuildPath, ctx.SketchBuildPath, ctx.SketchLibrariesDetector.ImportedLibraries(), - ctx.BuildProperties, - ctx.Builder.Sketch(), ctx.SketchLibrariesDetector.IncludeFolders(), - ctx.LineOffset, - ctx.OnlyUpdateCompilationDatabase, ) - if ctx.BuilderLogger.Verbose() { - ctx.BuilderLogger.WriteStdout(verboseOutput) - } else { - ctx.BuilderLogger.WriteStdout(normalOutput) - } - return err }), types.BareCommand(func(ctx *types.Context) error { - executableSectionsSize, err := sizer.Size( - ctx.OnlyUpdateCompilationDatabase, mainErr != nil, - ctx.BuildProperties, - ctx.BuilderLogger, - ) - ctx.ExecutableSectionsSize = executableSectionsSize - return err + return ctx.Builder.Size(mainErr != nil) }), } for _, command := range commands { @@ -269,8 +180,8 @@ func (s *Builder) Run(ctx *types.Context) error { otherErr = errors.WithStack(err) break } - ctx.Progress.CompleteStep() - ctx.PushProgress() + ctx.Builder.Progress.CompleteStep() + ctx.Builder.Progress.PushProgress() } if mainErr != nil { @@ -282,35 +193,17 @@ func (s *Builder) Run(ctx *types.Context) error { func preprocessSketchCommand(ctx *types.Context) types.BareCommand { return func(ctx *types.Context) error { - normalOutput, verboseOutput, err := PreprocessSketch( - ctx.Builder.Sketch(), ctx.BuildPath, ctx.SketchLibrariesDetector.IncludeFolders(), ctx.LineOffset, - ctx.BuildProperties, ctx.OnlyUpdateCompilationDatabase) - if ctx.BuilderLogger.Verbose() { - ctx.BuilderLogger.WriteStdout(verboseOutput) - } else { - ctx.BuilderLogger.WriteStdout(normalOutput) - } - return err + return ctx.Builder.PreprocessSketch(ctx.SketchLibrariesDetector.IncludeFolders()) } } -func PreprocessSketch( - sketch *sketch.Sketch, buildPath *paths.Path, includes paths.PathList, lineOffset int, - buildProperties *properties.Map, onlyUpdateCompilationDatabase bool, -) ([]byte, []byte, error) { - // In the future we might change the preprocessor - preprocessorImpl := preprocessor.PreprocessSketchWithCtags - return preprocessorImpl(sketch, buildPath, includes, lineOffset, buildProperties, onlyUpdateCompilationDatabase) -} - type Preprocess struct{} func (s *Preprocess) Run(ctx *types.Context) error { - if err := ctx.BuildPath.MkdirAll(); err != nil { + if err := ctx.Builder.GetBuildPath().MkdirAll(); err != nil { return err } - var _err error commands := []types.Command{ containerBuildOptions(ctx), @@ -319,8 +212,7 @@ func (s *Preprocess) Run(ctx *types.Context) error { }), types.BareCommand(func(ctx *types.Context) error { - ctx.LineOffset, _err = ctx.Builder.PrepareSketchBuildPath(ctx.SourceOverride, ctx.SketchBuildPath) - return _err + return ctx.Builder.PrepareSketchBuildPath() }), findIncludes(ctx), @@ -335,7 +227,7 @@ func (s *Preprocess) Run(ctx *types.Context) error { } // Output arduino-preprocessed source - preprocessedSketch, err := ctx.SketchBuildPath.Join(ctx.Builder.Sketch().MainFile.Base() + ".cpp").ReadFile() + preprocessedSketch, err := ctx.Builder.GetSketchBuildPath().Join(ctx.Builder.Sketch().MainFile.Base() + ".cpp").ReadFile() if err != nil { return err } @@ -344,8 +236,8 @@ func (s *Preprocess) Run(ctx *types.Context) error { } func runCommands(ctx *types.Context, commands []types.Command) error { - ctx.Progress.AddSubSteps(len(commands)) - defer ctx.Progress.RemoveSubSteps() + ctx.Builder.Progress.AddSubSteps(len(commands)) + defer ctx.Builder.Progress.RemoveSubSteps() for _, command := range commands { PrintRingNameIfDebug(ctx, command) @@ -353,8 +245,8 @@ func runCommands(ctx *types.Context, commands []types.Command) error { if err != nil { return errors.WithStack(err) } - ctx.Progress.CompleteStep() - ctx.PushProgress() + ctx.Builder.Progress.CompleteStep() + ctx.Builder.Progress.PushProgress() } return nil } @@ -375,14 +267,14 @@ func RunPreprocess(ctx *types.Context) error { func findIncludes(ctx *types.Context) types.BareCommand { return types.BareCommand(func(ctx *types.Context) error { return ctx.SketchLibrariesDetector.FindIncludes( - ctx.BuildPath, - ctx.BuildProperties.GetPath("build.core.path"), - ctx.BuildProperties.GetPath("build.variant.path"), - ctx.SketchBuildPath, + ctx.Builder.GetBuildPath(), + ctx.Builder.GetBuildProperties().GetPath("build.core.path"), + ctx.Builder.GetBuildProperties().GetPath("build.variant.path"), + ctx.Builder.GetSketchBuildPath(), ctx.Builder.Sketch(), - ctx.LibrariesBuildPath, - ctx.BuildProperties, - ctx.TargetPlatform.Platform.Architecture, + ctx.Builder.GetLibrariesBuildPath(), + ctx.Builder.GetBuildProperties(), + ctx.Builder.TargetPlatform().Platform.Architecture, ) }) } @@ -402,45 +294,19 @@ func logIfVerbose(warn bool, msg string) types.BareCommand { } func recipeByPrefixSuffixRunner(ctx *types.Context, prefix, suffix string, skipIfOnlyUpdatingCompilationDatabase bool) error { - return RecipeByPrefixSuffixRunner( - prefix, suffix, skipIfOnlyUpdatingCompilationDatabase, - ctx.OnlyUpdateCompilationDatabase, - ctx.BuildProperties, - ctx.BuilderLogger, - ) + return ctx.Builder.RunRecipe(prefix, suffix, skipIfOnlyUpdatingCompilationDatabase) } func containerBuildOptions(ctx *types.Context) types.BareCommand { return types.BareCommand(func(ctx *types.Context) error { - // TODO here we can pass only the properties we're reading from the - // ctx.BuildProperties - buildOptionsJSON, buildOptionsJSONPrevious, infoMessage, err := ContainerBuildOptions( - ctx.HardwareDirs, ctx.BuiltInToolsDirs, ctx.OtherLibrariesDirs, - ctx.BuiltInLibrariesDirs, ctx.BuildPath, ctx.Builder.Sketch(), ctx.CustomBuildProperties, - ctx.FQBN.String(), ctx.Clean, ctx.BuildProperties, - ) - if infoMessage != "" { - ctx.BuilderLogger.Info(infoMessage) - } - if err != nil { - return err - } - - ctx.BuildOptionsJson = buildOptionsJSON - ctx.BuildOptionsJsonPrevious = buildOptionsJSONPrevious - - return nil + return ctx.Builder.BuildOptionsManager.WipeBuildPath() }) } func warnAboutArchIncompatibleLibraries(ctx *types.Context) types.BareCommand { return types.BareCommand(func(ctx *types.Context) error { - overrides, _ := ctx.BuildProperties.GetOk("architecture.override_check") - WarnAboutArchIncompatibleLibraries( - ctx.TargetPlatform, - overrides, + ctx.Builder.WarnAboutArchIncompatibleLibraries( ctx.SketchLibrariesDetector.ImportedLibraries(), - func(s string) { ctx.BuilderLogger.Info(s) }, ) return nil }) diff --git a/legacy/builder/constants/constants.go b/legacy/builder/constants/constants.go deleted file mode 100644 index 31287e769da..00000000000 --- a/legacy/builder/constants/constants.go +++ /dev/null @@ -1,47 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) -// Copyright 2015 Matthijs Kooijman -// -// 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 constants - -const BUILD_OPTIONS_FILE = "build.options.json" -const BUILD_PROPERTIES_ARCH_OVERRIDE_CHECK = "architecture.override_check" -const BUILD_PROPERTIES_BOOTLOADER_FILE = "bootloader.file" -const BUILD_PROPERTIES_BOOTLOADER_NOBLINK = "bootloader.noblink" -const BUILD_PROPERTIES_BUILD_BOARD = "build.board" -const BUILD_PROPERTIES_COMPILER_LDFLAGS = "compiler.ldflags" -const BUILD_PROPERTIES_COMPILER_CPP_FLAGS = "compiler.cpp.flags" -const FOLDER_BOOTLOADERS = "bootloaders" -const FOLDER_CORE = "core" -const FOLDER_SKETCH = "sketch" -const FOLDER_TOOLS = "tools" -const FOLDER_LIBRARIES = "libraries" -const LIBRARY_ALL_ARCHS = "*" -const LIBRARY_EMAIL = "email" -const LIBRARY_FOLDER_SRC = "src" -const LOG_LEVEL_DEBUG = "debug" -const LOG_LEVEL_ERROR = "error" -const LOG_LEVEL_INFO = "info" -const LOG_LEVEL_WARN = "warn" - -const PACKAGE_NAME = "name" -const PACKAGE_TOOLS = "tools" -const PLATFORM_ARCHITECTURE = "architecture" -const PLATFORM_URL = "url" -const PLATFORM_VERSION = "version" -const RECIPE_C_COMBINE_PATTERN = "recipe.c.combine.pattern" -const TOOL_NAME = "name" -const TOOL_URL = "url" -const TOOL_VERSION = "version" diff --git a/legacy/builder/container_build_options.go b/legacy/builder/container_build_options.go deleted file mode 100644 index 6302bc558f7..00000000000 --- a/legacy/builder/container_build_options.go +++ /dev/null @@ -1,60 +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 ( - "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/go-paths-helper" - properties "github.com/arduino/go-properties-orderedmap" - "github.com/pkg/errors" -) - -func ContainerBuildOptions( - hardwareDirs, builtInToolsDirs, otherLibrariesDirs paths.PathList, - builtInLibrariesDirs, buildPath *paths.Path, - sketch *sketch.Sketch, - customBuildProperties []string, - fqbn string, - clean bool, - buildProperties *properties.Map, -) (string, string, string, error) { - buildOptionsJSON, err := CreateBuildOptionsMap( - hardwareDirs, builtInToolsDirs, otherLibrariesDirs, - builtInLibrariesDirs, sketch, customBuildProperties, - fqbn, buildProperties.Get("compiler.optimization_flags"), - ) - if err != nil { - return "", "", "", errors.WithStack(err) - } - - buildOptionsJSONPrevious, err := LoadPreviousBuildOptionsMap(buildPath) - if err != nil { - return "", "", "", errors.WithStack(err) - } - - infoOut, err := WipeoutBuildPathIfBuildOptionsChanged( - clean, - buildPath, - buildOptionsJSON, - buildOptionsJSONPrevious, - buildProperties, - ) - if err != nil { - return "", "", "", errors.WithStack(err) - } - - return buildOptionsJSON, buildOptionsJSONPrevious, infoOut, StoreBuildOptionsMap(buildPath, buildOptionsJSON) -} diff --git a/legacy/builder/create_build_options_map.go b/legacy/builder/create_build_options_map.go deleted file mode 100644 index 23240f56bc1..00000000000 --- a/legacy/builder/create_build_options_map.go +++ /dev/null @@ -1,63 +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 ( - "encoding/json" - "strings" - - "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/go-paths-helper" - properties "github.com/arduino/go-properties-orderedmap" - "github.com/pkg/errors" -) - -func CreateBuildOptionsMap( - hardwareDirs, builtInToolsDirs, otherLibrariesDirs paths.PathList, - builtInLibrariesDirs *paths.Path, - sketch *sketch.Sketch, - customBuildProperties []string, - fqbn, compilerOptimizationFlags string, -) (string, error) { - opts := properties.NewMap() - opts.Set("hardwareFolders", strings.Join(hardwareDirs.AsStrings(), ",")) - opts.Set("builtInToolsFolders", strings.Join(builtInToolsDirs.AsStrings(), ",")) - if builtInLibrariesDirs != nil { - opts.Set("builtInLibrariesFolders", builtInLibrariesDirs.String()) - } - opts.Set("otherLibrariesFolders", strings.Join(otherLibrariesDirs.AsStrings(), ",")) - opts.SetPath("sketchLocation", sketch.FullPath) - var additionalFilesRelative []string - absPath := sketch.FullPath.Parent() - for _, f := range sketch.AdditionalFiles { - relPath, err := f.RelTo(absPath) - if err != nil { - continue // ignore - } - additionalFilesRelative = append(additionalFilesRelative, relPath.String()) - } - opts.Set("fqbn", fqbn) - opts.Set("customBuildProperties", strings.Join(customBuildProperties, ",")) - opts.Set("additionalFiles", strings.Join(additionalFilesRelative, ",")) - opts.Set("compiler.optimization_flags", compilerOptimizationFlags) - - buildOptionsJSON, err := json.MarshalIndent(opts, "", " ") - if err != nil { - return "", errors.WithStack(err) - } - - return string(buildOptionsJSON), nil -} diff --git a/legacy/builder/merge_sketch_with_bootloader.go b/legacy/builder/merge_sketch_with_bootloader.go deleted file mode 100644 index 7d77204de33..00000000000 --- a/legacy/builder/merge_sketch_with_bootloader.go +++ /dev/null @@ -1,160 +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 ( - "math" - "strconv" - "strings" - - "github.com/arduino/arduino-cli/arduino/builder/logger" - "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/arduino-cli/legacy/builder/constants" - "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" - "github.com/marcinbor85/gohex" - "github.com/pkg/errors" -) - -func MergeSketchWithBootloader( - onlyUpdateCompilationDatabase bool, - buildPath *paths.Path, - sketch *sketch.Sketch, - buildProperties *properties.Map, - builderLogger *logger.BuilderLogger, -) error { - if onlyUpdateCompilationDatabase { - return nil - } - - if !buildProperties.ContainsKey(constants.BUILD_PROPERTIES_BOOTLOADER_NOBLINK) && !buildProperties.ContainsKey(constants.BUILD_PROPERTIES_BOOTLOADER_FILE) { - return nil - } - - sketchFileName := sketch.MainFile.Base() - sketchInBuildPath := buildPath.Join(sketchFileName + ".hex") - sketchInSubfolder := buildPath.Join(constants.FOLDER_SKETCH, sketchFileName+".hex") - - var builtSketchPath *paths.Path - if sketchInBuildPath.Exist() { - builtSketchPath = sketchInBuildPath - } else if sketchInSubfolder.Exist() { - builtSketchPath = sketchInSubfolder - } else { - return nil - } - - bootloader := "" - if bootloaderNoBlink, ok := buildProperties.GetOk(constants.BUILD_PROPERTIES_BOOTLOADER_NOBLINK); ok { - bootloader = bootloaderNoBlink - } else { - bootloader = buildProperties.Get(constants.BUILD_PROPERTIES_BOOTLOADER_FILE) - } - bootloader = buildProperties.ExpandPropsInString(bootloader) - - bootloaderPath := buildProperties.GetPath("runtime.platform.path").Join(constants.FOLDER_BOOTLOADERS, bootloader) - if bootloaderPath.NotExist() { - if builderLogger.Verbose() { - builderLogger.Warn(tr("Bootloader file specified but missing: %[1]s", bootloaderPath)) - } - return nil - } - - mergedSketchPath := builtSketchPath.Parent().Join(sketchFileName + ".with_bootloader.hex") - - // Ignore merger errors for the first iteration - maximumBinSize := 16000000 - if uploadMaxSize, ok := buildProperties.GetOk("upload.maximum_size"); ok { - maximumBinSize, _ = strconv.Atoi(uploadMaxSize) - maximumBinSize *= 2 - } - err := merge(builtSketchPath, bootloaderPath, mergedSketchPath, maximumBinSize) - if err != nil && builderLogger.Verbose() { - builderLogger.Info(err.Error()) - } - - return nil -} - -func merge(builtSketchPath, bootloaderPath, mergedSketchPath *paths.Path, maximumBinSize int) error { - if bootloaderPath.Ext() == ".bin" { - bootloaderPath = paths.New(strings.TrimSuffix(bootloaderPath.String(), ".bin") + ".hex") - } - - memBoot := gohex.NewMemory() - if bootFile, err := bootloaderPath.Open(); err == nil { - defer bootFile.Close() - if err := memBoot.ParseIntelHex(bootFile); err != nil { - return errors.New(bootFile.Name() + " " + err.Error()) - } - } else { - return err - } - - memSketch := gohex.NewMemory() - if buildFile, err := builtSketchPath.Open(); err == nil { - defer buildFile.Close() - if err := memSketch.ParseIntelHex(buildFile); err != nil { - return errors.New(buildFile.Name() + " " + err.Error()) - } - } else { - return err - } - - memMerged := gohex.NewMemory() - initialAddress := uint32(math.MaxUint32) - lastAddress := uint32(0) - - for _, segment := range memBoot.GetDataSegments() { - if err := memMerged.AddBinary(segment.Address, segment.Data); err != nil { - continue - } - if segment.Address < initialAddress { - initialAddress = segment.Address - } - if segment.Address+uint32(len(segment.Data)) > lastAddress { - lastAddress = segment.Address + uint32(len(segment.Data)) - } - } - for _, segment := range memSketch.GetDataSegments() { - if err := memMerged.AddBinary(segment.Address, segment.Data); err != nil { - continue - } - if segment.Address < initialAddress { - initialAddress = segment.Address - } - if segment.Address+uint32(len(segment.Data)) > lastAddress { - lastAddress = segment.Address + uint32(len(segment.Data)) - } - } - - if mergeFile, err := mergedSketchPath.Create(); err == nil { - defer mergeFile.Close() - memMerged.DumpIntelHex(mergeFile, 16) - } else { - return err - } - - // Write out a .bin if the addresses doesn't go too far away from origin - // (and consequently produce a very large bin) - size := lastAddress - initialAddress - if size > uint32(maximumBinSize) { - return nil - } - mergedSketchPathBin := paths.New(strings.TrimSuffix(mergedSketchPath.String(), ".hex") + ".bin") - data := memMerged.ToBinary(initialAddress, size, 0xFF) - return mergedSketchPathBin.WriteFile(data) -} diff --git a/legacy/builder/print_used_libraries_if_verbose.go b/legacy/builder/print_used_libraries_if_verbose.go deleted file mode 100644 index 1ae369d30a2..00000000000 --- a/legacy/builder/print_used_libraries_if_verbose.go +++ /dev/null @@ -1,54 +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 ( - "bytes" - "time" - - "github.com/arduino/arduino-cli/arduino/libraries" -) - -func PrintUsedLibrariesIfVerbose(verbose bool, importedLibraries libraries.List) ([]byte, error) { - if !verbose || len(importedLibraries) == 0 { - return nil, nil - } - - infoBuf := &bytes.Buffer{} - for _, library := range importedLibraries { - legacy := "" - if library.IsLegacy { - legacy = tr("(legacy)") - } - if library.Version.String() == "" { - infoBuf.WriteString( - tr("Using library %[1]s in folder: %[2]s %[3]s", - library.Name, - library.InstallDir, - legacy)) - } else { - infoBuf.WriteString( - tr("Using library %[1]s at version %[2]s in folder: %[3]s %[4]s", - library.Name, - library.Version, - library.InstallDir, - legacy)) - } - } - - time.Sleep(100 * time.Millisecond) - return infoBuf.Bytes(), nil -} diff --git a/legacy/builder/store_build_options_map.go b/legacy/builder/store_build_options_map.go deleted file mode 100644 index bc872d76d63..00000000000 --- a/legacy/builder/store_build_options_map.go +++ /dev/null @@ -1,25 +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 ( - "github.com/arduino/arduino-cli/legacy/builder/constants" - "github.com/arduino/go-paths-helper" -) - -func StoreBuildOptionsMap(buildPath *paths.Path, buildOptionsJson string) error { - return buildPath.Join(constants.BUILD_OPTIONS_FILE).WriteFile([]byte(buildOptionsJson)) -} diff --git a/legacy/builder/test/builder_test.go b/legacy/builder/test/builder_test.go index e6af9105ebc..25df800ff5e 100644 --- a/legacy/builder/test/builder_test.go +++ b/legacy/builder/test/builder_test.go @@ -17,39 +17,30 @@ package test import ( "fmt" + "os" "path/filepath" "testing" bldr "github.com/arduino/arduino-cli/arduino/builder" "github.com/arduino/arduino-cli/arduino/builder/detector" "github.com/arduino/arduino-cli/arduino/builder/logger" + "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/arduino-cli/legacy/builder/constants" "github.com/arduino/arduino-cli/legacy/builder/types" "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" ) func cleanUpBuilderTestContext(t *testing.T, ctx *types.Context) { - if ctx.BuildPath != nil { - err := ctx.BuildPath.RemoveAll() - require.NoError(t, err) + if ctx.Builder.GetBuildPath() != nil { + require.NoError(t, ctx.Builder.GetBuildPath().RemoveAll()) } } -type skipContextPreparationStepName string - -const skipLibraries = skipContextPreparationStepName("libraries") - -func prepareBuilderTestContext(t *testing.T, ctx *types.Context, sketchPath *paths.Path, fqbn string, skips ...skipContextPreparationStepName) *types.Context { +func prepareBuilderTestContext(t *testing.T, ctx *types.Context, sketchPath *paths.Path, fqbnString string) *types.Context { DownloadCoresAndToolsAndLibraries(t) - stepToSkip := map[skipContextPreparationStepName]bool{} - for _, skip := range skips { - stepToSkip[skip] = true - } - if ctx == nil { ctx = &types.Context{} } @@ -59,23 +50,10 @@ func prepareBuilderTestContext(t *testing.T, ctx *types.Context, sketchPath *pat ctx.BuiltInLibrariesDirs = paths.New("downloaded_libraries") ctx.OtherLibrariesDirs = paths.NewPathList("libraries") } - if ctx.BuildPath == nil { - buildPath, err := paths.MkTempDir("", "test_build_path") - require.NoError(t, err) - ctx.BuildPath = buildPath - } - buildPath := ctx.BuildPath - sketchBuildPath, err := buildPath.Join(constants.FOLDER_SKETCH).Abs() - require.NoError(t, err) - librariesBuildPath, err := buildPath.Join(constants.FOLDER_LIBRARIES).Abs() - require.NoError(t, err) - coreBuildPath, err := buildPath.Join(constants.FOLDER_CORE).Abs() + buildPath, err := paths.MkTempDir("", "test_build_path") require.NoError(t, err) - - ctx.SketchBuildPath = sketchBuildPath - ctx.LibrariesBuildPath = librariesBuildPath - ctx.CoreBuildPath = coreBuildPath + require.NotNil(t, buildPath) // Create a Package Manager from the given context // This should happen only on legacy arduino-builder. @@ -99,45 +77,65 @@ func prepareBuilderTestContext(t *testing.T, ctx *types.Context, sketchPath *pat sk = s } + // This is an hack to avoid panic when the `NewBuilder` assert a condition on sketch path. + // Since the test will be migrated soon in an E2E manner we temporary set the sketch to be empty. + // so this assertion inside the Builder: + // buildPath().Canonical().EqualsTo(sk.FullPath.Canonical())` + // Doesn't fail + if sk == nil { + sk = &sketch.Sketch{ + MainFile: &paths.Path{}, + FullPath: paths.New(os.TempDir()), + OtherSketchFiles: []*paths.Path{}, + AdditionalFiles: []*paths.Path{}, + RootFolderFiles: []*paths.Path{}, + Project: &sketch.Project{}, + } + } + builderLogger := logger.New(nil, nil, false, "") ctx.BuilderLogger = builderLogger - ctx.Builder = bldr.NewBuilder(sk, nil, nil, false, nil, 0) - if fqbn != "" { - ctx.FQBN = parseFQBN(t, fqbn) - targetPackage, targetPlatform, targetBoard, boardBuildProperties, buildPlatform, err := pme.ResolveFQBN(ctx.FQBN) + ctx.Builder, err = bldr.NewBuilder( + sk, nil, buildPath, false, nil, 0, nil, + ctx.HardwareDirs, ctx.BuiltInToolsDirs, ctx.OtherLibrariesDirs, + ctx.BuiltInLibrariesDirs, parseFQBN(t, "a:b:c"), false, nil, false, + nil, nil, builderLogger, nil, + ) + require.NoError(t, err) + + var actualPlatform, targetPlatform *cores.PlatformRelease + if fqbnString != "" { + fqbn := parseFQBN(t, fqbnString) + _, targetPlatfrm, _, boardBuildProperties, buildPlatform, err := pme.ResolveFQBN(fqbn) require.NoError(t, err) - requiredTools, err := pme.FindToolsRequiredForBuild(targetPlatform, buildPlatform) + targetPlatform = targetPlatfrm + actualPlatform = buildPlatform + + _, err = pme.FindToolsRequiredForBuild(targetPlatform, buildPlatform) require.NoError(t, err) - ctx.Builder = bldr.NewBuilder(sk, boardBuildProperties, ctx.BuildPath, false /*OptimizeForDebug*/, nil, 0) + ctx.Builder, err = bldr.NewBuilder( + sk, boardBuildProperties, buildPath, false, nil, 0, nil, + ctx.HardwareDirs, ctx.BuiltInToolsDirs, ctx.OtherLibrariesDirs, + ctx.BuiltInLibrariesDirs, fqbn, false, nil, false, targetPlatform, + actualPlatform, builderLogger, nil) + require.NoError(t, err) ctx.PackageManager = pme - ctx.TargetBoard = targetBoard - ctx.BuildProperties = ctx.Builder.GetBuildProperties() - ctx.TargetPlatform = targetPlatform - ctx.TargetPackage = targetPackage - ctx.ActualPlatform = buildPlatform - ctx.RequiredTools = requiredTools } - if sk != nil { - require.False(t, ctx.BuildPath.Canonical().EqualsTo(sk.FullPath.Canonical())) - } - - if !stepToSkip[skipLibraries] { - lm, libsResolver, _, err := detector.LibrariesLoader( - false, nil, - ctx.BuiltInLibrariesDirs, nil, ctx.OtherLibrariesDirs, - ctx.ActualPlatform, ctx.TargetPlatform, - ) - require.NoError(t, err) + lm, libsResolver, _, err := detector.LibrariesLoader( + false, nil, + ctx.BuiltInLibrariesDirs, nil, ctx.OtherLibrariesDirs, + actualPlatform, targetPlatform, + ) + require.NoError(t, err) - ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( - lm, libsResolver, - false, - false, - builderLogger, - ) - } + ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( + lm, libsResolver, + false, + false, + builderLogger, + ) return ctx } diff --git a/legacy/builder/test/builder_utils_test.go b/legacy/builder/test/builder_utils_test.go deleted file mode 100644 index 8d5cb09de2e..00000000000 --- a/legacy/builder/test/builder_utils_test.go +++ /dev/null @@ -1,156 +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 test - -import ( - "os" - "testing" - "time" - - "github.com/arduino/arduino-cli/arduino/builder/utils" - paths "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" -) - -func tempFile(t *testing.T, prefix string) *paths.Path { - file, err := os.CreateTemp("", prefix) - file.Close() - require.NoError(t, err) - return paths.New(file.Name()) -} - -func TestObjFileIsUpToDateObjMissing(t *testing.T) { - sourceFile := tempFile(t, "source") - defer sourceFile.RemoveAll() - - upToDate, err := utils.ObjFileIsUpToDate(sourceFile, nil, nil) - require.NoError(t, err) - require.False(t, upToDate) -} - -func TestObjFileIsUpToDateDepMissing(t *testing.T) { - sourceFile := tempFile(t, "source") - defer sourceFile.RemoveAll() - - objFile := tempFile(t, "obj") - defer objFile.RemoveAll() - - upToDate, err := utils.ObjFileIsUpToDate(sourceFile, objFile, nil) - require.NoError(t, err) - require.False(t, upToDate) -} - -func TestObjFileIsUpToDateObjOlder(t *testing.T) { - objFile := tempFile(t, "obj") - defer objFile.RemoveAll() - depFile := tempFile(t, "dep") - defer depFile.RemoveAll() - - time.Sleep(time.Second) - - sourceFile := tempFile(t, "source") - defer sourceFile.RemoveAll() - - upToDate, err := utils.ObjFileIsUpToDate(sourceFile, objFile, depFile) - require.NoError(t, err) - require.False(t, upToDate) -} - -func TestObjFileIsUpToDateObjNewer(t *testing.T) { - sourceFile := tempFile(t, "source") - defer sourceFile.RemoveAll() - - time.Sleep(time.Second) - - objFile := tempFile(t, "obj") - defer objFile.RemoveAll() - depFile := tempFile(t, "dep") - defer depFile.RemoveAll() - - upToDate, err := utils.ObjFileIsUpToDate(sourceFile, objFile, depFile) - require.NoError(t, err) - require.True(t, upToDate) -} - -func TestObjFileIsUpToDateDepIsNewer(t *testing.T) { - sourceFile := tempFile(t, "source") - defer sourceFile.RemoveAll() - - time.Sleep(time.Second) - - objFile := tempFile(t, "obj") - defer objFile.RemoveAll() - depFile := tempFile(t, "dep") - defer depFile.RemoveAll() - - time.Sleep(time.Second) - - headerFile := tempFile(t, "header") - defer headerFile.RemoveAll() - - data := objFile.String() + ": \\\n\t" + sourceFile.String() + " \\\n\t" + headerFile.String() - depFile.WriteFile([]byte(data)) - - upToDate, err := utils.ObjFileIsUpToDate(sourceFile, objFile, depFile) - require.NoError(t, err) - require.False(t, upToDate) -} - -func TestObjFileIsUpToDateDepIsOlder(t *testing.T) { - sourceFile := tempFile(t, "source") - defer sourceFile.RemoveAll() - - headerFile := tempFile(t, "header") - defer headerFile.RemoveAll() - - time.Sleep(time.Second) - - objFile := tempFile(t, "obj") - defer objFile.RemoveAll() - depFile := tempFile(t, "dep") - defer depFile.RemoveAll() - - res := objFile.String() + ": \\\n\t" + sourceFile.String() + " \\\n\t" + headerFile.String() - depFile.WriteFile([]byte(res)) - - upToDate, err := utils.ObjFileIsUpToDate(sourceFile, objFile, depFile) - require.NoError(t, err) - require.True(t, upToDate) -} - -func TestObjFileIsUpToDateDepIsWrong(t *testing.T) { - sourceFile := tempFile(t, "source") - defer sourceFile.RemoveAll() - - time.Sleep(time.Second) - - objFile := tempFile(t, "obj") - defer objFile.RemoveAll() - depFile := tempFile(t, "dep") - defer depFile.RemoveAll() - - time.Sleep(time.Second) - - headerFile := tempFile(t, "header") - defer headerFile.RemoveAll() - - res := sourceFile.String() + ": \\\n\t" + sourceFile.String() + " \\\n\t" + headerFile.String() - depFile.WriteFile([]byte(res)) - - upToDate, err := utils.ObjFileIsUpToDate(sourceFile, objFile, depFile) - require.NoError(t, err) - require.False(t, upToDate) -} diff --git a/legacy/builder/test/create_build_options_map_test.go b/legacy/builder/test/create_build_options_map_test.go deleted file mode 100644 index d3c5ce42580..00000000000 --- a/legacy/builder/test/create_build_options_map_test.go +++ /dev/null @@ -1,56 +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 test - -import ( - "testing" - - "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/arduino-cli/legacy/builder" - "github.com/arduino/arduino-cli/legacy/builder/types" - "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" - "github.com/stretchr/testify/require" -) - -func TestCreateBuildOptionsMap(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList("hardware", "hardware2"), - BuiltInToolsDirs: paths.NewPathList("tools"), - OtherLibrariesDirs: paths.NewPathList("libraries"), - FQBN: parseFQBN(t, "my:nice:fqbn"), - BuildPath: paths.New("buildPath"), - BuildProperties: properties.NewFromHashmap(map[string]string{"compiler.optimization_flags": "-Os"}), - } - - buildPropertiesJSON, err := builder.CreateBuildOptionsMap( - ctx.HardwareDirs, ctx.BuiltInToolsDirs, ctx.OtherLibrariesDirs, - ctx.BuiltInLibrariesDirs, &sketch.Sketch{FullPath: paths.New("sketchLocation")}, ctx.CustomBuildProperties, - ctx.FQBN.String(), ctx.BuildProperties.Get("compiler.optimization_flags"), - ) - require.NoError(t, err) - - require.Equal(t, `{ - "additionalFiles": "", - "builtInToolsFolders": "tools", - "compiler.optimization_flags": "-Os", - "customBuildProperties": "", - "fqbn": "my:nice:fqbn", - "hardwareFolders": "hardware,hardware2", - "otherLibrariesFolders": "libraries", - "sketchLocation": "sketchLocation" -}`, buildPropertiesJSON) -} diff --git a/legacy/builder/test/helper.go b/legacy/builder/test/helper.go index 33b9aa1e2cf..746096c473f 100644 --- a/legacy/builder/test/helper.go +++ b/legacy/builder/test/helper.go @@ -20,22 +20,13 @@ import ( "testing" "github.com/arduino/arduino-cli/arduino/cores" - "github.com/arduino/arduino-cli/arduino/libraries" - "github.com/arduino/arduino-cli/legacy/builder/types" paths "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" ) -func Abs(t *testing.T, rel *paths.Path) *paths.Path { - absPath, err := rel.Abs() - require.NoError(t, err) - return absPath -} - -func SetupBuildPath(t *testing.T, ctx *types.Context) *paths.Path { +func SetupBuildPath(t *testing.T) *paths.Path { buildPath, err := paths.MkTempDir("", "test_build_path") require.NoError(t, err) - ctx.BuildPath = buildPath return buildPath } @@ -44,15 +35,3 @@ func parseFQBN(t *testing.T, fqbnIn string) *cores.FQBN { require.NoError(t, err) return fqbn } - -type ByLibraryName []*libraries.Library - -func (s ByLibraryName) Len() int { - return len(s) -} -func (s ByLibraryName) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} -func (s ByLibraryName) Less(i, j int) bool { - return s[i].Name < s[j].Name -} diff --git a/legacy/builder/test/helper_tools_downloader.go b/legacy/builder/test/helper_tools_downloader.go index 2d80f0417fe..ee4b60df572 100644 --- a/legacy/builder/test/helper_tools_downloader.go +++ b/legacy/builder/test/helper_tools_downloader.go @@ -26,7 +26,6 @@ import ( "strings" "testing" - "github.com/arduino/arduino-cli/legacy/builder/constants" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" @@ -264,12 +263,12 @@ func findCoreUrl(index map[string]interface{}, core Core) (string, error) { packages := index["packages"].([]interface{}) for _, p := range packages { pack := p.(map[string]interface{}) - if pack[constants.PACKAGE_NAME].(string) == core.Maintainer { + if pack["name"].(string) == core.Maintainer { packagePlatforms := pack["platforms"].([]interface{}) for _, pt := range packagePlatforms { packagePlatform := pt.(map[string]interface{}) - if packagePlatform[constants.PLATFORM_ARCHITECTURE] == core.Arch && packagePlatform[constants.PLATFORM_VERSION] == core.Version { - return packagePlatform[constants.PLATFORM_URL].(string), nil + if packagePlatform["architecture"] == core.Arch && packagePlatform["version"] == core.Version { + return packagePlatform["url"].(string), nil } } } @@ -394,7 +393,7 @@ func allBoardsManagerToolsAlreadyDownloadedAndUnpacked(targetPath *paths.Path, t } func boardManagerToolAlreadyDownloadedAndUnpacked(targetPath *paths.Path, tool Tool) bool { - return targetPath.Join(tool.Package, constants.FOLDER_TOOLS, tool.Name, tool.Version).Exist() + return targetPath.Join(tool.Package, "tools", tool.Name, tool.Version).Exist() } func allToolsAlreadyDownloadedAndUnpacked(targetPath *paths.Path, tools []Tool) bool { @@ -513,10 +512,10 @@ func downloadAndUnpackBoardsManagerTool(tool Tool, url string, targetPath *paths } defer unpackFolder.RemoveAll() - if err := targetPath.Join(tool.Package, constants.FOLDER_TOOLS, tool.Name).MkdirAll(); err != nil { + if err := targetPath.Join(tool.Package, "tools", tool.Name).MkdirAll(); err != nil { return errors.WithStack(err) } - if err := unpackFolder.Join(files[0].Base()).CopyDirTo(targetPath.Join(tool.Package, constants.FOLDER_TOOLS, tool.Name, tool.Version)); err != nil { + if err := unpackFolder.Join(files[0].Base()).CopyDirTo(targetPath.Join(tool.Package, "tools", tool.Name, tool.Version)); err != nil { return errors.WithStack(err) } return nil @@ -646,17 +645,17 @@ func findToolUrl(index map[string]interface{}, tool Tool, host []string) (string packages := index["packages"].([]interface{}) for _, p := range packages { pack := p.(map[string]interface{}) - packageTools := pack[constants.PACKAGE_TOOLS].([]interface{}) + packageTools := pack["tools"].([]interface{}) for _, pt := range packageTools { packageTool := pt.(map[string]interface{}) - name := packageTool[constants.TOOL_NAME].(string) - version := packageTool[constants.TOOL_VERSION].(string) + name := packageTool["name"].(string) + version := packageTool["version"].(string) if name == tool.Name && version == tool.Version { systems := packageTool["systems"].([]interface{}) for _, s := range systems { system := s.(map[string]interface{}) if slices.Contains(host, system["host"].(string)) { - return system[constants.TOOL_URL].(string), nil + return system["url"].(string), nil } } } diff --git a/legacy/builder/test/libraries_loader_test.go b/legacy/builder/test/libraries_loader_test.go deleted file mode 100644 index 5866fbcfa98..00000000000 --- a/legacy/builder/test/libraries_loader_test.go +++ /dev/null @@ -1,267 +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 test - -import ( - "path/filepath" - "sort" - "testing" - - "github.com/arduino/arduino-cli/arduino/builder/detector" - "github.com/arduino/arduino-cli/arduino/libraries" - "github.com/arduino/arduino-cli/legacy/builder/constants" - "github.com/arduino/arduino-cli/legacy/builder/types" - paths "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" -) - -func extractLibraries(libs map[string]libraries.List) []*libraries.Library { - res := []*libraries.Library{} - for _, lib := range libs { - for _, libAlternative := range lib { - res = append(res, libAlternative) - } - } - return res -} - -func TestLoadLibrariesAVR(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware"), - BuiltInLibrariesDirs: paths.New("downloaded_libraries"), - OtherLibrariesDirs: paths.NewPathList("libraries"), - } - ctx = prepareBuilderTestContext(t, ctx, nil, "arduino:avr:leonardo") - defer cleanUpBuilderTestContext(t, ctx) - - lm, libsResolver, _, err := detector.LibrariesLoader( - false, nil, - ctx.BuiltInLibrariesDirs, nil, ctx.OtherLibrariesDirs, - ctx.ActualPlatform, ctx.TargetPlatform, - ) - require.NoError(t, err) - - librariesFolders := lm.LibrariesDir - require.Equal(t, 3, len(librariesFolders)) - require.True(t, Abs(t, paths.New("downloaded_libraries")).EquivalentTo(librariesFolders[0].Path)) - require.True(t, Abs(t, paths.New("downloaded_hardware", "arduino", "avr", "libraries")).EquivalentTo(librariesFolders[1].Path)) - require.True(t, Abs(t, paths.New("libraries")).EquivalentTo(librariesFolders[2].Path)) - - libs := extractLibraries(lm.Libraries) - require.Equal(t, 24, len(libs)) - - sort.Sort(ByLibraryName(libs)) - - idx := 0 - - require.Equal(t, "ANewLibrary-master", libs[idx].Name) - - idx++ - require.Equal(t, "Adafruit PN532", libs[idx].Name) - require.True(t, Abs(t, paths.New("downloaded_libraries/Adafruit_PN532")).EquivalentTo(libs[idx].InstallDir)) - require.True(t, Abs(t, paths.New("downloaded_libraries/Adafruit_PN532")).EquivalentTo(libs[idx].SourceDir)) - require.Equal(t, 1, len(libs[idx].Architectures)) - require.Equal(t, constants.LIBRARY_ALL_ARCHS, libs[idx].Architectures[0]) - require.False(t, libs[idx].IsLegacy) - - idx++ - require.Equal(t, "Audio", libs[idx].Name) - - idx++ - require.Equal(t, "Balanduino", libs[idx].Name) - require.True(t, libs[idx].IsLegacy) - - idx++ - bridgeLib := libs[idx] - require.Equal(t, "Bridge", bridgeLib.Name) - require.True(t, Abs(t, paths.New("downloaded_libraries/Bridge")).EquivalentTo(bridgeLib.InstallDir)) - require.True(t, Abs(t, paths.New("downloaded_libraries/Bridge/src")).EquivalentTo(bridgeLib.SourceDir)) - require.Equal(t, 1, len(bridgeLib.Architectures)) - require.Equal(t, constants.LIBRARY_ALL_ARCHS, bridgeLib.Architectures[0]) - require.Equal(t, "Arduino", bridgeLib.Author) - require.Equal(t, "Arduino ", bridgeLib.Maintainer) - - idx++ - require.Equal(t, "CapacitiveSensor", libs[idx].Name) - idx++ - require.Equal(t, "EEPROM", libs[idx].Name) - idx++ - require.Equal(t, "Ethernet", libs[idx].Name) - idx++ - require.Equal(t, "FakeAudio", libs[idx].Name) - idx++ - require.Equal(t, "FastLED", libs[idx].Name) - idx++ - require.Equal(t, "HID", libs[idx].Name) - idx++ - require.Equal(t, "IRremote", libs[idx].Name) - idx++ - require.Equal(t, "Robot IR Remote", libs[idx].Name) - idx++ - require.Equal(t, "SPI", libs[idx].Name) - idx++ - require.Equal(t, "SPI", libs[idx].Name) - idx++ - require.Equal(t, "ShouldNotRecurseWithOldLibs", libs[idx].Name) - idx++ - require.Equal(t, "SoftwareSerial", libs[idx].Name) - idx++ - require.Equal(t, "USBHost", libs[idx].Name) - idx++ - require.Equal(t, "Wire", libs[idx].Name) - - libs = libsResolver.AlternativesFor("Audio.h") - require.Len(t, libs, 2) - sort.Sort(ByLibraryName(libs)) - require.Equal(t, "Audio", libs[0].Name) - require.Equal(t, "FakeAudio", libs[1].Name) - - libs = libsResolver.AlternativesFor("FakeAudio.h") - require.Len(t, libs, 1) - require.Equal(t, "FakeAudio", libs[0].Name) - - libs = libsResolver.AlternativesFor("Adafruit_PN532.h") - require.Len(t, libs, 1) - require.Equal(t, "Adafruit PN532", libs[0].Name) - - libs = libsResolver.AlternativesFor("IRremote.h") - require.Len(t, libs, 1) - require.Equal(t, "IRremote", libs[0].Name) -} - -func TestLoadLibrariesSAM(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware"), - BuiltInLibrariesDirs: paths.New("downloaded_libraries"), - OtherLibrariesDirs: paths.NewPathList("libraries"), - } - ctx = prepareBuilderTestContext(t, ctx, nil, "arduino:sam:arduino_due_x_dbg") - defer cleanUpBuilderTestContext(t, ctx) - - lm, libsResolver, _, err := detector.LibrariesLoader( - false, nil, - ctx.BuiltInLibrariesDirs, nil, ctx.OtherLibrariesDirs, - ctx.ActualPlatform, ctx.TargetPlatform, - ) - require.NoError(t, err) - - librariesFolders := lm.LibrariesDir - require.Equal(t, 3, len(librariesFolders)) - require.True(t, Abs(t, paths.New("downloaded_libraries")).EquivalentTo(librariesFolders[0].Path)) - require.True(t, Abs(t, paths.New("downloaded_hardware", "arduino", "sam", "libraries")).EquivalentTo(librariesFolders[1].Path)) - require.True(t, Abs(t, paths.New("libraries")).EquivalentTo(librariesFolders[2].Path)) - - libraries := extractLibraries(lm.Libraries) - require.Equal(t, 22, len(libraries)) - - sort.Sort(ByLibraryName(libraries)) - - idx := 0 - require.Equal(t, "ANewLibrary-master", libraries[idx].Name) - idx++ - require.Equal(t, "Adafruit PN532", libraries[idx].Name) - idx++ - require.Equal(t, "Audio", libraries[idx].Name) - idx++ - require.Equal(t, "Balanduino", libraries[idx].Name) - idx++ - require.Equal(t, "Bridge", libraries[idx].Name) - idx++ - require.Equal(t, "CapacitiveSensor", libraries[idx].Name) - idx++ - require.Equal(t, "Ethernet", libraries[idx].Name) - idx++ - require.Equal(t, "FakeAudio", libraries[idx].Name) - idx++ - require.Equal(t, "FastLED", libraries[idx].Name) - idx++ - require.Equal(t, "HID", libraries[idx].Name) - idx++ - require.Equal(t, "IRremote", libraries[idx].Name) - idx++ - require.Equal(t, "Robot IR Remote", libraries[idx].Name) - idx++ - require.Equal(t, "SPI", libraries[idx].Name) - idx++ - require.Equal(t, "SPI", libraries[idx].Name) - idx++ - require.Equal(t, "ShouldNotRecurseWithOldLibs", libraries[idx].Name) - idx++ - require.Equal(t, "USBHost", libraries[idx].Name) - idx++ - require.Equal(t, "Wire", libraries[idx].Name) - - libs := libsResolver.AlternativesFor("Audio.h") - require.Len(t, libs, 2) - sort.Sort(ByLibraryName(libs)) - require.Equal(t, "Audio", libs[0].Name) - require.Equal(t, "FakeAudio", libs[1].Name) - - libs = libsResolver.AlternativesFor("FakeAudio.h") - require.Len(t, libs, 1) - require.Equal(t, "FakeAudio", libs[0].Name) - - libs = libsResolver.AlternativesFor("IRremote.h") - require.Len(t, libs, 1) - require.Equal(t, "IRremote", libs[0].Name) -} - -func TestLoadLibrariesAVRNoDuplicateLibrariesFolders(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware"), - BuiltInLibrariesDirs: paths.New("downloaded_libraries"), - OtherLibrariesDirs: paths.NewPathList("libraries", filepath.Join("downloaded_hardware", "arduino", "avr", "libraries")), - } - ctx = prepareBuilderTestContext(t, ctx, nil, "arduino:avr:leonardo") - defer cleanUpBuilderTestContext(t, ctx) - - lm, _, _, err := detector.LibrariesLoader( - false, nil, - ctx.BuiltInLibrariesDirs, nil, ctx.OtherLibrariesDirs, - ctx.ActualPlatform, ctx.TargetPlatform, - ) - require.NoError(t, err) - - librariesFolders := lm.LibrariesDir - require.Equal(t, 3, len(librariesFolders)) - require.True(t, Abs(t, paths.New("downloaded_libraries")).EquivalentTo(librariesFolders[0].Path)) - require.True(t, Abs(t, paths.New("downloaded_hardware", "arduino", "avr", "libraries")).EquivalentTo(librariesFolders[1].Path)) - require.True(t, Abs(t, paths.New("libraries")).EquivalentTo(librariesFolders[2].Path)) -} - -func TestLoadLibrariesMyAVRPlatform(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "user_hardware", "downloaded_hardware"), - BuiltInLibrariesDirs: paths.New("downloaded_libraries"), - OtherLibrariesDirs: paths.NewPathList("libraries", filepath.Join("downloaded_hardware", "arduino", "avr", "libraries")), - } - ctx = prepareBuilderTestContext(t, ctx, nil, "my_avr_platform:avr:custom_yun") - defer cleanUpBuilderTestContext(t, ctx) - - lm, _, _, err := detector.LibrariesLoader( - false, nil, - ctx.BuiltInLibrariesDirs, nil, ctx.OtherLibrariesDirs, - ctx.ActualPlatform, ctx.TargetPlatform, - ) - require.NoError(t, err) - - librariesFolders := lm.LibrariesDir - require.Equal(t, 4, len(librariesFolders)) - require.True(t, Abs(t, paths.New("downloaded_libraries")).EquivalentTo(librariesFolders[0].Path)) - require.True(t, Abs(t, paths.New("downloaded_hardware", "arduino", "avr", "libraries")).EquivalentTo(librariesFolders[1].Path)) - require.True(t, Abs(t, paths.New("user_hardware", "my_avr_platform", "avr", "libraries")).EquivalentTo(librariesFolders[2].Path)) - require.True(t, Abs(t, paths.New("libraries")).EquivalentTo(librariesFolders[3].Path)) -} diff --git a/legacy/builder/test/load_previous_build_options_map_test.go b/legacy/builder/test/load_previous_build_options_map_test.go deleted file mode 100644 index 88613fb9034..00000000000 --- a/legacy/builder/test/load_previous_build_options_map_test.go +++ /dev/null @@ -1,51 +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 test - -import ( - "testing" - - "github.com/arduino/arduino-cli/legacy/builder" - "github.com/arduino/arduino-cli/legacy/builder/constants" - "github.com/arduino/arduino-cli/legacy/builder/types" - "github.com/stretchr/testify/require" -) - -func TestLoadPreviousBuildOptionsMap(t *testing.T) { - ctx := &types.Context{} - - buildPath := SetupBuildPath(t, ctx) - defer buildPath.RemoveAll() - - err := buildPath.Join(constants.BUILD_OPTIONS_FILE).WriteFile([]byte("test")) - require.NoError(t, err) - - buildOptionsJsonPrevious, err := builder.LoadPreviousBuildOptionsMap(ctx.BuildPath) - require.NoError(t, err) - - require.Equal(t, "test", buildOptionsJsonPrevious) -} - -func TestLoadPreviousBuildOptionsMapMissingFile(t *testing.T) { - ctx := &types.Context{} - - buildPath := SetupBuildPath(t, ctx) - defer buildPath.RemoveAll() - - buildOptionsJsonPrevious, err := builder.LoadPreviousBuildOptionsMap(ctx.BuildPath) - require.NoError(t, err) - require.Empty(t, buildOptionsJsonPrevious) -} diff --git a/legacy/builder/test/merge_sketch_with_bootloader_test.go b/legacy/builder/test/merge_sketch_with_bootloader_test.go index f1d9224b840..f7c9a24024f 100644 --- a/legacy/builder/test/merge_sketch_with_bootloader_test.go +++ b/legacy/builder/test/merge_sketch_with_bootloader_test.go @@ -21,9 +21,6 @@ import ( "strings" "testing" - "github.com/arduino/arduino-cli/arduino/builder/logger" - "github.com/arduino/arduino-cli/legacy/builder" - "github.com/arduino/arduino-cli/legacy/builder/constants" "github.com/arduino/arduino-cli/legacy/builder/types" paths "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" @@ -33,7 +30,7 @@ func TestMergeSketchWithBootloader(t *testing.T) { ctx := prepareBuilderTestContext(t, nil, paths.New("sketch1", "sketch1.ino"), "arduino:avr:uno") defer cleanUpBuilderTestContext(t, ctx) - buildPath := ctx.BuildPath + buildPath := ctx.Builder.GetBuildPath() err := buildPath.Join("sketch").MkdirAll() require.NoError(t, err) @@ -70,12 +67,7 @@ func TestMergeSketchWithBootloader(t *testing.T) { err = buildPath.Join("sketch", "sketch1.ino.hex").WriteFile([]byte(fakeSketchHex)) require.NoError(t, err) - builderLogger := logger.New(nil, nil, false, "") - err = builder.MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, - ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - builderLogger, - ) + err = ctx.Builder.MergeSketchWithBootloader() require.NoError(t, err) bytes, err := buildPath.Join("sketch", "sketch1.ino.with_bootloader.hex").ReadFile() @@ -90,7 +82,7 @@ func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) { ctx := prepareBuilderTestContext(t, nil, paths.New("sketch1", "sketch1.ino"), "arduino:avr:uno") defer cleanUpBuilderTestContext(t, ctx) - buildPath := ctx.BuildPath + buildPath := ctx.Builder.GetBuildPath() err := buildPath.Join("sketch").MkdirAll() require.NoError(t, err) @@ -127,12 +119,7 @@ func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) { err = buildPath.Join("sketch1.ino.hex").WriteFile([]byte(fakeSketchHex)) require.NoError(t, err) - builderLogger := logger.New(nil, nil, false, "") - err = builder.MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, - ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - builderLogger, - ) + err = ctx.Builder.MergeSketchWithBootloader() require.NoError(t, err) bytes, err := buildPath.Join("sketch1.ino.with_bootloader.hex").ReadFile() @@ -148,17 +135,12 @@ func TestMergeSketchWithBootloaderWhenNoBootloaderAvailable(t *testing.T) { ctx := prepareBuilderTestContext(t, nil, paths.New("sketch1", "sketch1.ino"), "arduino:avr:uno") defer cleanUpBuilderTestContext(t, ctx) - buildPath := ctx.BuildPath - buildProperties := ctx.BuildProperties - buildProperties.Remove(constants.BUILD_PROPERTIES_BOOTLOADER_NOBLINK) - buildProperties.Remove(constants.BUILD_PROPERTIES_BOOTLOADER_FILE) - - builderLogger := logger.New(nil, nil, false, "") - err := builder.MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, - ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - builderLogger, - ) + buildPath := ctx.Builder.GetBuildPath() + buildProperties := ctx.Builder.GetBuildProperties() + buildProperties.Remove("bootloader.noblink") + buildProperties.Remove("bootloader.file") + + err := ctx.Builder.MergeSketchWithBootloader() require.NoError(t, err) exist, err := buildPath.Join("sketch.ino.with_bootloader.hex").ExistCheck() @@ -166,6 +148,7 @@ func TestMergeSketchWithBootloaderWhenNoBootloaderAvailable(t *testing.T) { require.False(t, exist) } +// TODO convert in a compile test and we check against the real .hex func TestMergeSketchWithBootloaderPathIsParameterized(t *testing.T) { ctx := &types.Context{ HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware", "user_hardware"), @@ -176,7 +159,7 @@ func TestMergeSketchWithBootloaderPathIsParameterized(t *testing.T) { ctx = prepareBuilderTestContext(t, ctx, paths.New("sketch1", "sketch1.ino"), "my_avr_platform:avr:mymega:cpu=atmega2560") defer cleanUpBuilderTestContext(t, ctx) - buildPath := ctx.BuildPath + buildPath := ctx.Builder.GetBuildPath() err := buildPath.Join("sketch").MkdirAll() require.NoError(t, err) @@ -213,12 +196,7 @@ func TestMergeSketchWithBootloaderPathIsParameterized(t *testing.T) { err = buildPath.Join("sketch", "sketch1.ino.hex").WriteFile([]byte(fakeSketchHex)) require.NoError(t, err) - builderLogger := logger.New(nil, nil, false, "") - err = builder.MergeSketchWithBootloader( - ctx.OnlyUpdateCompilationDatabase, - ctx.BuildPath, ctx.Builder.Sketch(), ctx.BuildProperties, - builderLogger, - ) + err = ctx.Builder.MergeSketchWithBootloader() require.NoError(t, err) bytes, err := buildPath.Join("sketch", "sketch1.ino.with_bootloader.hex").ReadFile() diff --git a/legacy/builder/test/setup_build_properties_test.go b/legacy/builder/test/setup_build_properties_test.go index 9b8d7236a31..68aaa6b0574 100644 --- a/legacy/builder/test/setup_build_properties_test.go +++ b/legacy/builder/test/setup_build_properties_test.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/require" ) +// TODO maybe create a test that actually check all the keys func TestSetupBuildProperties(t *testing.T) { ctx := &types.Context{ HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware", "user_hardware"), @@ -33,7 +34,7 @@ func TestSetupBuildProperties(t *testing.T) { ctx = prepareBuilderTestContext(t, ctx, paths.New("sketch1", "sketch1.ino"), "arduino:avr:uno") defer cleanUpBuilderTestContext(t, ctx) - buildProperties := ctx.BuildProperties + buildProperties := ctx.Builder.GetBuildProperties() require.Equal(t, "ARDUINO", buildProperties.Get("software")) @@ -71,19 +72,19 @@ func TestSetupBuildProperties(t *testing.T) { require.True(t, buildProperties.ContainsKey("extra.time.dst")) } +// TODO make this integration tests func TestSetupBuildPropertiesWithSomeCustomOverrides(t *testing.T) { ctx := &types.Context{ - HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware"), - BuiltInToolsDirs: paths.NewPathList("downloaded_tools", "tools_builtin"), - CustomBuildProperties: []string{"name=fake name", "tools.avrdude.config.path=non existent path with space and a ="}, + HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware"), + BuiltInToolsDirs: paths.NewPathList("downloaded_tools", "tools_builtin"), } ctx = prepareBuilderTestContext(t, ctx, paths.New("sketch1", "sketch1.ino"), "arduino:avr:uno") defer cleanUpBuilderTestContext(t, ctx) - customProps, err := properties.LoadFromSlice(ctx.CustomBuildProperties) + customBuildProp := []string{"name=fake name", "tools.avrdude.config.path=non existent path with space and a ="} + customProps, err := properties.LoadFromSlice(customBuildProp) require.NoError(t, err) - ctx.BuildProperties.Merge(customProps) - buildProperties := ctx.BuildProperties + buildProperties := ctx.Builder.GetBuildProperties().Merge(customProps) require.Equal(t, "ARDUINO", buildProperties.Get("software")) require.Equal(t, "uno", buildProperties.Get("_id")) require.Equal(t, "fake name", buildProperties.Get("name")) @@ -91,6 +92,7 @@ func TestSetupBuildPropertiesWithSomeCustomOverrides(t *testing.T) { require.Equal(t, "non existent path with space and a =", buildProperties.Get("tools.avrdude.config.path")) } +// TODO go to compile_4 that uses the custom_yum to compile and we also verify this properties func TestSetupBuildPropertiesUserHardware(t *testing.T) { ctx := &types.Context{ HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware", "user_hardware"), @@ -99,7 +101,7 @@ func TestSetupBuildPropertiesUserHardware(t *testing.T) { ctx = prepareBuilderTestContext(t, ctx, paths.New("sketch1", "sketch1.ino"), "my_avr_platform:avr:custom_yun") defer cleanUpBuilderTestContext(t, ctx) - buildProperties := ctx.BuildProperties + buildProperties := ctx.Builder.GetBuildProperties() require.Equal(t, "ARDUINO", buildProperties.Get("software")) @@ -117,7 +119,7 @@ func TestSetupBuildPropertiesWithMissingPropsFromParentPlatformTxtFiles(t *testi ctx = prepareBuilderTestContext(t, ctx, paths.New("sketch1", "sketch1.ino"), "my_avr_platform:avr:custom_yun") defer cleanUpBuilderTestContext(t, ctx) - buildProperties := ctx.BuildProperties + buildProperties := ctx.Builder.GetBuildProperties() require.Equal(t, "ARDUINO", buildProperties.Get("software")) diff --git a/legacy/builder/test/store_build_options_map_test.go b/legacy/builder/test/store_build_options_map_test.go index c9782e4dc40..ad087a0c48b 100644 --- a/legacy/builder/test/store_build_options_map_test.go +++ b/legacy/builder/test/store_build_options_map_test.go @@ -18,45 +18,42 @@ package test import ( "testing" + "github.com/arduino/arduino-cli/arduino/builder" "github.com/arduino/arduino-cli/arduino/sketch" - "github.com/arduino/arduino-cli/legacy/builder" - "github.com/arduino/arduino-cli/legacy/builder/constants" - "github.com/arduino/arduino-cli/legacy/builder/types" paths "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/stretchr/testify/require" ) -func TestStoreBuildOptionsMap(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList("hardware"), - BuiltInToolsDirs: paths.NewPathList("tools"), - BuiltInLibrariesDirs: paths.New("built-in libraries"), - OtherLibrariesDirs: paths.NewPathList("libraries"), - FQBN: parseFQBN(t, "my:nice:fqbn"), - CustomBuildProperties: []string{"custom=prop"}, - BuildProperties: properties.NewFromHashmap(map[string]string{"compiler.optimization_flags": "-Os"}), - } +func TestCheckIfBuildOptionsChanged(t *testing.T) { + hardwareDirs := paths.NewPathList("hardware") + builtInToolsDirs := paths.NewPathList("tools") + builtInLibrariesDirs := paths.New("built-in libraries") + otherLibrariesDirs := paths.NewPathList("libraries") + fqbn := parseFQBN(t, "my:nice:fqbn") - buildPath := SetupBuildPath(t, ctx) + buildPath := SetupBuildPath(t) defer buildPath.RemoveAll() - buildPropertiesJSON, err := builder.CreateBuildOptionsMap( - ctx.HardwareDirs, ctx.BuiltInToolsDirs, ctx.OtherLibrariesDirs, - ctx.BuiltInLibrariesDirs, &sketch.Sketch{FullPath: paths.New("sketchLocation")}, ctx.CustomBuildProperties, - ctx.FQBN.String(), ctx.BuildProperties.Get("compiler.optimization_flags"), + buildProperties := properties.NewFromHashmap(map[string]string{"compiler.optimization_flags": "-Os"}) + buildOptionsManager := builder.NewBuildOptionsManager( + hardwareDirs, builtInToolsDirs, otherLibrariesDirs, + builtInLibrariesDirs, buildPath, &sketch.Sketch{FullPath: paths.New("sketchLocation")}, []string{"custom=prop"}, + fqbn, false, + buildProperties.Get("compiler.optimization_flags"), + buildProperties.GetPath("runtime.platform.path"), + buildProperties.GetPath("build.core.path"), + nil, ) - require.NoError(t, err) - ctx.BuildOptionsJson = buildPropertiesJSON - err = builder.StoreBuildOptionsMap(ctx.BuildPath, ctx.BuildOptionsJson) + err := buildOptionsManager.WipeBuildPath() require.NoError(t, err) - exist, err := buildPath.Join(constants.BUILD_OPTIONS_FILE).ExistCheck() + exist, err := buildPath.Join("build.options.json").ExistCheck() require.NoError(t, err) require.True(t, exist) - bytes, err := buildPath.Join(constants.BUILD_OPTIONS_FILE).ReadFile() + bytes, err := buildPath.Join("build.options.json").ReadFile() require.NoError(t, err) require.Equal(t, `{ @@ -71,3 +68,64 @@ func TestStoreBuildOptionsMap(t *testing.T) { "sketchLocation": "sketchLocation" }`, string(bytes)) } + +//func TestWipeoutBuildPathIfBuildOptionsChanged(t *testing.T) { +// buildPath := SetupBuildPath(t) +// defer buildPath.RemoveAll() +// +// buildOptionsJsonPrevious := "{ \"old\":\"old\" }" +// buildOptionsJson := "{ \"new\":\"new\" }" +// +// buildPath.Join("should_be_deleted.txt").Truncate() +// +// _, err := builder.WipeoutBuildPathIfBuildOptionsChanged( +// false, +// buildPath, +// buildOptionsJson, +// buildOptionsJsonPrevious, +// nil, +// ) +// require.NoError(t, err) +// +// exist, err := buildPath.ExistCheck() +// require.NoError(t, err) +// require.True(t, exist) +// +// files, err := buildPath.ReadDir() +// require.NoError(t, err) +// require.Equal(t, 0, len(files)) +// +// exist, err = buildPath.Join("should_be_deleted.txt").ExistCheck() +// require.NoError(t, err) +// require.False(t, exist) +//} +// +//func TestWipeoutBuildPathIfBuildOptionsChangedNoPreviousBuildOptions(t *testing.T) { +// buildPath := SetupBuildPath(t) +// defer buildPath.RemoveAll() +// +// buildOptionsJson := "{ \"new\":\"new\" }" +// +// require.NoError(t, buildPath.Join("should_not_be_deleted.txt").Truncate()) +// +// _, err := builder.WipeoutBuildPathIfBuildOptionsChanged( +// false, +// buildPath, +// buildOptionsJson, +// "", +// nil, +// ) +// require.NoError(t, err) +// +// exist, err := buildPath.ExistCheck() +// require.NoError(t, err) +// require.True(t, exist) +// +// files, err := buildPath.ReadDir() +// require.NoError(t, err) +// require.Equal(t, 1, len(files)) +// +// exist, err = buildPath.Join("should_not_be_deleted.txt").ExistCheck() +// require.NoError(t, err) +// require.True(t, exist) +//} diff --git a/legacy/builder/test/tools_loader_test.go b/legacy/builder/test/tools_loader_test.go index e28f828401d..3460ac82c76 100644 --- a/legacy/builder/test/tools_loader_test.go +++ b/legacy/builder/test/tools_loader_test.go @@ -16,35 +16,12 @@ package test import ( - "path/filepath" - "sort" "testing" - "github.com/arduino/arduino-cli/arduino/cores" - "github.com/arduino/arduino-cli/arduino/cores/packagemanager" - "github.com/arduino/arduino-cli/legacy/builder/types" paths "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" ) -type ByToolIDAndVersion []*cores.ToolRelease - -func (s ByToolIDAndVersion) Len() int { - return len(s) -} -func (s ByToolIDAndVersion) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} -func (s ByToolIDAndVersion) Less(i, j int) bool { - if s[i].Tool.Name != s[j].Tool.Name { - return s[i].Tool.Name < s[j].Tool.Name - } - if !s[i].Version.Equal(s[j].Version) { - return s[i].Version.LessThan(s[j].Version) - } - return s[i].InstallDir.String() < s[j].InstallDir.String() -} - func requireEquivalentPaths(t *testing.T, actual string, expected ...string) { if len(expected) == 1 { actualAbs, err := paths.New(actual).Abs() @@ -60,134 +37,3 @@ func requireEquivalentPaths(t *testing.T, actual string, expected ...string) { require.Contains(t, expectedAbs.AsStrings(), actualAbs.String()) } } - -func TestLoadTools(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList(filepath.Join("..", "hardware"), "downloaded_hardware"), - BuiltInToolsDirs: paths.NewPathList("downloaded_tools", "tools_builtin"), - } - ctx = prepareBuilderTestContext(t, ctx, nil, "", skipLibraries) - defer cleanUpBuilderTestContext(t, ctx) - - tools := ctx.PackageManager.GetAllInstalledToolsReleases() - require.Equal(t, 9, len(tools)) - - sort.Sort(ByToolIDAndVersion(tools)) - - idx := 0 - require.Equal(t, ":arduino-preprocessor@0.1.5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/arduino-preprocessor/0.1.5") - idx++ - require.Equal(t, ":arm-none-eabi-gcc@4.8.3-2014q1", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/arm-none-eabi-gcc/4.8.3-2014q1") - idx++ - require.Equal(t, ":avr-gcc@4.8.1-arduino5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/avr-gcc/4.8.1-arduino5") - idx++ - require.Equal(t, "arduino:avr-gcc@4.8.1-arduino5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "tools_builtin/avr") - idx++ - require.Equal(t, ":avrdude@6.0.1-arduino5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/avrdude/6.0.1-arduino5") - idx++ - require.Equal(t, "arduino:avrdude@6.0.1-arduino5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "tools_builtin/avr") - idx++ - require.Equal(t, ":bossac@1.5-arduino", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/bossac/1.5-arduino") - idx++ - require.Equal(t, ":bossac@1.6.1-arduino", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/bossac/1.6.1-arduino") - idx++ - require.Equal(t, ":ctags@5.8-arduino11", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/ctags/5.8-arduino11") -} - -func TestLoadToolsWithBoardManagerFolderStructure(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList("downloaded_board_manager_stuff"), - } - ctx = prepareBuilderTestContext(t, ctx, nil, "", skipLibraries) - defer cleanUpBuilderTestContext(t, ctx) - - tools := ctx.PackageManager.GetAllInstalledToolsReleases() - require.Equal(t, 3, len(tools)) - - sort.Sort(ByToolIDAndVersion(tools)) - - idx := 0 - require.Equal(t, "arduino:CMSIS@4.0.0-atmel", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_board_manager_stuff/arduino/tools/CMSIS/4.0.0-atmel") - idx++ - require.Equal(t, "RFduino:arm-none-eabi-gcc@4.8.3-2014q1", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_board_manager_stuff/RFduino/tools/arm-none-eabi-gcc/4.8.3-2014q1") - idx++ - require.Equal(t, "arduino:openocd@0.9.0-arduino", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_board_manager_stuff/arduino/tools/openocd/0.9.0-arduino") -} - -func TestLoadLotsOfTools(t *testing.T) { - ctx := &types.Context{ - HardwareDirs: paths.NewPathList("downloaded_board_manager_stuff"), - BuiltInToolsDirs: paths.NewPathList("downloaded_tools", "tools_builtin"), - } - ctx = prepareBuilderTestContext(t, ctx, nil, "", skipLibraries) - defer cleanUpBuilderTestContext(t, ctx) - - tools := ctx.PackageManager.GetAllInstalledToolsReleases() - require.Equal(t, 12, len(tools)) - - sort.Sort(ByToolIDAndVersion(tools)) - - idx := 0 - require.Equal(t, "arduino:CMSIS@4.0.0-atmel", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_board_manager_stuff/arduino/tools/CMSIS/4.0.0-atmel") - idx++ - require.Equal(t, ":arduino-preprocessor@0.1.5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/arduino-preprocessor/0.1.5") - idx++ - require.Equal(t, "RFduino:arm-none-eabi-gcc@4.8.3-2014q1", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_board_manager_stuff/RFduino/tools/arm-none-eabi-gcc/4.8.3-2014q1") - idx++ - require.Equal(t, ":arm-none-eabi-gcc@4.8.3-2014q1", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/arm-none-eabi-gcc/4.8.3-2014q1") - idx++ - require.Equal(t, ":avr-gcc@4.8.1-arduino5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/avr-gcc/4.8.1-arduino5") - idx++ - require.Equal(t, "arduino:avr-gcc@4.8.1-arduino5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "tools_builtin/avr") - idx++ - require.Equal(t, ":avrdude@6.0.1-arduino5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/avrdude/6.0.1-arduino5") - idx++ - require.Equal(t, "arduino:avrdude@6.0.1-arduino5", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "tools_builtin/avr") - idx++ - require.Equal(t, ":bossac@1.5-arduino", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/bossac/1.5-arduino") - idx++ - require.Equal(t, ":bossac@1.6.1-arduino", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), tools[idx].InstallDir.String(), "downloaded_tools/bossac/1.6.1-arduino") - idx++ - require.Equal(t, ":ctags@5.8-arduino11", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_tools/ctags/5.8-arduino11") - idx++ - require.Equal(t, "arduino:openocd@0.9.0-arduino", tools[idx].String()) - requireEquivalentPaths(t, tools[idx].InstallDir.String(), "downloaded_board_manager_stuff/arduino/tools/openocd/0.9.0-arduino") -} - -func TestAllToolsContextIsPopulated(t *testing.T) { - pmb := packagemanager.NewBuilder(nil, nil, nil, nil, "") - pmb.LoadHardwareFromDirectories(paths.NewPathList("downloaded_board_manager_stuff")) - pmb.LoadToolsFromBundleDirectory(paths.New("downloaded_tools", "tools_builtin")) - pm := pmb.Build() - pme, release := pm.NewExplorer() - defer release() - - ctx := &types.Context{ - PackageManager: pme, - } - - require.NotEmpty(t, ctx.PackageManager.GetAllInstalledToolsReleases()) -} diff --git a/legacy/builder/test/try_build_of_problematic_sketch_test.go b/legacy/builder/test/try_build_of_problematic_sketch_test.go index ab40de05714..6504bcd9b84 100644 --- a/legacy/builder/test/try_build_of_problematic_sketch_test.go +++ b/legacy/builder/test/try_build_of_problematic_sketch_test.go @@ -27,11 +27,7 @@ import ( "github.com/stretchr/testify/require" ) -// This is a sketch that fails to build on purpose -//func TestTryBuild016(t *testing.T) { -// tryBuild(t, paths.New("sketch_that_checks_if_SPI_has_transactions_and_includes_missing_Ethernet", "sketch.ino")) -//} - +// TODO add them in the compile_4 func TestTryBuild033(t *testing.T) { tryBuild(t, paths.New("sketch_that_includes_arduino_h", "sketch_that_includes_arduino_h.ino")) } diff --git a/legacy/builder/test/unused_compiled_libraries_remover_test.go b/legacy/builder/test/unused_compiled_libraries_remover_test.go deleted file mode 100644 index 6e7ab70df1b..00000000000 --- a/legacy/builder/test/unused_compiled_libraries_remover_test.go +++ /dev/null @@ -1,108 +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 test - -import ( - "testing" - - "github.com/arduino/arduino-cli/arduino/builder/detector" - "github.com/arduino/arduino-cli/arduino/builder/logger" - "github.com/arduino/arduino-cli/arduino/libraries" - "github.com/arduino/arduino-cli/legacy/builder" - "github.com/arduino/arduino-cli/legacy/builder/types" - paths "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" -) - -func TestUnusedCompiledLibrariesRemover(t *testing.T) { - temp, err := paths.MkTempDir("", "test") - require.NoError(t, err) - defer temp.RemoveAll() - - require.NoError(t, temp.Join("SPI").MkdirAll()) - require.NoError(t, temp.Join("Bridge").MkdirAll()) - require.NoError(t, temp.Join("dummy_file").WriteFile([]byte{})) - - ctx := &types.Context{} - ctx.LibrariesBuildPath = temp - ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( - nil, nil, false, false, logger.New(nil, nil, false, ""), - ) - ctx.SketchLibrariesDetector.AppendImportedLibraries(&libraries.Library{Name: "Bridge"}) - - err = builder.UnusedCompiledLibrariesRemover( - ctx.LibrariesBuildPath, - ctx.SketchLibrariesDetector.ImportedLibraries(), - ) - require.NoError(t, err) - - exist, err := temp.Join("SPI").ExistCheck() - require.NoError(t, err) - require.False(t, exist) - exist, err = temp.Join("Bridge").ExistCheck() - require.NoError(t, err) - require.True(t, exist) - exist, err = temp.Join("dummy_file").ExistCheck() - require.NoError(t, err) - require.True(t, exist) -} - -func TestUnusedCompiledLibrariesRemoverLibDoesNotExist(t *testing.T) { - ctx := &types.Context{} - ctx.LibrariesBuildPath = paths.TempDir().Join("test") - ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( - nil, nil, false, false, logger.New(nil, nil, false, ""), - ) - ctx.SketchLibrariesDetector.AppendImportedLibraries(&libraries.Library{Name: "Bridge"}) - - err := builder.UnusedCompiledLibrariesRemover( - ctx.LibrariesBuildPath, - ctx.SketchLibrariesDetector.ImportedLibraries(), - ) - require.NoError(t, err) -} - -func TestUnusedCompiledLibrariesRemoverNoUsedLibraries(t *testing.T) { - temp, err := paths.MkTempDir("", "test") - require.NoError(t, err) - defer temp.RemoveAll() - - require.NoError(t, temp.Join("SPI").MkdirAll()) - require.NoError(t, temp.Join("Bridge").MkdirAll()) - require.NoError(t, temp.Join("dummy_file").WriteFile([]byte{})) - - ctx := &types.Context{} - ctx.SketchLibrariesDetector = detector.NewSketchLibrariesDetector( - nil, nil, false, false, logger.New(nil, nil, false, ""), - ) - ctx.LibrariesBuildPath = temp - - err = builder.UnusedCompiledLibrariesRemover( - ctx.LibrariesBuildPath, - ctx.SketchLibrariesDetector.ImportedLibraries(), - ) - require.NoError(t, err) - - exist, err := temp.Join("SPI").ExistCheck() - require.NoError(t, err) - require.False(t, exist) - exist, err = temp.Join("Bridge").ExistCheck() - require.NoError(t, err) - require.False(t, exist) - exist, err = temp.Join("dummy_file").ExistCheck() - require.NoError(t, err) - require.True(t, exist) -} diff --git a/legacy/builder/test/wipeout_build_path_if_build_options_changed_test.go b/legacy/builder/test/wipeout_build_path_if_build_options_changed_test.go deleted file mode 100644 index 7df448e9b54..00000000000 --- a/legacy/builder/test/wipeout_build_path_if_build_options_changed_test.go +++ /dev/null @@ -1,89 +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 test - -import ( - "testing" - - "github.com/arduino/arduino-cli/legacy/builder" - "github.com/arduino/arduino-cli/legacy/builder/types" - "github.com/stretchr/testify/require" -) - -func TestWipeoutBuildPathIfBuildOptionsChanged(t *testing.T) { - ctx := &types.Context{} - - buildPath := SetupBuildPath(t, ctx) - defer buildPath.RemoveAll() - - ctx.BuildOptionsJsonPrevious = "{ \"old\":\"old\" }" - ctx.BuildOptionsJson = "{ \"new\":\"new\" }" - - buildPath.Join("should_be_deleted.txt").Truncate() - - _, err := builder.WipeoutBuildPathIfBuildOptionsChanged( - ctx.Clean, - ctx.BuildPath, - ctx.BuildOptionsJson, - ctx.BuildOptionsJsonPrevious, - ctx.BuildProperties, - ) - require.NoError(t, err) - - exist, err := buildPath.ExistCheck() - require.NoError(t, err) - require.True(t, exist) - - files, err := buildPath.ReadDir() - require.NoError(t, err) - require.Equal(t, 0, len(files)) - - exist, err = buildPath.Join("should_be_deleted.txt").ExistCheck() - require.NoError(t, err) - require.False(t, exist) -} - -func TestWipeoutBuildPathIfBuildOptionsChangedNoPreviousBuildOptions(t *testing.T) { - ctx := &types.Context{} - - buildPath := SetupBuildPath(t, ctx) - defer buildPath.RemoveAll() - - ctx.BuildOptionsJson = "{ \"new\":\"new\" }" - - require.NoError(t, buildPath.Join("should_not_be_deleted.txt").Truncate()) - - _, err := builder.WipeoutBuildPathIfBuildOptionsChanged( - ctx.Clean, - ctx.BuildPath, - ctx.BuildOptionsJson, - ctx.BuildOptionsJsonPrevious, - ctx.BuildProperties, - ) - require.NoError(t, err) - - exist, err := buildPath.ExistCheck() - require.NoError(t, err) - require.True(t, exist) - - files, err := buildPath.ReadDir() - require.NoError(t, err) - require.Equal(t, 1, len(files)) - - exist, err = buildPath.Join("should_not_be_deleted.txt").ExistCheck() - require.NoError(t, err) - require.True(t, exist) -} diff --git a/legacy/builder/types/context.go b/legacy/builder/types/context.go index 61eff082d7a..e720af613d1 100644 --- a/legacy/builder/types/context.go +++ b/legacy/builder/types/context.go @@ -17,16 +17,10 @@ package types import ( "github.com/arduino/arduino-cli/arduino/builder" - "github.com/arduino/arduino-cli/arduino/builder/compilation" "github.com/arduino/arduino-cli/arduino/builder/detector" "github.com/arduino/arduino-cli/arduino/builder/logger" - "github.com/arduino/arduino-cli/arduino/builder/progress" - "github.com/arduino/arduino-cli/arduino/builder/sizer" - "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" - rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" - properties "github.com/arduino/go-properties-orderedmap" ) // Context structure @@ -35,65 +29,10 @@ type Context struct { SketchLibrariesDetector *detector.SketchLibrariesDetector BuilderLogger *logger.BuilderLogger - // Build options + // Used only by legacy tests HardwareDirs paths.PathList BuiltInToolsDirs paths.PathList BuiltInLibrariesDirs *paths.Path OtherLibrariesDirs paths.PathList - FQBN *cores.FQBN - Clean bool - - // Build options are serialized here - BuildOptionsJson string - BuildOptionsJsonPrevious string - - PackageManager *packagemanager.Explorer - RequiredTools []*cores.ToolRelease - TargetBoard *cores.Board - TargetPackage *cores.Package - TargetPlatform *cores.PlatformRelease - ActualPlatform *cores.PlatformRelease - - BuildProperties *properties.Map - BuildPath *paths.Path - SketchBuildPath *paths.Path - CoreBuildPath *paths.Path - CoreArchiveFilePath *paths.Path - CoreObjectsFiles paths.PathList - LibrariesBuildPath *paths.Path - LibrariesObjectFiles paths.PathList - SketchObjectFiles paths.PathList - - // C++ Parsing - LineOffset int - - // Dry run, only create progress map - Progress progress.Struct - // Send progress events to this callback - ProgressCB rpc.TaskProgressCB - - // Custom build properties defined by user (line by line as "key=value" pairs) - CustomBuildProperties []string - - // Sizer results - ExecutableSectionsSize sizer.ExecutablesFileSections - - // Compilation Database to build/update - CompilationDatabase *compilation.Database - // Set to true to skip build and produce only Compilation Database - OnlyUpdateCompilationDatabase bool - - // Source code overrides (filename -> content map). - // The provided source data is used instead of reading it from disk. - // The keys of the map are paths relative to sketch folder. - SourceOverride map[string]string -} - -func (ctx *Context) PushProgress() { - if ctx.ProgressCB != nil { - ctx.ProgressCB(&rpc.TaskProgress{ - Percent: ctx.Progress.Progress, - Completed: ctx.Progress.Progress >= 100.0, - }) - } + PackageManager *packagemanager.Explorer } diff --git a/legacy/builder/unused_compiled_libraries_remover.go b/legacy/builder/unused_compiled_libraries_remover.go deleted file mode 100644 index cea88bd9db6..00000000000 --- a/legacy/builder/unused_compiled_libraries_remover.go +++ /dev/null @@ -1,55 +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 ( - "github.com/arduino/arduino-cli/arduino/libraries" - "github.com/arduino/go-paths-helper" - "github.com/pkg/errors" - "golang.org/x/exp/slices" -) - -func UnusedCompiledLibrariesRemover(librariesBuildPath *paths.Path, importedLibraries libraries.List) error { - if librariesBuildPath.NotExist() { - return nil - } - - files, err := librariesBuildPath.ReadDir() - if err != nil { - return errors.WithStack(err) - } - - libraryNames := toLibraryNames(importedLibraries) - for _, file := range files { - if file.IsDir() { - if !slices.Contains(libraryNames, file.Base()) { - if err := file.RemoveAll(); err != nil { - return errors.WithStack(err) - } - } - } - } - - return nil -} - -func toLibraryNames(libraries []*libraries.Library) []string { - libraryNames := []string{} - for _, library := range libraries { - libraryNames = append(libraryNames, library.Name) - } - return libraryNames -} diff --git a/legacy/builder/warn_about_arch_incompatible_libraries.go b/legacy/builder/warn_about_arch_incompatible_libraries.go deleted file mode 100644 index ea7392560bc..00000000000 --- a/legacy/builder/warn_about_arch_incompatible_libraries.go +++ /dev/null @@ -1,45 +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 ( - "strings" - - "github.com/arduino/arduino-cli/arduino/cores" - "github.com/arduino/arduino-cli/arduino/libraries" -) - -func WarnAboutArchIncompatibleLibraries( - targetPlatform *cores.PlatformRelease, - overrides string, - importedLibraries libraries.List, - printInfoFn func(string), -) { - archs := []string{targetPlatform.Platform.Architecture} - if overrides != "" { - archs = append(archs, strings.Split(overrides, ",")...) - } - - for _, importedLibrary := range importedLibraries { - if !importedLibrary.SupportsAnyArchitectureIn(archs...) { - printInfoFn( - tr("WARNING: library %[1]s claims to run on %[2]s architecture(s) and may be incompatible with your current board which runs on %[3]s architecture(s).", - importedLibrary.Name, - strings.Join(importedLibrary.Architectures, ", "), - strings.Join(archs, ", "))) - } - } -} diff --git a/legacy/builder/wipeout_build_path_if_build_options_changed.go b/legacy/builder/wipeout_build_path_if_build_options_changed.go deleted file mode 100644 index 108664978ca..00000000000 --- a/legacy/builder/wipeout_build_path_if_build_options_changed.go +++ /dev/null @@ -1,94 +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 ( - "encoding/json" - "path/filepath" - - "github.com/arduino/arduino-cli/arduino/builder/utils" - "github.com/arduino/arduino-cli/legacy/builder/constants" - "github.com/arduino/go-paths-helper" - properties "github.com/arduino/go-properties-orderedmap" - "github.com/pkg/errors" -) - -func WipeoutBuildPathIfBuildOptionsChanged( - clean bool, - buildPath *paths.Path, - buildOptionsJson, buildOptionsJsonPrevious string, - buildProperties *properties.Map, -) (string, error) { - if clean { - return "", doCleanup(buildPath) - } - if buildOptionsJsonPrevious == "" { - return "", nil - } - - var opts *properties.Map - if err := json.Unmarshal([]byte(buildOptionsJson), &opts); err != nil || opts == nil { - panic(constants.BUILD_OPTIONS_FILE + " is invalid") - } - - var prevOpts *properties.Map - if err := json.Unmarshal([]byte(buildOptionsJsonPrevious), &prevOpts); err != nil || prevOpts == nil { - return tr("%[1]s invalid, rebuilding all", constants.BUILD_OPTIONS_FILE), doCleanup(buildPath) - } - - // If SketchLocation path is different but filename is the same, consider it equal - if filepath.Base(opts.Get("sketchLocation")) == filepath.Base(prevOpts.Get("sketchLocation")) { - opts.Remove("sketchLocation") - prevOpts.Remove("sketchLocation") - } - - // If options are not changed check if core has - if opts.Equals(prevOpts) { - // check if any of the files contained in the core folders has changed - // since the json was generated - like platform.txt or similar - // if so, trigger a "safety" wipe - targetCoreFolder := buildProperties.GetPath("runtime.platform.path") - coreFolder := buildProperties.GetPath("build.core.path") - realCoreFolder := coreFolder.Parent().Parent() - jsonPath := buildPath.Join(constants.BUILD_OPTIONS_FILE) - coreUnchanged, _ := utils.DirContentIsOlderThan(realCoreFolder, jsonPath, ".txt") - if coreUnchanged && targetCoreFolder != nil && !realCoreFolder.EqualsTo(targetCoreFolder) { - coreUnchanged, _ = utils.DirContentIsOlderThan(targetCoreFolder, jsonPath, ".txt") - } - if coreUnchanged { - return "", nil - } - } - - return "", doCleanup(buildPath) -} - -func doCleanup(buildPath *paths.Path) error { - // FIXME: this should go outside legacy and behind a `logrus` call so users can - // control when this should be printed. - // logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_BUILD_OPTIONS_CHANGED + constants.MSG_REBUILD_ALL) - - if files, err := buildPath.ReadDir(); err != nil { - return errors.WithMessage(err, tr("cleaning build path")) - } else { - for _, file := range files { - if err := file.RemoveAll(); err != nil { - return errors.WithMessage(err, tr("cleaning build path")) - } - } - } - return nil -}