Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ type (
executionHashes map[string]context.Context
executionHashesMutex sync.Mutex
watchedDirs *xsync.MapOf[string, bool]
stdoutMutex sync.Mutex
}
TempDir struct {
Remote string
Expand Down
14 changes: 13 additions & 1 deletion task.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package task

import (
"bytes"
"context"
"fmt"
"os"
Expand Down Expand Up @@ -341,7 +342,10 @@ func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *Call, i in
if err != nil {
return fmt.Errorf("task: failed to get variables: %w", err)
}
stdOut, stdErr, closer := outputWrapper.WrapWriter(e.Stdout, e.Stderr, t.Prefix, outputTemplater)
// Capture stdout to a buffer because when run from a go routine (i.e. deps)
// then concurrent writes may occur on the shared e.Stdout.
_stdout := bytes.NewBuffer([]byte{})
stdOut, stdErr, closer := outputWrapper.WrapWriter(_stdout, e.Stderr, t.Prefix, outputTemplater)

err = execext.RunCommand(ctx, &execext.RunCommandOptions{
Command: cmd.Cmd,
Expand All @@ -353,9 +357,17 @@ func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *Call, i in
Stdout: stdOut,
Stderr: stdErr,
})
// Calling closer will copy remaining buffered stdOut to _stdout. Then
// use a mutex to prevents concurant writes to e.Stdout.
e.stdoutMutex.Lock()
if closeErr := closer(err); closeErr != nil {
e.Logger.Errf(logger.Red, "task: unable to close writer: %v\n", closeErr)
}
if _, writeErr := e.Stdout.Write(_stdout.Bytes()); writeErr != nil {
e.Logger.Errf(logger.Red, "task: unable to write to e.Stdout: %v\n", writeErr)
}
e.stdoutMutex.Unlock()

var exitCode interp.ExitStatus
if errors.As(err, &exitCode) && cmd.IgnoreError {
e.Logger.VerboseErrf(logger.Yellow, "task: [%s] command error ignored: %v\n", t.Name(), err)
Expand Down
Loading