Skip to content

Commit 271d241

Browse files
authored
compile --show-properties now correctly output the result in text and JSON format (#2035)
* Added function to create buffering streams * Moved the direct output of build properties to commands.Compile * BuildProperties are now returned as part of Compile response * Build properties are now displayed alone if running in text mode * Fixed wrong error report * Added integration test * Small improvement on result output
1 parent c666277 commit 271d241

File tree

8 files changed

+160
-84
lines changed

8 files changed

+160
-84
lines changed

Diff for: commands/compile/compile.go

+21-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"context"
2020
"fmt"
2121
"io"
22+
"sort"
2223
"strings"
2324

2425
"github.com/arduino/arduino-cli/arduino"
@@ -185,17 +186,32 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream
185186
}
186187
}()
187188

188-
// if --preprocess or --show-properties were passed, we can stop here
189+
defer func() {
190+
buildProperties := builderCtx.BuildProperties
191+
if buildProperties == nil {
192+
return
193+
}
194+
keys := buildProperties.Keys()
195+
sort.Strings(keys)
196+
for _, key := range keys {
197+
r.BuildProperties = append(r.BuildProperties, key+"="+buildProperties.Get(key))
198+
}
199+
}()
200+
189201
if req.GetShowProperties() {
190-
compileErr := builder.RunParseHardwareAndDumpBuildProperties(builderCtx)
202+
// Just get build properties and exit
203+
compileErr := builder.RunParseHardware(builderCtx)
191204
if compileErr != nil {
192-
compileErr = &arduino.CompileFailedError{Message: err.Error()}
205+
compileErr = &arduino.CompileFailedError{Message: compileErr.Error()}
193206
}
194207
return r, compileErr
195-
} else if req.GetPreprocess() {
208+
}
209+
210+
if req.GetPreprocess() {
211+
// Just output preprocessed source code and exit
196212
compileErr := builder.RunPreprocess(builderCtx)
197213
if compileErr != nil {
198-
compileErr = &arduino.CompileFailedError{Message: err.Error()}
214+
compileErr = &arduino.CompileFailedError{Message: compileErr.Error()}
199215
}
200216
return r, compileErr
201217
}

Diff for: internal/cli/compile/compile.go

+21-7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"encoding/json"
2121
"errors"
2222
"fmt"
23+
"io"
2324
"os"
2425
"strings"
2526

@@ -187,6 +188,14 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
187188
overrides = o.Overrides
188189
}
189190

191+
var stdOut, stdErr io.Writer
192+
var stdIORes func() *feedback.OutputStreamsResult
193+
if showProperties {
194+
stdOut, stdErr, stdIORes = feedback.NewBufferedStreams()
195+
} else {
196+
stdOut, stdErr, stdIORes = feedback.OutputStreams()
197+
}
198+
190199
compileRequest := &rpc.CompileRequest{
191200
Instance: inst,
192201
Fqbn: fqbn,
@@ -212,9 +221,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
212221
EncryptKey: encryptKey,
213222
SkipLibrariesDiscovery: skipLibrariesDiscovery,
214223
}
215-
stdOut, stdErr, stdIORes := feedback.OutputStreams()
216224
compileRes, compileError := compile.Compile(context.Background(), compileRequest, stdOut, stdErr, nil)
217-
218225
if compileError == nil && uploadAfterCompile {
219226
userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{
220227
Instance: inst,
@@ -306,11 +313,12 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
306313

307314
stdIO := stdIORes()
308315
res := &compileResult{
309-
CompilerOut: stdIO.Stdout,
310-
CompilerErr: stdIO.Stderr,
311-
BuilderResult: compileRes,
312-
ProfileOut: profileOut,
313-
Success: compileError == nil,
316+
CompilerOut: stdIO.Stdout,
317+
CompilerErr: stdIO.Stderr,
318+
BuilderResult: compileRes,
319+
ProfileOut: profileOut,
320+
Success: compileError == nil,
321+
showOnlyProperties: showProperties,
314322
}
315323

316324
if compileError != nil {
@@ -355,13 +363,19 @@ type compileResult struct {
355363
Success bool `json:"success"`
356364
ProfileOut string `json:"profile_out,omitempty"`
357365
Error string `json:"error,omitempty"`
366+
367+
showOnlyProperties bool
358368
}
359369

360370
func (r *compileResult) Data() interface{} {
361371
return r
362372
}
363373

364374
func (r *compileResult) String() string {
375+
if r.showOnlyProperties {
376+
return strings.Join(r.BuilderResult.BuildProperties, fmt.Sprintln())
377+
}
378+
365379
titleColor := color.New(color.FgHiGreen)
366380
nameColor := color.New(color.FgHiYellow)
367381
pathColor := color.New(color.FgHiBlack)

Diff for: internal/cli/feedback/stdio.go

+19
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package feedback
1717

1818
import (
19+
"bytes"
1920
"errors"
2021
"io"
2122
)
@@ -56,6 +57,24 @@ func OutputStreams() (io.Writer, io.Writer, func() *OutputStreamsResult) {
5657
return feedbackOut, feedbackErr, getOutputStreamResult
5758
}
5859

60+
// NewBufferedStreams returns a pair of io.Writer to buffer the command output.
61+
// The returned writers will accumulate the output until the command
62+
// execution is completed. The io.Writes will not affect other feedback streams.
63+
//
64+
// This function returns also a callback that must be called when the
65+
// command execution is completed, it will return an *OutputStreamsResult
66+
// object that can be used as a Result or to retrieve the accumulated output
67+
// to embed it in another object.
68+
func NewBufferedStreams() (io.Writer, io.Writer, func() *OutputStreamsResult) {
69+
out, err := &bytes.Buffer{}, &bytes.Buffer{}
70+
return out, err, func() *OutputStreamsResult {
71+
return &OutputStreamsResult{
72+
Stdout: out.String(),
73+
Stderr: err.String(),
74+
}
75+
}
76+
}
77+
5978
func getOutputStreamResult() *OutputStreamsResult {
6079
return &OutputStreamsResult{
6180
Stdout: bufferOut.String(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2022 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package compile_test
17+
18+
import (
19+
"testing"
20+
21+
"github.com/arduino/arduino-cli/internal/integrationtest"
22+
"github.com/arduino/go-properties-orderedmap"
23+
"github.com/stretchr/testify/require"
24+
"go.bug.st/testifyjson/requirejson"
25+
)
26+
27+
func TestCompileShowProperties(t *testing.T) {
28+
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
29+
defer env.CleanUp()
30+
31+
_, _, err := cli.Run("core", "update-index")
32+
require.NoError(t, err)
33+
_, _, err = cli.Run("core", "install", "arduino:avr")
34+
require.NoError(t, err)
35+
36+
bareMinimum := cli.CopySketch("bare_minimum")
37+
38+
// Test --show-properties output is clean
39+
stdout, stderr, err := cli.Run("compile", "--fqbn", "arduino:avr:uno", "-v", "--show-properties", bareMinimum.String())
40+
require.NoError(t, err)
41+
_, err = properties.LoadFromBytes(stdout)
42+
require.NoError(t, err, "Output must be a clean property list")
43+
require.Empty(t, stderr)
44+
45+
// Test --show-properties --format JSON output is clean
46+
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:uno", "-v", "--show-properties", "--format", "json", bareMinimum.String())
47+
require.NoError(t, err)
48+
requirejson.Parse(t, stdout, "Output must be a valid JSON")
49+
require.Empty(t, stderr)
50+
51+
// Test --show-properties output is clean, with a wrong FQBN
52+
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:unoa", "-v", "--show-properties", bareMinimum.String())
53+
require.Error(t, err)
54+
_, err = properties.LoadFromBytes(stdout)
55+
require.NoError(t, err, "Output must be a clean property list")
56+
require.NotEmpty(t, stderr)
57+
58+
// Test --show-properties --format JSON output is clean, with a wrong FQBN
59+
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:unoa", "-v", "--show-properties", "--format", "json", bareMinimum.String())
60+
require.Error(t, err)
61+
requirejson.Parse(t, stdout, "Output must be a valid JSON")
62+
require.Empty(t, stderr)
63+
}

Diff for: legacy/builder/builder.go

+8-19
Original file line numberDiff line numberDiff line change
@@ -162,22 +162,6 @@ func (s *Preprocess) Run(ctx *types.Context) error {
162162
return nil
163163
}
164164

165-
type ParseHardwareAndDumpBuildProperties struct{}
166-
167-
func (s *ParseHardwareAndDumpBuildProperties) Run(ctx *types.Context) error {
168-
if ctx.BuildPath == nil {
169-
ctx.BuildPath = sketch.GenBuildPath(ctx.SketchLocation)
170-
}
171-
172-
commands := []types.Command{
173-
&ContainerSetupHardwareToolsLibsSketchAndProps{},
174-
175-
&DumpBuildProperties{},
176-
}
177-
178-
return runCommands(ctx, commands)
179-
}
180-
181165
func runCommands(ctx *types.Context, commands []types.Command) error {
182166
ctx.Progress.AddSubSteps(len(commands))
183167
defer ctx.Progress.RemoveSubSteps()
@@ -203,9 +187,14 @@ func RunBuilder(ctx *types.Context) error {
203187
return command.Run(ctx)
204188
}
205189

206-
func RunParseHardwareAndDumpBuildProperties(ctx *types.Context) error {
207-
command := ParseHardwareAndDumpBuildProperties{}
208-
return command.Run(ctx)
190+
func RunParseHardware(ctx *types.Context) error {
191+
if ctx.BuildPath == nil {
192+
ctx.BuildPath = sketch.GenBuildPath(ctx.SketchLocation)
193+
}
194+
commands := []types.Command{
195+
&ContainerSetupHardwareToolsLibsSketchAndProps{},
196+
}
197+
return runCommands(ctx, commands)
209198
}
210199

211200
func RunPreprocess(ctx *types.Context) error {

Diff for: legacy/builder/dump_build_properties.go

-38
This file was deleted.

Diff for: rpc/cc/arduino/cli/commands/v1/compile.pb.go

+25-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: rpc/cc/arduino/cli/commands/v1/compile.proto

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ message CompileRequest {
3232
string fqbn = 2;
3333
// The path where the sketch is stored.
3434
string sketch_path = 3;
35-
// Show all build preferences used instead of compiling.
35+
// Just get the build properties and do not run the full compile.
3636
bool show_properties = 4;
3737
// Print preprocessed code to stdout instead of compiling.
3838
bool preprocess = 5;
@@ -112,6 +112,8 @@ message CompileResponse {
112112
InstalledPlatformReference build_platform = 7;
113113
// Completions reports of the compilation process (stream)
114114
TaskProgress progress = 8;
115+
// Build properties used for compiling
116+
repeated string build_properties = 9;
115117
}
116118

117119
message ExecutableSectionSize {

0 commit comments

Comments
 (0)