Transfer completed Go output without copies
This commit is contained in:
@@ -105,7 +105,7 @@ func PrepareBuildDependencies(ctx context.Context, directory string) error {
|
||||
Stderr: captured,
|
||||
})
|
||||
if err != nil {
|
||||
if output := strings.TrimSpace(string(captured.Bytes())); output != "" {
|
||||
if output := strings.TrimSpace(string(captured.take())); output != "" {
|
||||
return fmt.Errorf("go mod download: %w: %s", err, output)
|
||||
}
|
||||
return fmt.Errorf("go mod download: %w", err)
|
||||
@@ -121,8 +121,19 @@ func (tool *Tool) HostTarget() Target {
|
||||
// Run executes a Go command with ReleaseKit's shared offline baseline. Native
|
||||
// commands use the host target and effective cgo configuration. Static commands
|
||||
// use target and disable cgo. Output, when supplied, receives stdout and stderr
|
||||
// as the command runs; the returned bytes retain both streams for diagnostics.
|
||||
func (tool *Tool) Run(ctx context.Context, directory string, mode Mode, target Target, output io.Writer, args ...string) ([]byte, error) {
|
||||
// as the command runs.
|
||||
func (tool *Tool) Run(ctx context.Context, directory string, mode Mode, target Target, output io.Writer, args ...string) error {
|
||||
_, err := tool.execute(ctx, directory, mode, target, output, false, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// Output executes a Go command and returns its combined stdout and stderr.
|
||||
// Output, when supplied, also receives the bytes as the command runs.
|
||||
func (tool *Tool) Output(ctx context.Context, directory string, mode Mode, target Target, output io.Writer, args ...string) ([]byte, error) {
|
||||
return tool.execute(ctx, directory, mode, target, output, true, args...)
|
||||
}
|
||||
|
||||
func (tool *Tool) execute(ctx context.Context, directory string, mode Mode, target Target, output io.Writer, keepOutput bool, args ...string) ([]byte, error) {
|
||||
if len(args) == 0 {
|
||||
return nil, errors.New("Go command requires arguments")
|
||||
}
|
||||
@@ -136,14 +147,24 @@ func (tool *Tool) Run(ctx context.Context, directory string, mode Mode, target T
|
||||
Stdout: captured,
|
||||
Stderr: captured,
|
||||
})
|
||||
contents := captured.Bytes()
|
||||
if forwardErr := captured.forwardingError(); forwardErr != nil {
|
||||
err = errors.Join(err, fmt.Errorf("forward Go output: %w", forwardErr))
|
||||
}
|
||||
contents := captured.take()
|
||||
if err != nil {
|
||||
if len(contents) != 0 {
|
||||
return contents, fmt.Errorf("go %s: %w: %s", strings.Join(args, " "), err, strings.TrimSpace(string(contents)))
|
||||
return outputBytes(contents, keepOutput), fmt.Errorf("go %s: %w: %s", strings.Join(args, " "), err, strings.TrimSpace(string(contents)))
|
||||
}
|
||||
return contents, fmt.Errorf("go %s: %w", strings.Join(args, " "), err)
|
||||
return outputBytes(contents, keepOutput), fmt.Errorf("go %s: %w", strings.Join(args, " "), err)
|
||||
}
|
||||
return contents, nil
|
||||
return outputBytes(contents, keepOutput), nil
|
||||
}
|
||||
|
||||
func outputBytes(contents []byte, keep bool) []byte {
|
||||
if keep {
|
||||
return contents
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tool *Tool) environment(mode Mode, target Target) map[string]string {
|
||||
@@ -206,9 +227,10 @@ func discover(ctx context.Context, directory string, environment map[string]stri
|
||||
}
|
||||
|
||||
type combinedWriter struct {
|
||||
mu sync.Mutex
|
||||
output io.Writer
|
||||
buffer bytes.Buffer
|
||||
mu sync.Mutex
|
||||
output io.Writer
|
||||
buffer bytes.Buffer
|
||||
forwardErr error
|
||||
}
|
||||
|
||||
func (writer *combinedWriter) Write(contents []byte) (int, error) {
|
||||
@@ -217,11 +239,29 @@ func (writer *combinedWriter) Write(contents []byte) (int, error) {
|
||||
if writer.output == nil {
|
||||
return writer.buffer.Write(contents)
|
||||
}
|
||||
return io.MultiWriter(&writer.buffer, writer.output).Write(contents)
|
||||
if _, err := writer.buffer.Write(contents); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
written, err := writer.output.Write(contents)
|
||||
if err == nil && written != len(contents) {
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
if err != nil && writer.forwardErr == nil {
|
||||
writer.forwardErr = err
|
||||
}
|
||||
return written, err
|
||||
}
|
||||
|
||||
func (writer *combinedWriter) Bytes() []byte {
|
||||
func (writer *combinedWriter) forwardingError() error {
|
||||
writer.mu.Lock()
|
||||
defer writer.mu.Unlock()
|
||||
return append([]byte(nil), writer.buffer.Bytes()...)
|
||||
return writer.forwardErr
|
||||
}
|
||||
|
||||
// take transfers the completed capture to the caller. It must only be used
|
||||
// after the child process has stopped writing.
|
||||
func (writer *combinedWriter) take() []byte {
|
||||
writer.mu.Lock()
|
||||
defer writer.mu.Unlock()
|
||||
return writer.buffer.Bytes()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user