Skip to content

Commit b5c6a07

Browse files
authored
Merge branch 'master' into feat/more-error-details
2 parents e79cd0c + fbeb271 commit b5c6a07

File tree

12 files changed

+134
-25
lines changed

12 files changed

+134
-25
lines changed

Diff for: arduino/cores/packagemanager/install_uninstall.go

+28-9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package packagemanager
1717

1818
import (
19+
"bytes"
1920
"encoding/json"
2021
"fmt"
2122
"runtime"
@@ -174,9 +175,13 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
174175
if !platformRelease.IsInstalled() {
175176
return errors.New(tr("platform not installed"))
176177
}
177-
if err := pme.RunPostInstallScript(platformRelease.InstallDir); err != nil {
178-
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot configure platform: %s", err)})
178+
stdout, stderr, err := pme.RunPostInstallScript(platformRelease.InstallDir)
179+
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
180+
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
181+
if err != nil {
182+
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot configure platform: %s", err), Completed: true})
179183
}
184+
180185
} else {
181186
log.Info("Skipping platform configuration.")
182187
taskCB(&rpc.TaskProgress{Message: tr("Skipping platform configuration.")})
@@ -226,7 +231,7 @@ func (pme *Explorer) cacheInstalledJSON(platformRelease *cores.PlatformRelease)
226231

227232
// RunPostInstallScript runs the post_install.sh (or post_install.bat) script for the
228233
// specified platformRelease or toolRelease.
229-
func (pme *Explorer) RunPostInstallScript(installDir *paths.Path) error {
234+
func (pme *Explorer) RunPostInstallScript(installDir *paths.Path) ([]byte, []byte, error) {
230235
postInstallFilename := "post_install.sh"
231236
if runtime.GOOS == "windows" {
232237
postInstallFilename = "post_install.bat"
@@ -235,14 +240,16 @@ func (pme *Explorer) RunPostInstallScript(installDir *paths.Path) error {
235240
if postInstall.Exist() && postInstall.IsNotDir() {
236241
cmd, err := executils.NewProcessFromPath(pme.GetEnvVarsForSpawnedProcess(), postInstall)
237242
if err != nil {
238-
return err
243+
return []byte{}, []byte{}, err
239244
}
245+
cmdStdout, cmdStderr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
246+
cmd.RedirectStdoutTo(cmdStdout)
247+
cmd.RedirectStderrTo(cmdStderr)
240248
cmd.SetDirFromPath(installDir)
241-
if err := cmd.Run(); err != nil {
242-
return err
243-
}
249+
err = cmd.Run()
250+
return cmdStdout.Bytes(), cmdStderr.Bytes(), err
244251
}
245-
return nil
252+
return []byte{}, []byte{}, nil
246253
}
247254

248255
// IsManagedPlatformRelease returns true if the PlatforRelease is managed by the PackageManager
@@ -335,7 +342,10 @@ func (pme *Explorer) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Task
335342
if !skipPostInstall {
336343
log.Info("Running tool post_install script")
337344
taskCB(&rpc.TaskProgress{Message: tr("Configuring tool.")})
338-
if err := pme.RunPostInstallScript(toolRelease.InstallDir); err != nil {
345+
stdout, stderr, err := pme.RunPostInstallScript(toolRelease.InstallDir)
346+
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout)})
347+
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr)})
348+
if err != nil {
339349
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot configure tool: %s", err)})
340350
}
341351
} else {
@@ -412,3 +422,12 @@ func (pme *Explorer) IsToolRequired(toolRelease *cores.ToolRelease) bool {
412422
}
413423
return false
414424
}
425+
426+
func skipEmptyMessageTaskProgressCB(taskCB rpc.TaskProgressCB) rpc.TaskProgressCB {
427+
return func(msg *rpc.TaskProgress) {
428+
if msg != nil && len(msg.Message) == 0 {
429+
return
430+
}
431+
taskCB(msg)
432+
}
433+
}

Diff for: arduino/cores/packagemanager/package_manager_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"fmt"
2020
"net/url"
2121
"os"
22+
"runtime"
23+
"strings"
2224
"testing"
2325

2426
"github.com/arduino/arduino-cli/arduino/cores"
@@ -639,3 +641,39 @@ func TestLegacyPackageConversionToPluggableDiscovery(t *testing.T) {
639641
require.Equal(t, `"{network_cmd}" -address {upload.port.address} -port {upload.port.properties.port} -sketch "{build.path}/{build.project_name}.hex" -upload {upload.port.properties.endpoint_upload} -sync {upload.port.properties.endpoint_sync} -reset {upload.port.properties.endpoint_reset} -sync_exp {upload.port.properties.sync_return}`, platformProps.Get("tools.avrdude__pluggable_network.upload.pattern"))
640642
}
641643
}
644+
645+
func TestRunPostInstall(t *testing.T) {
646+
pmb := packagemanager.NewBuilder(nil, nil, nil, nil, "test")
647+
pm := pmb.Build()
648+
pme, release := pm.NewExplorer()
649+
defer release()
650+
651+
// prepare dummy post install script
652+
dir := paths.New(t.TempDir())
653+
654+
var scriptPath *paths.Path
655+
var err error
656+
if runtime.GOOS == "windows" {
657+
scriptPath = dir.Join("post_install.bat")
658+
659+
err = scriptPath.WriteFile([]byte(
660+
`@echo off
661+
echo sent in stdout
662+
echo sent in stderr 1>&2`))
663+
} else {
664+
scriptPath = dir.Join("post_install.sh")
665+
err = scriptPath.WriteFile([]byte(
666+
`#!/bin/sh
667+
echo "sent in stdout"
668+
echo "sent in stderr" 1>&2`))
669+
}
670+
require.NoError(t, err)
671+
err = os.Chmod(scriptPath.String(), 0777)
672+
require.NoError(t, err)
673+
stdout, stderr, err := pme.RunPostInstallScript(dir)
674+
require.NoError(t, err)
675+
676+
// `HasPrefix` because windows seem to add a trailing space at the end
677+
require.Equal(t, "sent in stdout", strings.Trim(string(stdout), "\n\r "))
678+
require.Equal(t, "sent in stderr", strings.Trim(string(stderr), "\n\r "))
679+
}

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package daemon
1717

1818
import (
19+
"encoding/json"
1920
"errors"
2021
"fmt"
2122
"net"
@@ -173,5 +174,6 @@ func (r daemonResult) Data() interface{} {
173174
}
174175

175176
func (r daemonResult) String() string {
176-
return tr("Daemon is now listening on %s:%s", r.IP, r.Port)
177+
j, _ := json.Marshal(r)
178+
return fmt.Sprintln(tr("Daemon is now listening on %s:%s", r.IP, r.Port)) + fmt.Sprintln(string(j))
177179
}

Diff for: internal/integrationtest/compile_3/compile_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/arduino/go-paths-helper"
2323
"github.com/arduino/go-properties-orderedmap"
2424
"github.com/stretchr/testify/require"
25+
"go.bug.st/testifyjson/requirejson"
2526
)
2627

2728
func TestRuntimeToolPropertiesGeneration(t *testing.T) {
@@ -96,3 +97,22 @@ func TestCompileBuildPathInsideSketch(t *testing.T) {
9697
_, _, err = cli.Run("compile", "-b", "arduino:avr:mega", "--build-path", "build-mega")
9798
require.NoError(t, err)
9899
}
100+
101+
func TestCompilerErrOutput(t *testing.T) {
102+
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
103+
defer env.CleanUp()
104+
105+
// Run update-index with our test index
106+
_, _, err := cli.Run("core", "install", "arduino:[email protected]")
107+
require.NoError(t, err)
108+
109+
// prepare sketch
110+
sketch, err := paths.New("testdata", "blink_with_wrong_cpp").Abs()
111+
require.NoError(t, err)
112+
113+
// Run compile and catch err stream
114+
out, _, err := cli.Run("compile", "-b", "arduino:avr:uno", "--format", "json", sketch.String())
115+
require.Error(t, err)
116+
compilerErr := requirejson.Parse(t, out).Query(".compiler_err")
117+
compilerErr.MustContain(`"error"`)
118+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
void setup() {}
2+
void loop() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void wrong() {

Diff for: legacy/builder/builder.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func (s *Preprocess) Run(ctx *types.Context) error {
152152
}
153153

154154
// Output arduino-preprocessed source
155-
ctx.Stdout.Write([]byte(ctx.Source))
155+
ctx.WriteStdout([]byte(ctx.Source))
156156
return nil
157157
}
158158

Diff for: legacy/builder/builder_utils/utils.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,15 @@ func compileFileWithRecipe(ctx *types.Context, sourcePath *paths.Path, source *p
190190
ctx.CompilationDatabase.Add(source, command)
191191
}
192192
if !objIsUpToDate && !ctx.OnlyUpdateCompilationDatabase {
193-
_, _, err = utils.ExecCommand(ctx, command, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */)
193+
// Since this compile could be multithreaded, we first capture the command output
194+
stdout, stderr, err := utils.ExecCommand(ctx, command, utils.Capture, utils.Capture)
195+
// and transfer all at once at the end...
196+
if ctx.Verbose {
197+
ctx.WriteStdout(stdout)
198+
}
199+
ctx.WriteStderr(stderr)
200+
201+
// ...and then return the error
194202
if err != nil {
195203
return nil, errors.WithStack(err)
196204
}

Diff for: legacy/builder/container_find_includes.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ func findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFile t
408408
return errors.New(tr("Internal error in cache"))
409409
}
410410
}
411-
ctx.Stderr.Write(preproc_stderr)
411+
ctx.WriteStderr(preproc_stderr)
412412
return errors.WithStack(preproc_err)
413413
}
414414

Diff for: legacy/builder/preprocess_sketch.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,6 @@ func (s *OutputCodeCompletions) Run(ctx *types.Context) error {
146146
// we assume it is a json, let's make it compliant at least
147147
ctx.CodeCompletions = "[]"
148148
}
149-
fmt.Fprintln(ctx.Stdout, ctx.CodeCompletions)
149+
ctx.WriteStdout([]byte(ctx.CodeCompletions))
150150
return nil
151151
}

Diff for: legacy/builder/types/context.go

+18
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,21 @@ func (ctx *Context) Warn(msg string) {
249249
}
250250
ctx.stdLock.Unlock()
251251
}
252+
253+
func (ctx *Context) WriteStdout(data []byte) (int, error) {
254+
ctx.stdLock.Lock()
255+
defer ctx.stdLock.Unlock()
256+
if ctx.Stdout == nil {
257+
return os.Stdout.Write(data)
258+
}
259+
return ctx.Stdout.Write(data)
260+
}
261+
262+
func (ctx *Context) WriteStderr(data []byte) (int, error) {
263+
ctx.stdLock.Lock()
264+
defer ctx.stdLock.Unlock()
265+
if ctx.Stderr == nil {
266+
return os.Stderr.Write(data)
267+
}
268+
return ctx.Stderr.Write(data)
269+
}

Diff for: legacy/builder/utils/utils.go

+12-11
Original file line numberDiff line numberDiff line change
@@ -184,29 +184,30 @@ const (
184184
)
185185

186186
func ExecCommand(ctx *types.Context, command *exec.Cmd, stdout int, stderr int) ([]byte, []byte, error) {
187-
if ctx.Stdout == nil {
188-
ctx.Stdout = os.Stdout
189-
}
190-
if ctx.Stderr == nil {
191-
ctx.Stderr = os.Stderr
192-
}
193-
194187
if ctx.Verbose {
195188
ctx.Info(PrintableCommand(command.Args))
196189
}
197190

198191
if stdout == Capture {
199192
buffer := &bytes.Buffer{}
200193
command.Stdout = buffer
201-
} else if stdout == Show || stdout == ShowIfVerbose && ctx.Verbose {
202-
command.Stdout = ctx.Stdout
194+
} else if stdout == Show || (stdout == ShowIfVerbose && ctx.Verbose) {
195+
if ctx.Stdout != nil {
196+
command.Stdout = ctx.Stdout
197+
} else {
198+
command.Stdout = os.Stdout
199+
}
203200
}
204201

205202
if stderr == Capture {
206203
buffer := &bytes.Buffer{}
207204
command.Stderr = buffer
208-
} else if stderr == Show || stderr == ShowIfVerbose && ctx.Verbose {
209-
command.Stderr = ctx.Stderr
205+
} else if stderr == Show || (stderr == ShowIfVerbose && ctx.Verbose) {
206+
if ctx.Stderr != nil {
207+
command.Stderr = ctx.Stderr
208+
} else {
209+
command.Stderr = os.Stderr
210+
}
210211
}
211212

212213
err := command.Start()

0 commit comments

Comments
 (0)