package adb import ( "bytes" "context" "fmt" "os/exec" "strings" "time" ) type Client struct { path string } func New(adbPath string) *Client { return &Client{path: adbPath} } // run executes an adb command and returns stdout. func (c *Client) run(ctx context.Context, args ...string) (string, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() cmd := exec.CommandContext(ctx, c.path, args...) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { msg := strings.TrimSpace(stderr.String()) if msg == "" { msg = err.Error() } return "", fmt.Errorf("adb %s: %s", strings.Join(args, " "), msg) } return strings.TrimSpace(stdout.String()), nil } // Devices returns raw output of `adb devices -l`. func (c *Client) Devices(ctx context.Context) (string, error) { return c.run(ctx, "devices", "-l") } // Shell runs a shell command on a specific device and returns stdout. func (c *Client) Shell(ctx context.Context, deviceID, cmd string) (string, error) { return c.run(ctx, "-s", deviceID, "shell", cmd) } // Connect connects to a device over TCP/IP (wireless ADB). func (c *Client) Connect(ctx context.Context, address string) (string, error) { return c.run(ctx, "connect", address) } // Disconnect disconnects a device. func (c *Client) Disconnect(ctx context.Context, deviceID string) (string, error) { return c.run(ctx, "disconnect", deviceID) } // Pull copies a file from the device to a local path. func (c *Client) Pull(ctx context.Context, deviceID, remotePath, localPath string) error { _, err := c.run(ctx, "-s", deviceID, "pull", remotePath, localPath) return err } // Push copies a local file to the device. func (c *Client) Push(ctx context.Context, deviceID, localPath, remotePath string) error { _, err := c.run(ctx, "-s", deviceID, "push", localPath, remotePath) return err } // StartServer starts the ADB server if not already running. func (c *Client) StartServer(ctx context.Context) error { _, err := c.run(ctx, "start-server") return err } // Path returns the resolved ADB binary path. func (c *Client) Path() string { return c.path }