| // 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 |
| } |