Skip to content

Commit b9edb78

Browse files
authored
bugfix: compile ... --dump-profile now produces a clean output (only the profile) (#2852)
* Output a clean profile with --dump-profile * Use bytes.NewBuffer for creation of bytes buffers * Added integration test
1 parent 079a28f commit b9edb78

File tree

6 files changed

+140
-52
lines changed

6 files changed

+140
-52
lines changed

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

+61-49
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
211211

212212
var stdOut, stdErr io.Writer
213213
var stdIORes func() *feedback.OutputStreamsResult
214-
if showProperties != arguments.ShowPropertiesDisabled {
214+
if showProperties != arguments.ShowPropertiesDisabled || dumpProfile {
215+
// When dumping profile or showing properties, we buffer the output
216+
// to avoid mixing compilation output with profile/properties output
215217
stdOut, stdErr, stdIORes = feedback.NewBufferedStreams()
216218
} else {
217219
stdOut, stdErr, stdIORes = feedback.OutputStreams()
@@ -312,60 +314,69 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer
312314
}
313315
}
314316

317+
successful := (compileError == nil)
315318
profileOut := ""
316-
if dumpProfile && compileError == nil {
317-
// Output profile
318-
319-
libs := ""
320-
hasVendoredLibs := false
321-
for _, lib := range builderRes.GetUsedLibraries() {
322-
if lib.GetLocation() != rpc.LibraryLocation_LIBRARY_LOCATION_USER && lib.GetLocation() != rpc.LibraryLocation_LIBRARY_LOCATION_UNMANAGED {
323-
continue
319+
stdIO := stdIORes()
320+
321+
if dumpProfile {
322+
if successful {
323+
// Output profile
324+
325+
libs := ""
326+
hasVendoredLibs := false
327+
for _, lib := range builderRes.GetUsedLibraries() {
328+
if lib.GetLocation() != rpc.LibraryLocation_LIBRARY_LOCATION_USER && lib.GetLocation() != rpc.LibraryLocation_LIBRARY_LOCATION_UNMANAGED {
329+
continue
330+
}
331+
if lib.GetVersion() == "" {
332+
hasVendoredLibs = true
333+
continue
334+
}
335+
libs += fmt.Sprintln(" - " + lib.GetName() + " (" + lib.GetVersion() + ")")
324336
}
325-
if lib.GetVersion() == "" {
326-
hasVendoredLibs = true
327-
continue
337+
if hasVendoredLibs {
338+
msg := "\n"
339+
msg += i18n.Tr("WARNING: The sketch is compiled using one or more custom libraries.") + "\n"
340+
msg += i18n.Tr("Currently, Build Profiles only support libraries available through Arduino Library Manager.")
341+
feedback.Warning(msg)
328342
}
329-
libs += fmt.Sprintln(" - " + lib.GetName() + " (" + lib.GetVersion() + ")")
330-
}
331-
if hasVendoredLibs {
332-
msg := "\n"
333-
msg += i18n.Tr("WARNING: The sketch is compiled using one or more custom libraries.") + "\n"
334-
msg += i18n.Tr("Currently, Build Profiles only support libraries available through Arduino Library Manager.")
335-
feedback.Warning(msg)
336-
}
337-
338-
newProfileName := "my_profile_name"
339-
if split := strings.Split(compileRequest.GetFqbn(), ":"); len(split) > 2 {
340-
newProfileName = split[2]
341-
}
342-
profileOut = fmt.Sprintln("profiles:")
343-
profileOut += fmt.Sprintln(" " + newProfileName + ":")
344-
profileOut += fmt.Sprintln(" fqbn: " + compileRequest.GetFqbn())
345-
profileOut += fmt.Sprintln(" platforms:")
346-
boardPlatform := builderRes.GetBoardPlatform()
347-
profileOut += fmt.Sprintln(" - platform: " + boardPlatform.GetId() + " (" + boardPlatform.GetVersion() + ")")
348-
if url := boardPlatform.GetPackageUrl(); url != "" {
349-
profileOut += fmt.Sprintln(" platform_index_url: " + url)
350-
}
351343

352-
if buildPlatform := builderRes.GetBuildPlatform(); buildPlatform != nil &&
353-
buildPlatform.GetId() != boardPlatform.GetId() &&
354-
buildPlatform.GetVersion() != boardPlatform.GetVersion() {
355-
profileOut += fmt.Sprintln(" - platform: " + buildPlatform.GetId() + " (" + buildPlatform.GetVersion() + ")")
356-
if url := buildPlatform.GetPackageUrl(); url != "" {
344+
newProfileName := "my_profile_name"
345+
if split := strings.Split(compileRequest.GetFqbn(), ":"); len(split) > 2 {
346+
newProfileName = split[2]
347+
}
348+
profileOut = fmt.Sprintln("profiles:")
349+
profileOut += fmt.Sprintln(" " + newProfileName + ":")
350+
profileOut += fmt.Sprintln(" fqbn: " + compileRequest.GetFqbn())
351+
profileOut += fmt.Sprintln(" platforms:")
352+
boardPlatform := builderRes.GetBoardPlatform()
353+
profileOut += fmt.Sprintln(" - platform: " + boardPlatform.GetId() + " (" + boardPlatform.GetVersion() + ")")
354+
if url := boardPlatform.GetPackageUrl(); url != "" {
357355
profileOut += fmt.Sprintln(" platform_index_url: " + url)
358356
}
357+
358+
if buildPlatform := builderRes.GetBuildPlatform(); buildPlatform != nil &&
359+
buildPlatform.GetId() != boardPlatform.GetId() &&
360+
buildPlatform.GetVersion() != boardPlatform.GetVersion() {
361+
profileOut += fmt.Sprintln(" - platform: " + buildPlatform.GetId() + " (" + buildPlatform.GetVersion() + ")")
362+
if url := buildPlatform.GetPackageUrl(); url != "" {
363+
profileOut += fmt.Sprintln(" platform_index_url: " + url)
364+
}
365+
}
366+
if len(libs) > 0 {
367+
profileOut += fmt.Sprintln(" libraries:")
368+
profileOut += fmt.Sprint(libs)
369+
}
370+
profileOut += fmt.Sprintln()
371+
} else {
372+
// An error occurred, output the buffered build errors instead of the profile
373+
if stdOut, stdErr, err := feedback.DirectStreams(); err == nil {
374+
stdOut.Write([]byte(stdIO.Stdout))
375+
stdErr.Write([]byte(stdIO.Stderr))
376+
}
359377
}
360-
if len(libs) > 0 {
361-
profileOut += fmt.Sprintln(" libraries:")
362-
profileOut += fmt.Sprint(libs)
363-
}
364-
profileOut += fmt.Sprintln()
365378
}
366379

367-
stdIO := stdIORes()
368-
successful := (compileError == nil)
369380
res := &compileResult{
370381
CompilerOut: stdIO.Stdout,
371382
CompilerErr: stdIO.Stderr,
@@ -437,6 +448,10 @@ func (r *compileResult) String() string {
437448
return strings.Join(r.BuilderResult.BuildProperties, fmt.Sprintln())
438449
}
439450

451+
if r.Success && r.ProfileOut != "" {
452+
return r.ProfileOut
453+
}
454+
440455
if r.hideStats {
441456
return ""
442457
}
@@ -485,9 +500,6 @@ func (r *compileResult) String() string {
485500
}
486501
res += fmt.Sprintln(platforms.Render())
487502
}
488-
if r.ProfileOut != "" {
489-
res += fmt.Sprintln(r.ProfileOut)
490-
}
491503
return strings.TrimRight(res, fmt.Sprintln())
492504
}
493505

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ func reset() {
8484
stdErr = os.Stderr
8585
feedbackOut = os.Stdout
8686
feedbackErr = os.Stderr
87-
bufferOut = &bytes.Buffer{}
88-
bufferErr = &bytes.Buffer{}
87+
bufferOut = bytes.NewBuffer(nil)
88+
bufferErr = bytes.NewBuffer(nil)
8989
bufferWarnings = nil
9090
format = Text
9191
formatSelected = false

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func OutputStreams() (io.Writer, io.Writer, func() *OutputStreamsResult) {
6868
// object that can be used as a Result or to retrieve the accumulated output
6969
// to embed it in another object.
7070
func NewBufferedStreams() (io.Writer, io.Writer, func() *OutputStreamsResult) {
71-
out, err := &bytes.Buffer{}, &bytes.Buffer{}
71+
out, err := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
7272
return out, err, func() *OutputStreamsResult {
7373
return &OutputStreamsResult{
7474
Stdout: out.String(),
+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2023 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+
"strings"
20+
"testing"
21+
22+
"github.com/arduino/arduino-cli/internal/integrationtest"
23+
"github.com/arduino/go-paths-helper"
24+
"github.com/stretchr/testify/require"
25+
)
26+
27+
func TestDumpProfileClean(t *testing.T) {
28+
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
29+
t.Cleanup(env.CleanUp)
30+
31+
// Install Arduino AVR Boards
32+
_, _, err := cli.Run("core", "install", "arduino:[email protected]")
33+
require.NoError(t, err)
34+
35+
validSketchPath, err := paths.New("testdata", "ValidSketch").Abs()
36+
require.NoError(t, err)
37+
invalidSketchPath, err := paths.New("testdata", "InvalidSketch").Abs()
38+
require.NoError(t, err)
39+
40+
validProfile := `profiles:
41+
uno:
42+
fqbn: arduino:avr:uno
43+
platforms:
44+
- platform: arduino:avr (1.8.6)`
45+
t.Run("NoVerbose", func(t *testing.T) {
46+
stdout, stderr, err := cli.Run("compile", "-b", "arduino:avr:uno", validSketchPath.String(), "--dump-profile")
47+
require.NoError(t, err)
48+
require.Empty(t, stderr)
49+
profile := strings.TrimSpace(string(stdout))
50+
require.Equal(t, validProfile, profile)
51+
})
52+
t.Run("Verbose", func(t *testing.T) {
53+
stdout, stderr, err := cli.Run("compile", "-b", "arduino:avr:uno", validSketchPath.String(), "--dump-profile", "--verbose")
54+
require.NoError(t, err)
55+
require.Empty(t, stderr)
56+
profile := strings.TrimSpace(string(stdout))
57+
require.Equal(t, validProfile, profile)
58+
})
59+
t.Run("ErrorNoVerbose", func(t *testing.T) {
60+
stdout, stderr, err := cli.Run("compile", "-b", "arduino:avr:uno", invalidSketchPath.String(), "--dump-profile")
61+
require.Error(t, err)
62+
require.NotEmpty(t, stderr)
63+
require.NotContains(t, string(stdout), validProfile)
64+
})
65+
t.Run("ErrorVerbose", func(t *testing.T) {
66+
stdout, stderr, err := cli.Run("compile", "-b", "arduino:avr:uno", invalidSketchPath.String(), "--dump-profile", "--verbose")
67+
require.Error(t, err)
68+
require.NotEmpty(t, stderr)
69+
require.NotContains(t, string(stdout), validProfile)
70+
})
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void setup() {}
2+
void loop() {}
3+
aaaaaa
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
void setup() {}
2+
void loop() {}

0 commit comments

Comments
 (0)