From ebbe936e6c36ef5ac104a86630b01a6a47c5ee41 Mon Sep 17 00:00:00 2001 From: Luca Bianconi Date: Fri, 24 Feb 2023 18:24:54 +0100 Subject: [PATCH 1/3] feat: allow to show compilation properties without providing a sketch --- commands/compile/compile.go | 79 +++++++++++-------- internal/cli/arguments/sketch.go | 8 +- internal/cli/board/attach.go | 2 +- internal/cli/compile/compile.go | 22 ++++-- internal/cli/debug/debug.go | 2 +- .../fail_if_buildpath_equals_sketchpath.go | 3 + 6 files changed, 76 insertions(+), 40 deletions(-) diff --git a/commands/compile/compile.go b/commands/compile/compile.go index 31e0a647b01..232d05d6484 100644 --- a/commands/compile/compile.go +++ b/commands/compile/compile.go @@ -73,11 +73,14 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream return nil, &arduino.MissingSketchPathError{} } sketchPath := paths.New(req.GetSketchPath()) - sk, err := sketch.New(sketchPath) - if err != nil { - return nil, &arduino.CantOpenSketchError{Cause: err} + builderCtx := &types.Context{} + builderCtx.PackageManager = pme + if pme.GetProfile() != nil { + builderCtx.LibrariesManager = lm } + sk, newSketchErr := sketch.New(sketchPath) + fqbnIn := req.GetFqbn() if fqbnIn == "" && sk != nil { fqbnIn = sk.GetDefaultFQBN() @@ -111,13 +114,23 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream securityKeysOverride = append(securityKeysOverride, "build.keys.keychain="+req.KeysKeychain, "build.keys.sign_key="+req.GetSignKey(), "build.keys.encrypt_key="+req.EncryptKey) } - builderCtx := &types.Context{} - builderCtx.PackageManager = pme - if pme.GetProfile() != nil { - builderCtx.LibrariesManager = lm - } builderCtx.UseCachedLibrariesResolution = req.GetSkipLibrariesDiscovery() builderCtx.FQBN = fqbn + defer func() { + appendBuildProperties(r, builderCtx) + }() + r = &rpc.CompileResponse{} + if newSketchErr != nil { + if req.GetShowProperties() { + // Just get build properties and exit + compileErr := builder.RunParseHardware(builderCtx) + if compileErr != nil { + compileErr = &arduino.CompileFailedError{Message: compileErr.Error()} + } + return r, compileErr + } + return nil, &arduino.CantOpenSketchError{Cause: err} + } builderCtx.Sketch = sk builderCtx.ProgressCB = progressCB @@ -187,7 +200,6 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream builderCtx.OnlyUpdateCompilationDatabase = req.GetCreateCompilationDatabaseOnly() builderCtx.SourceOverride = req.GetSourceOverride() - r = &rpc.CompileResponse{} defer func() { if p := builderCtx.BuildPath; p != nil { r.BuildPath = p.String() @@ -200,18 +212,6 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream } }() - defer func() { - buildProperties := builderCtx.BuildProperties - if buildProperties == nil { - return - } - keys := buildProperties.Keys() - sort.Strings(keys) - for _, key := range keys { - r.BuildProperties = append(r.BuildProperties, key+"="+buildProperties.Get(key)) - } - }() - if req.GetShowProperties() { // Just get build properties and exit compileErr := builder.RunParseHardware(builderCtx) @@ -231,16 +231,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream } defer func() { - importedLibs := []*rpc.Library{} - for _, lib := range builderCtx.ImportedLibraries { - rpcLib, err := lib.ToRPCLibrary() - if err != nil { - msg := tr("Error getting information for library %s", lib.Name) + ": " + err.Error() + "\n" - errStream.Write([]byte(msg)) - } - importedLibs = append(importedLibs, rpcLib) - } - r.UsedLibraries = importedLibs + appendUserLibraries(r, builderCtx, errStream) }() // if it's a regular build, go on... @@ -309,6 +300,32 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream return r, nil } +func appendUserLibraries(r *rpc.CompileResponse, builderCtx *types.Context, errStream io.Writer) { + importedLibs := []*rpc.Library{} + for _, lib := range builderCtx.ImportedLibraries { + rpcLib, err := lib.ToRPCLibrary() + if err != nil { + msg := tr("Error getting information for library %s", lib.Name) + ": " + err.Error() + "\n" + errStream.Write([]byte(msg)) + } + importedLibs = append(importedLibs, rpcLib) + } + r.UsedLibraries = importedLibs +} + +func appendBuildProperties(r *rpc.CompileResponse, builderCtx *types.Context) bool { + buildProperties := builderCtx.BuildProperties + if buildProperties == nil { + return true + } + keys := buildProperties.Keys() + sort.Strings(keys) + for _, key := range keys { + r.BuildProperties = append(r.BuildProperties, key+"="+buildProperties.Get(key)) + } + return false +} + // maybePurgeBuildCache runs the build files cache purge if the policy conditions are met. func maybePurgeBuildCache() { diff --git a/internal/cli/arguments/sketch.go b/internal/cli/arguments/sketch.go index 974426044c6..ad983610f0c 100644 --- a/internal/cli/arguments/sketch.go +++ b/internal/cli/arguments/sketch.go @@ -43,7 +43,13 @@ func InitSketchPath(path string) (sketchPath *paths.Path) { } // NewSketch is a helper function useful to create a sketch instance -func NewSketch(sketchPath *paths.Path) *sketch.Sketch { +func NewSketch(sketchPath *paths.Path) (*sketch.Sketch, error) { + return sketch.New(sketchPath) +} + +// MustNewSketch is a helper function useful to create a sketch instance, exits if the +// initialization fails +func MustNewSketch(sketchPath *paths.Path) *sketch.Sketch { sketch, err := sketch.New(sketchPath) if err != nil { feedback.Fatal(tr("Error opening sketch: %v", err), feedback.ErrGeneric) diff --git a/internal/cli/board/attach.go b/internal/cli/board/attach.go index d701ad15e8a..12b4d4b5db5 100644 --- a/internal/cli/board/attach.go +++ b/internal/cli/board/attach.go @@ -50,7 +50,7 @@ func initAttachCommand() *cobra.Command { func runAttachCommand(path string, port *arguments.Port, fqbn string) { sketchPath := arguments.InitSketchPath(path) - sk := arguments.NewSketch(sketchPath) + sk := arguments.MustNewSketch(sketchPath) var currentPort *boardAttachPortResult if currentAddress, currentProtocol := sk.GetDefaultPortAddressAndProtocol(); currentAddress != "" { diff --git a/internal/cli/compile/compile.go b/internal/cli/compile/compile.go index 318fc021dc3..933d1096674 100644 --- a/internal/cli/compile/compile.go +++ b/internal/cli/compile/compile.go @@ -180,6 +180,10 @@ func runCompileCommand(cmd *cobra.Command, args []string) { feedback.Fatal(tr("You cannot use the %s flag while compiling with a profile.", "--library"), feedback.ErrBadArgument) } } + showPropertiesM, err := parseShowPropertiesMode(showProperties) + if err != nil { + feedback.Fatal(tr("Error parsing --show-properties flag: %v", err), feedback.ErrGeneric) + } path := "" if len(args) > 0 { @@ -187,7 +191,18 @@ func runCompileCommand(cmd *cobra.Command, args []string) { } sketchPath := arguments.InitSketchPath(path) - sk := arguments.NewSketch(sketchPath) + sk, err := arguments.NewSketch(sketchPath) + + if err != nil { + showPropertiesWithEmptySketchPath := path == "" && showPropertiesM != showPropertiesModeDisabled + if showPropertiesWithEmptySketchPath { + // properties were requested and no sketch path was provided + // let's use an empty sketch struct and hope for the best + sk = nil + } else { + feedback.Fatal(tr("Error opening sketch: %v", err), feedback.ErrGeneric) + } + } inst, profile := instance.CreateAndInitWithProfile(profileArg.Get(), sketchPath) if fqbnArg.String() == "" { @@ -215,11 +230,6 @@ func runCompileCommand(cmd *cobra.Command, args []string) { overrides = o.Overrides } - showPropertiesM, err := parseShowPropertiesMode(showProperties) - if err != nil { - feedback.Fatal(tr("Error parsing --show-properties flag: %v", err), feedback.ErrGeneric) - } - var stdOut, stdErr io.Writer var stdIORes func() *feedback.OutputStreamsResult if showPropertiesM != showPropertiesModeDisabled { diff --git a/internal/cli/debug/debug.go b/internal/cli/debug/debug.go index 3078fd8d1c8..bd8c146e5c1 100644 --- a/internal/cli/debug/debug.go +++ b/internal/cli/debug/debug.go @@ -75,7 +75,7 @@ func runDebugCommand(command *cobra.Command, args []string) { } sketchPath := arguments.InitSketchPath(path) - sk := arguments.NewSketch(sketchPath) + sk := arguments.MustNewSketch(sketchPath) fqbn, port := arguments.CalculateFQBNAndPort(&portArgs, &fqbnArg, instance, sk) debugConfigRequested := &dbg.DebugConfigRequest{ Instance: instance, diff --git a/legacy/builder/fail_if_buildpath_equals_sketchpath.go b/legacy/builder/fail_if_buildpath_equals_sketchpath.go index 2ec5c0da662..41f1f42c213 100644 --- a/legacy/builder/fail_if_buildpath_equals_sketchpath.go +++ b/legacy/builder/fail_if_buildpath_equals_sketchpath.go @@ -23,6 +23,9 @@ import ( type FailIfBuildPathEqualsSketchPath struct{} func (s *FailIfBuildPathEqualsSketchPath) Run(ctx *types.Context) error { + if ctx.BuildPath == nil || ctx.Sketch == nil { + return nil + } buildPath := ctx.BuildPath.Canonical() sketchPath := ctx.Sketch.FullPath.Canonical() if buildPath.EqualsTo(sketchPath) { From 7a3eefd02791ab4318b277174f5fa4eaa635407b Mon Sep 17 00:00:00 2001 From: Luca Bianconi <71259950+Bikappa@users.noreply.github.com> Date: Thu, 9 Mar 2023 17:11:47 +0100 Subject: [PATCH 2/3] chore: comment --- internal/cli/compile/compile.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/cli/compile/compile.go b/internal/cli/compile/compile.go index 933d1096674..551baa31fad 100644 --- a/internal/cli/compile/compile.go +++ b/internal/cli/compile/compile.go @@ -196,8 +196,8 @@ func runCompileCommand(cmd *cobra.Command, args []string) { if err != nil { showPropertiesWithEmptySketchPath := path == "" && showPropertiesM != showPropertiesModeDisabled if showPropertiesWithEmptySketchPath { - // properties were requested and no sketch path was provided - // let's use an empty sketch struct and hope for the best + // only properties were requested and no sketch path was provided + // an empty sketch is used to collect properties without sketch related values sk = nil } else { feedback.Fatal(tr("Error opening sketch: %v", err), feedback.ErrGeneric) From ff638bc4f35fe85ea2805a6bb4a99373744fe973 Mon Sep 17 00:00:00 2001 From: Luca Bianconi <71259950+Bikappa@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:50:00 +0100 Subject: [PATCH 3/3] refactor: simplified --- commands/compile/compile.go | 75 +++++++++++++----------- legacy/builder/setup_build_properties.go | 4 +- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/commands/compile/compile.go b/commands/compile/compile.go index 232d05d6484..22a70de0c52 100644 --- a/commands/compile/compile.go +++ b/commands/compile/compile.go @@ -120,17 +120,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream appendBuildProperties(r, builderCtx) }() r = &rpc.CompileResponse{} - if newSketchErr != nil { - if req.GetShowProperties() { - // Just get build properties and exit - compileErr := builder.RunParseHardware(builderCtx) - if compileErr != nil { - compileErr = &arduino.CompileFailedError{Message: compileErr.Error()} - } - return r, compileErr - } - return nil, &arduino.CantOpenSketchError{Cause: err} - } + builderCtx.Sketch = sk builderCtx.ProgressCB = progressCB @@ -142,30 +132,11 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream builderCtx.OtherLibrariesDirs = paths.NewPathList(req.GetLibraries()...) builderCtx.OtherLibrariesDirs.Add(configuration.LibrariesDir(configuration.Settings)) builderCtx.LibraryDirs = paths.NewPathList(req.Library...) - if req.GetBuildPath() == "" { - builderCtx.BuildPath = sk.DefaultBuildPath() - } else { - builderCtx.BuildPath = paths.New(req.GetBuildPath()).Canonical() - if in, err := builderCtx.BuildPath.IsInsideDir(sk.FullPath); err != nil { - return nil, &arduino.NotFoundError{Message: tr("Cannot find build path"), Cause: err} - } else if in && builderCtx.BuildPath.IsDir() { - if sk.AdditionalFiles, err = removeBuildFromSketchFiles(sk.AdditionalFiles, builderCtx.BuildPath); err != nil { - return nil, err - } - } - } - if err = builderCtx.BuildPath.MkdirAll(); err != nil { - return nil, &arduino.PermissionDeniedError{Message: tr("Cannot create build directory"), Cause: err} + err = prepareBuildPath(sk, req.GetBuildPath(), builderCtx) + if err != nil { + return r, err } - buildcache.New(builderCtx.BuildPath.Parent()).GetOrCreate(builderCtx.BuildPath.Base()) - // cache is purged after compilation to not remove entries that might be required - defer maybePurgeBuildCache() - - builderCtx.CompilationDatabase = bldr.NewCompilationDatabase( - builderCtx.BuildPath.Join("compile_commands.json"), - ) - builderCtx.Verbose = req.GetVerbose() // Optimize for debug @@ -221,6 +192,15 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream return r, compileErr } + if newSketchErr != nil { + // newSketchErr causes to exit only here since the request could have + // been to only show properties until now + return r, &arduino.CantOpenSketchError{Cause: err} + } + + // cache is purged after compilation to not remove entries that might be required + defer maybePurgeBuildCache() + if req.GetPreprocess() { // Just output preprocessed source code and exit compileErr := builder.RunPreprocess(builderCtx) @@ -300,6 +280,35 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream return r, nil } +func prepareBuildPath(sk *sketch.Sketch, requestedBuildPath string, builderCtx *types.Context) error { + if sk == nil { + return nil + } + + if requestedBuildPath == "" { + builderCtx.BuildPath = sk.DefaultBuildPath() + } else { + builderCtx.BuildPath = paths.New(requestedBuildPath).Canonical() + if in, err := builderCtx.BuildPath.IsInsideDir(sk.FullPath); err != nil { + return &arduino.NotFoundError{Message: tr("Cannot find build path"), Cause: err} + } else if in && builderCtx.BuildPath.IsDir() { + if sk.AdditionalFiles, err = removeBuildFromSketchFiles(sk.AdditionalFiles, builderCtx.BuildPath); err != nil { + return err + } + } + } + + if err := builderCtx.BuildPath.MkdirAll(); err != nil { + return &arduino.PermissionDeniedError{Message: tr("Cannot create build directory"), Cause: err} + } + + builderCtx.CompilationDatabase = bldr.NewCompilationDatabase( + builderCtx.BuildPath.Join("compile_commands.json"), + ) + buildcache.New(builderCtx.BuildPath.Parent()).GetOrCreate(builderCtx.BuildPath.Base()) + return nil +} + func appendUserLibraries(r *rpc.CompileResponse, builderCtx *types.Context, errStream io.Writer) { importedLibs := []*rpc.Library{} for _, lib := range builderCtx.ImportedLibraries { diff --git a/legacy/builder/setup_build_properties.go b/legacy/builder/setup_build_properties.go index 5b191dd8dff..a660ed212fe 100644 --- a/legacy/builder/setup_build_properties.go +++ b/legacy/builder/setup_build_properties.go @@ -45,7 +45,9 @@ func (s *SetupBuildProperties) Run(ctx *types.Context) error { } ctx.OptimizationFlags = buildProperties.Get("compiler.optimization_flags") - buildProperties.SetPath("build.source.path", ctx.Sketch.FullPath) + if ctx.Sketch != nil { + buildProperties.SetPath("build.source.path", ctx.Sketch.FullPath) + } keychainProp := buildProperties.ContainsKey("build.keys.keychain") signProp := buildProperties.ContainsKey("build.keys.sign_key")