Skip to content

Commit

Permalink
move coreBuildCachePath in the arduino Builder
Browse files Browse the repository at this point in the history
  • Loading branch information
alessio-perugini committed Sep 6, 2023
1 parent b73a681 commit 22449c9
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 82 deletions.
13 changes: 10 additions & 3 deletions arduino/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@

package builder

import "github.com/arduino/arduino-cli/arduino/sketch"
import (
"github.com/arduino/arduino-cli/arduino/sketch"
"github.com/arduino/go-paths-helper"
)

// nolint
const (
Expand All @@ -31,11 +34,15 @@ const (
// Builder is a Sketch builder.
type Builder struct {
sketch *sketch.Sketch

// core related
coreBuildCachePath *paths.Path
}

// NewBuilder creates a sketch Builder.
func NewBuilder(sk *sketch.Sketch) *Builder {
func NewBuilder(sk *sketch.Sketch, coreBuildCachePath *paths.Path) *Builder {
return &Builder{
sketch: sk,
sketch: sk,
coreBuildCachePath: coreBuildCachePath,
}
}
7 changes: 7 additions & 0 deletions arduino/builder/core.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package builder

import "github.com/arduino/go-paths-helper"

func (b *Builder) CoreBuildCachePath() *paths.Path {

Check failure on line 5 in arduino/builder/core.go

View workflow job for this annotation

GitHub Actions / check-style (./)

exported method Builder.CoreBuildCachePath should have comment or be unexported

Check failure on line 5 in arduino/builder/core.go

View workflow job for this annotation

GitHub Actions / check-style (./)

exported method Builder.CoreBuildCachePath should have comment or be unexported
return b.coreBuildCachePath
}
29 changes: 15 additions & 14 deletions commands/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,21 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream
// cache is purged after compilation to not remove entries that might be required
defer maybePurgeBuildCache()

sketchBuilder := bldr.NewBuilder(sk)
var coreBuildCachePath *paths.Path
if req.GetBuildCachePath() == "" {
coreBuildCachePath = paths.TempDir().Join("arduino", "cores")
} else {
buildCachePath, err := paths.New(req.GetBuildCachePath()).Abs()
if err != nil {
return nil, &arduino.PermissionDeniedError{Message: tr("Cannot create build cache directory"), Cause: err}
}
if err := buildCachePath.MkdirAll(); err != nil {
return nil, &arduino.PermissionDeniedError{Message: tr("Cannot create build cache directory"), Cause: err}
}
coreBuildCachePath = buildCachePath.Join("core")
}

sketchBuilder := bldr.NewBuilder(sk, coreBuildCachePath)

// Add build properites related to sketch data
buildProperties = sketchBuilder.SetupBuildProperties(buildProperties, buildPath, req.GetOptimizeForDebug())
Expand Down Expand Up @@ -206,19 +220,6 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream
builderCtx.WarningsLevel = builder.DEFAULT_WARNINGS_LEVEL
}

if req.GetBuildCachePath() == "" {
builderCtx.CoreBuildCachePath = paths.TempDir().Join("arduino", "cores")
} else {
buildCachePath, err := paths.New(req.GetBuildCachePath()).Abs()
if err != nil {
return nil, &arduino.PermissionDeniedError{Message: tr("Cannot create build cache directory"), Cause: err}
}
if err := buildCachePath.MkdirAll(); err != nil {
return nil, &arduino.PermissionDeniedError{Message: tr("Cannot create build cache directory"), Cause: err}
}
builderCtx.CoreBuildCachePath = buildCachePath.Join("core")
}

builderCtx.BuiltInLibrariesDirs = configuration.IDEBuiltinLibrariesDir(configuration.Settings)

builderCtx.Stdout = outStream
Expand Down
53 changes: 53 additions & 0 deletions internal/integrationtest/compile_4/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strings"
"testing"
"text/template"
"time"

"github.com/arduino/arduino-cli/arduino/builder/cpp"
"github.com/arduino/arduino-cli/internal/integrationtest"
Expand Down Expand Up @@ -710,3 +711,55 @@ func comparePreprocessGoldenFile(t *testing.T, sketchDir *paths.Path, preprocess

require.Equal(t, buf.String(), strings.Replace(preprocessedSketch, "\r\n", "\n", -1))
}

func TestCoreCaching(t *testing.T) {
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
defer env.CleanUp()

sketchPath, err := paths.New("..", "testdata", "bare_minimum").Abs()
require.NoError(t, err)

// Install Arduino AVR Boards
_, _, err = cli.Run("core", "install", "arduino:[email protected]")
require.NoError(t, err)

// Create temporary cache dir
buildCachePath, err := paths.MkTempDir("", "test_build_cache")
require.NoError(t, err)
defer buildCachePath.RemoveAll()

// Build first time
_, _, err = cli.Run("compile", "-b", "arduino:avr:uno", "--build-cache-path", buildCachePath.String(), sketchPath.String())
require.NoError(t, err)

// Find cached core and save timestamp
pathList, err := buildCachePath.ReadDirRecursiveFiltered(nil, paths.FilterPrefixes("core.a"))
require.NoError(t, err)
require.Len(t, pathList, 1)
cachedCoreFile := pathList[0]
lastUsedPath := cachedCoreFile.Parent().Join(".last-used")
require.True(t, lastUsedPath.Exist())
coreStatBefore, err := cachedCoreFile.Stat()
require.NoError(t, err)

// Run build again and check timestamp is unchanged
_, _, err = cli.Run("compile", "-b", "arduino:avr:uno", "--build-cache-path", buildCachePath.String(), sketchPath.String())
require.NoError(t, err)
coreStatAfterRebuild, err := cachedCoreFile.Stat()
require.NoError(t, err)
require.Equal(t, coreStatBefore.ModTime(), coreStatAfterRebuild.ModTime())

// Touch a file of the core and check if the builder invalidate the cache
time.Sleep(time.Second)
now := time.Now().Local()
coreFolder := cli.DataDir().Join("packages", "arduino", "hardware", "avr", "1.8.6")
err = coreFolder.Join("cores", "arduino", "Arduino.h").Chtimes(now, now)
require.NoError(t, err)

// Run build again, to verify that the builder rebuilds core.a
_, _, err = cli.Run("compile", "-b", "arduino:avr:uno", "--build-cache-path", buildCachePath.String(), sketchPath.String())
require.NoError(t, err)
coreStatAfterTouch, err := cachedCoreFile.Stat()
require.NoError(t, err)
require.NotEqual(t, coreStatBefore.ModTime(), coreStatAfterTouch.ModTime())
}
5 changes: 2 additions & 3 deletions legacy/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ func (s *Builder) Run(ctx *types.Context) error {
&RecipeByPrefixSuffixRunner{Prefix: "recipe.hooks.core.prebuild", Suffix: ".pattern"},

types.BareCommand(func(ctx *types.Context) error {
objectFiles, archiveFile, coreBuildCachePath, err := phases.CoreBuilder(
ctx.BuildPath, ctx.CoreBuildPath, ctx.CoreBuildCachePath,
objectFiles, archiveFile, err := phases.CoreBuilder(
ctx.BuildPath, ctx.CoreBuildPath, ctx.Builder.CoreBuildCachePath(),
ctx.BuildProperties,
ctx.ActualPlatform,
ctx.Verbose, ctx.OnlyUpdateCompilationDatabase, ctx.Clean,
Expand All @@ -90,7 +90,6 @@ func (s *Builder) Run(ctx *types.Context) error {

ctx.CoreObjectsFiles = objectFiles
ctx.CoreArchiveFilePath = archiveFile
ctx.CoreBuildCachePath = coreBuildCachePath

return err
}),
Expand Down
10 changes: 5 additions & 5 deletions legacy/builder/phases/core_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ func CoreBuilder(
verboseInfoFn func(msg string),
verboseStdoutFn, verboseStderrFn func(data []byte),
progress *progress.Struct, progressCB rpc.TaskProgressCB,
) (paths.PathList, *paths.Path, *paths.Path, error) {
) (paths.PathList, *paths.Path, error) {
if err := coreBuildPath.MkdirAll(); err != nil {
return nil, nil, coreBuildCachePath, errors.WithStack(err)
return nil, nil, errors.WithStack(err)
}

if coreBuildCachePath != nil {
Expand All @@ -63,7 +63,7 @@ func CoreBuilder(
verboseInfoFn(tr("Running normal build of the core..."))
coreBuildCachePath = nil
} else if err := coreBuildCachePath.MkdirAll(); err != nil {
return nil, nil, coreBuildCachePath, errors.WithStack(err)
return nil, nil, errors.WithStack(err)
}
}

Expand All @@ -81,10 +81,10 @@ func CoreBuilder(
progress, progressCB,
)
if err != nil {
return nil, nil, coreBuildCachePath, errors.WithStack(err)
return nil, nil, errors.WithStack(err)
}

return objectFiles, archiveFile, coreBuildCachePath, nil
return objectFiles, archiveFile, nil
}

func compileCore(
Expand Down
49 changes: 1 addition & 48 deletions legacy/builder/test/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ import (
"fmt"
"path/filepath"
"testing"
"time"

bldr "github.com/arduino/arduino-cli/arduino/builder"
"github.com/arduino/arduino-cli/arduino/builder/detector"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"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/phases"
"github.com/arduino/arduino-cli/legacy/builder/types"
"github.com/arduino/go-paths-helper"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -100,7 +98,7 @@ func prepareBuilderTestContext(t *testing.T, ctx *types.Context, sketchPath *pat
ctx.Sketch = sk
}

ctx.Builder = bldr.NewBuilder(ctx.Sketch)
ctx.Builder = bldr.NewBuilder(ctx.Sketch, nil)
if fqbn != "" {
ctx.FQBN = parseFQBN(t, fqbn)
targetPackage, targetPlatform, targetBoard, buildProperties, buildPlatform, err := pme.ResolveFQBN(ctx.FQBN)
Expand Down Expand Up @@ -185,48 +183,3 @@ func TestBuilderWithBuildPathInSketchDir(t *testing.T) {
err = command.Run(ctx)
NoError(t, err)
}

func TestBuilderCacheCoreAFile(t *testing.T) {
ctx := prepareBuilderTestContext(t, nil, paths.New("sketch1", "sketch1.ino"), "arduino:avr:uno")
defer cleanUpBuilderTestContext(t, ctx)

SetupBuildCachePath(t, ctx)
defer ctx.CoreBuildCachePath.RemoveAll()

// Run build
bldr := builder.Builder{}
err := bldr.Run(ctx)
NoError(t, err)

// Pick timestamp of cached core
coreFolder := paths.New("downloaded_hardware", "arduino", "avr")
coreFileName := phases.GetCachedCoreArchiveDirName(ctx.FQBN.String(), ctx.BuildProperties.Get("compiler.optimization_flags"), coreFolder)
cachedCoreFile := ctx.CoreBuildCachePath.Join(coreFileName, "core.a")
coreStatBefore, err := cachedCoreFile.Stat()
require.NoError(t, err)
lastUsedFile := ctx.CoreBuildCachePath.Join(coreFileName, ".last-used")
_, err = lastUsedFile.Stat()
require.NoError(t, err)

// Run build again, to verify that the builder skips rebuilding core.a
err = bldr.Run(ctx)
NoError(t, err)

coreStatAfterRebuild, err := cachedCoreFile.Stat()
require.NoError(t, err)
require.Equal(t, coreStatBefore.ModTime(), coreStatAfterRebuild.ModTime())

// Touch a file of the core and check if the builder invalidate the cache
time.Sleep(time.Second)
now := time.Now().Local()
err = coreFolder.Join("cores", "arduino", "Arduino.h").Chtimes(now, now)
require.NoError(t, err)

// Run build again, to verify that the builder rebuilds core.a
err = bldr.Run(ctx)
NoError(t, err)

coreStatAfterTouch, err := cachedCoreFile.Stat()
require.NoError(t, err)
require.NotEqual(t, coreStatBefore.ModTime(), coreStatAfterTouch.ModTime())
}
8 changes: 0 additions & 8 deletions legacy/builder/test/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/arduino/arduino-cli/arduino/builder/cpp"
"github.com/arduino/arduino-cli/arduino/cores"
"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/assert"
Expand Down Expand Up @@ -70,13 +69,6 @@ func SetupBuildPath(t *testing.T, ctx *types.Context) *paths.Path {
return buildPath
}

func SetupBuildCachePath(t *testing.T, ctx *types.Context) *paths.Path {
buildCachePath, err := paths.MkTempDir(constants.EMPTY_STRING, "test_build_cache")
NoError(t, err)
ctx.CoreBuildCachePath = buildCachePath
return buildCachePath
}

func parseFQBN(t *testing.T, fqbnIn string) *cores.FQBN {
fqbn, err := cores.ParseFQBN(fqbnIn)
require.NoError(t, err)
Expand Down
1 change: 0 additions & 1 deletion legacy/builder/types/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ type Context struct {
BuildPath *paths.Path
SketchBuildPath *paths.Path
CoreBuildPath *paths.Path
CoreBuildCachePath *paths.Path
CoreArchiveFilePath *paths.Path
CoreObjectsFiles paths.PathList
LibrariesBuildPath *paths.Path
Expand Down

0 comments on commit 22449c9

Please sign in to comment.