Merge pull request #3 from taigrr/cd/cleanup-filter-err-and-deps

fix(errors): implement filterErr with common adb stderr patterns
This commit is contained in:
2026-04-12 10:26:49 +02:00
committed by GitHub
7 changed files with 60 additions and 27 deletions

View File

@@ -4,8 +4,8 @@
This library aims at providing idiomatic `adb` bindings for go developers, in order to make it easier to write system tooling using golang.
This tool tries to take guesswork out of arbitrarily shelling out to `adb` by providing a structured, thoroughly-tested wrapper for the `adb` functions most-likely to be used in a system program.
If `adb` must be installed in your path `PATH`. At this time, while this library may work on Windows or MacOS, only Linux is supported.
If you would like to add support for Windows, MacOS, *BSD..., please [Submit a Pull Request](https://github.com/taigrr/adb/pulls).
`adb` must be installed and available in your `PATH`. At this time, while this library may work on Windows or macOS, only Linux is supported.
If you would like to add support for Windows, macOS, *BSD, etc., please [Submit a Pull Request](https://github.com/taigrr/adb/pulls).
## What is adb
@@ -14,17 +14,21 @@ If you would like to add support for Windows, MacOS, *BSD..., please [Submit a P
## Supported adb functions
- [ ] `adb connect`
- [ ] `adb disconnect`
- [ ] `adb shell <input>s`
- [ ] `adb kill-server`
- [ ] `adb device`
- [ ] `adb pull`
- [x] `adb connect`
- [x] `adb disconnect`
- [x] `adb shell <command>`
- [x] `adb kill-server`
- [x] `adb devices`
- [x] `adb pull`
- [ ] `adb install`
- [ ] `adb push`
- [ ] `adb reboot`
- [ ] `adb shell input tap X Y`
- [ ] `adb shell input swipe X1 Y1 X2 Y2 duration`
- [x] `adb push`
- [x] `adb reboot`
- [x] `adb root`
- [x] `adb shell input tap X Y`
- [x] `adb shell input swipe X1 Y1 X2 Y2 duration`
- [x] `adb shell input keyevent` (home, back, app switch)
- [x] `adb shell wm size` (screen resolution)
- [x] `adb shell getevent` (capture and replay tap sequences)
Please note that as this is a purpose-driven project library, not all functionality of ADB is currently supported, but if you need functionality that's not currently supported,
Feel free to [Open an Issue](https://github.com/taigrr/adb/issues) or [Submit a Pull Request](https://github.com/taigrr/adb/pulls)

7
adb.go
View File

@@ -51,10 +51,11 @@ func Connect(ctx context.Context, opts ConnOptions) (Device, error) {
}
func (d Device) ConnString() string {
if d.Port == 0 {
d.Port = 5555
port := d.Port
if port == 0 {
port = 5555
}
return d.IP.String() + ":" + strconv.Itoa(int(d.Port))
return d.IP.String() + ":" + strconv.Itoa(int(port))
}
// Connect to a previously discovered device.

View File

@@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"errors"
"log"
"regexp"
"strconv"
"strings"
@@ -236,10 +235,7 @@ func (d Device) CaptureSequence(ctx context.Context) (t TapSequence, err error)
if errors.Is(err, ErrUnspecified) {
err = nil
}
if errCode != 130 && errCode != -1 && errCode != 1 {
// TODO remove log output here
log.Printf("Expected error code 130 or -1, but got %d\n", errCode)
}
_ = errCode
if stdout == "" {
return TapSequence{}, ErrStdoutEmpty

View File

@@ -17,6 +17,16 @@ var (
ErrResolutionParseFail = errors.New("failed to parse screen size from input text")
// ErrDestExists is returned when a pull destination file already exists.
ErrDestExists = errors.New("destination file already exists")
// ErrDeviceNotFound is returned when no device is connected or the target device cannot be found.
ErrDeviceNotFound = errors.New("device not found")
// ErrDeviceOffline is returned when the target device is offline.
ErrDeviceOffline = errors.New("device offline")
// ErrDeviceUnauthorized is returned when the device has not authorized USB debugging.
ErrDeviceUnauthorized = errors.New("device unauthorized; check the confirmation dialog on the device")
// ErrConnectionRefused is returned when the connection to a device is refused.
ErrConnectionRefused = errors.New("connection refused")
// ErrMoreThanOneDevice is returned when multiple devices are connected and no serial is specified.
ErrMoreThanOneDevice = errors.New("more than one device/emulator; use -s to specify a device")
// ErrUnspecified is returned when the exact error cannot be determined.
ErrUnspecified = errors.New("an unknown error has occurred, please open an issue on GitHub")
)

2
go.mod
View File

@@ -1,5 +1,5 @@
module github.com/taigrr/adb
go 1.26.1
go 1.26.2
require github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510

20
util.go
View File

@@ -5,6 +5,7 @@ import (
"context"
"fmt"
"os/exec"
"strings"
"sync"
)
@@ -56,7 +57,22 @@ func execute(ctx context.Context, args []string) (string, string, int, error) {
// filterErr matches known output strings against the stderr.
//
// The inferred error type is then returned.
// TODO: implement
func filterErr(stderr string) error {
return nil
if stderr == "" {
return nil
}
switch {
case strings.Contains(stderr, "device not found"):
return ErrDeviceNotFound
case strings.Contains(stderr, "device offline"):
return ErrDeviceOffline
case strings.Contains(stderr, "device unauthorized"):
return ErrDeviceUnauthorized
case strings.Contains(stderr, "Connection refused"):
return ErrConnectionRefused
case strings.Contains(stderr, "more than one device"):
return ErrMoreThanOneDevice
default:
return nil
}
}

View File

@@ -1,6 +1,7 @@
package adb
import (
"errors"
"testing"
)
@@ -8,15 +9,20 @@ func Test_filterErr(t *testing.T) {
tests := []struct {
name string
stderr string
wantErr bool
wantErr error
}{
{name: "empty stderr", stderr: "", wantErr: false},
{name: "random output", stderr: "some warning text", wantErr: false},
{name: "empty stderr", stderr: "", wantErr: nil},
{name: "random output", stderr: "some warning text", wantErr: nil},
{name: "device not found", stderr: "error: device not found", wantErr: ErrDeviceNotFound},
{name: "device offline", stderr: "error: device offline", wantErr: ErrDeviceOffline},
{name: "device unauthorized", stderr: "error: device unauthorized.\nThis adb server's $ADB_VENDOR_KEYS is not set", wantErr: ErrDeviceUnauthorized},
{name: "connection refused", stderr: "cannot connect to daemon at tcp:5037: Connection refused", wantErr: ErrConnectionRefused},
{name: "more than one device", stderr: "error: more than one device/emulator", wantErr: ErrMoreThanOneDevice},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := filterErr(tt.stderr)
if (err != nil) != tt.wantErr {
if !errors.Is(err, tt.wantErr) {
t.Errorf("filterErr() error = %v, wantErr %v", err, tt.wantErr)
}
})