blob: a4513783db9c3ab88ad56417f4dc78ca5d850c5d [file] [edit]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package androidtools
import (
"bytes"
"context"
"strings"
"go.chromium.org/luci/common/errors"
"go.chromium.org/luci/common/exec"
"go.chromium.org/infra/cros/recovery/internal/log"
)
// localRun runs blocking command.
// Do not use for non-blocking commands (like: logcat).
func localRun(ctx context.Context, tool string, command string, args ...string) (Response, error) {
if tool == "" {
return nil, errors.Fmt("local run: a tool was not provided")
}
if command == "" {
return nil, errors.Fmt("local run: a command was not provided")
}
// The tool is command so we need adjust arguments.
newCommand := tool
newArgs := []string{command}
newArgs = append(newArgs, args...)
fullCommand := newCommand + " " + strings.Join(newArgs, " ")
log.Debugf(ctx, "Local run: %q.", fullCommand)
cmd := exec.CommandContext(ctx, newCommand, newArgs...)
var outB bytes.Buffer
var errB bytes.Buffer
cmd.Stdout = &outB
cmd.Stderr = &errB
// We always convert error to exit code.
// Return an error only if there is an issue in the code.
err := cmd.Run()
res := &responseImp{
Stdout: outB.Bytes(),
Stderr: errB.Bytes(),
ExitCode: 0,
}
if err != nil {
log.Debugf(ctx, "Local run: execution error: %v", err)
res.ExitCode = 1
res.Stderr = []byte(err.Error())
var exitErr *exec.ExitError
if errors.As(err, &exitErr) {
res.ExitCode = int32(exitErr.ExitCode())
}
}
return res, nil
}