From 7cb1de5def2642fb3e4ea56e5ba7e9ced678269a Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Fri, 21 Nov 2025 17:37:01 +0100 Subject: [PATCH 1/6] fix(pkg/board): handle adb connection error --- pkg/board/remote/adb/adb.go | 42 ++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/pkg/board/remote/adb/adb.go b/pkg/board/remote/adb/adb.go index eb401305..f386b1a7 100644 --- a/pkg/board/remote/adb/adb.go +++ b/pkg/board/remote/adb/adb.go @@ -36,7 +36,13 @@ import ( "github.com/arduino/arduino-app-cli/pkg/x/ports" ) -const username = "arduino" +var ( + // NotFoundErr is returned when the ADB device is not found. + NotFoundErr = fmt.Errorf("ADB device not found") + // DeviceOfflineErr is returned when the ADB device is not reachable. + // This usually requires a restart of the adbd server daemon on the device. + DeviceOfflineErr = fmt.Errorf("ADB device is offline") +) type ADBConnection struct { adbPath string @@ -46,15 +52,21 @@ type ADBConnection struct { // Ensures ADBConnection implements the RemoteConn interface at compile time. var _ remote.RemoteConn = (*ADBConnection)(nil) +const username = "arduino" + func FromSerial(serial string, adbPath string) (*ADBConnection, error) { if adbPath == "" { adbPath = FindAdbPath() } - return &ADBConnection{ - host: serial, - adbPath: adbPath, - }, nil + conn := ADBConnection{host: serial, adbPath: adbPath} + if connected, err := conn.IsConnected(); err != nil { + return nil, err + } else if !connected { + return nil, fmt.Errorf("device %s is not connected", serial) + } + + return &conn, nil } func FromHost(host string, adbPath string) (*ADBConnection, error) { @@ -71,6 +83,26 @@ func FromHost(host string, adbPath string) (*ADBConnection, error) { return FromSerial(host, adbPath) } +// IsConnected checks if the ADB device is connected and online. +func (a *ADBConnection) IsConnected() (bool, error) { + cmd, err := paths.NewProcess(nil, a.adbPath, "-s", a.host, "get-state") + if err != nil { + return false, fmt.Errorf("failed to create ADB command: %w", err) + } + + output, err := cmd.RunAndCaptureCombinedOutput(context.TODO()) + if err != nil { + if bytes.Contains(output, []byte("device offline")) { + return false, DeviceOfflineErr + } else if bytes.Contains(output, []byte("not found")) { + return false, NotFoundErr + } + return false, fmt.Errorf("failed to get ADB device state: %w: %s", err, output) + } + + return string(bytes.TrimSpace(output)) == "device", nil +} + func (a *ADBConnection) Forward(ctx context.Context, localPort int, remotePort int) error { if !ports.IsAvailable(localPort) { return remote.ErrPortAvailable From 02af7995ba46a64deec6999b0af4efd0189b1202 Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Fri, 21 Nov 2025 17:57:21 +0100 Subject: [PATCH 2/6] add a warning --- pkg/board/board.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/board/board.go b/pkg/board/board.go index 3dac4af2..b8a1ec1c 100644 --- a/pkg/board/board.go +++ b/pkg/board/board.go @@ -192,6 +192,8 @@ func FromFQBN(ctx context.Context, fqbn string) ([]Board, error) { if name, err := GetCustomName(ctx, conn); err == nil { customName = name } + } else { + slog.Warn("failed to get custom name", "serial", serial, "error", err) } boards = append(boards, Board{ From 8fd8e18fb20784fb1089aed69e442ef6f041a747 Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Fri, 21 Nov 2025 18:11:00 +0100 Subject: [PATCH 3/6] don't expose the function --- pkg/board/remote/adb/adb.go | 68 +++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/pkg/board/remote/adb/adb.go b/pkg/board/remote/adb/adb.go index f386b1a7..acbd8d89 100644 --- a/pkg/board/remote/adb/adb.go +++ b/pkg/board/remote/adb/adb.go @@ -36,14 +36,6 @@ import ( "github.com/arduino/arduino-app-cli/pkg/x/ports" ) -var ( - // NotFoundErr is returned when the ADB device is not found. - NotFoundErr = fmt.Errorf("ADB device not found") - // DeviceOfflineErr is returned when the ADB device is not reachable. - // This usually requires a restart of the adbd server daemon on the device. - DeviceOfflineErr = fmt.Errorf("ADB device is offline") -) - type ADBConnection struct { adbPath string host string @@ -54,19 +46,49 @@ var _ remote.RemoteConn = (*ADBConnection)(nil) const username = "arduino" +var ( + // NotFoundErr is returned when the ADB device is not found. + NotFoundErr = fmt.Errorf("ADB device not found") + // DeviceOfflineErr is returned when the ADB device is not reachable. + // This usually requires a restart of the adbd server daemon on the device. + DeviceOfflineErr = fmt.Errorf("ADB device is offline") +) + +// FromSerial creates an ADBConnection from a device serial number. +// returns an error NotFoundErr if the device is not found, and DeviceOfflineErr if the device is offline. func FromSerial(serial string, adbPath string) (*ADBConnection, error) { if adbPath == "" { adbPath = FindAdbPath() } - conn := ADBConnection{host: serial, adbPath: adbPath} - if connected, err := conn.IsConnected(); err != nil { + isConnected := func(serial, adbPath string) (bool, error) { + cmd, err := paths.NewProcess(nil, adbPath, "-s", serial, "get-state") + if err != nil { + return false, fmt.Errorf("failed to create ADB command: %w", err) + } + + output, err := cmd.RunAndCaptureCombinedOutput(context.TODO()) + if err != nil { + if bytes.Contains(output, []byte("device offline")) { + return false, DeviceOfflineErr + } else if bytes.Contains(output, []byte("not found")) { + return false, NotFoundErr + } + return false, fmt.Errorf("failed to get ADB device state: %w: %s", err, output) + } + + return string(bytes.TrimSpace(output)) == "device", nil + } + if connected, err := isConnected(adbPath, serial); err != nil { return nil, err } else if !connected { return nil, fmt.Errorf("device %s is not connected", serial) } - return &conn, nil + return &ADBConnection{ + adbPath: adbPath, + host: serial, + }, nil } func FromHost(host string, adbPath string) (*ADBConnection, error) { @@ -77,32 +99,12 @@ func FromHost(host string, adbPath string) (*ADBConnection, error) { if err != nil { return nil, err } - if err := cmd.Run(); err != nil { - return nil, fmt.Errorf("failed to connect to ADB host %s: %w", host, err) + if out, err := cmd.RunAndCaptureCombinedOutput(context.TODO()); err != nil { + return nil, fmt.Errorf("failed to connect to ADB host %s: %w: %s", host, err, out) } return FromSerial(host, adbPath) } -// IsConnected checks if the ADB device is connected and online. -func (a *ADBConnection) IsConnected() (bool, error) { - cmd, err := paths.NewProcess(nil, a.adbPath, "-s", a.host, "get-state") - if err != nil { - return false, fmt.Errorf("failed to create ADB command: %w", err) - } - - output, err := cmd.RunAndCaptureCombinedOutput(context.TODO()) - if err != nil { - if bytes.Contains(output, []byte("device offline")) { - return false, DeviceOfflineErr - } else if bytes.Contains(output, []byte("not found")) { - return false, NotFoundErr - } - return false, fmt.Errorf("failed to get ADB device state: %w: %s", err, output) - } - - return string(bytes.TrimSpace(output)) == "device", nil -} - func (a *ADBConnection) Forward(ctx context.Context, localPort int, remotePort int) error { if !ports.IsAvailable(localPort) { return remote.ErrPortAvailable From 4a77c683811d73cc89b215787e68fac56d6e891a Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Fri, 21 Nov 2025 18:13:24 +0100 Subject: [PATCH 4/6] rename errors --- pkg/board/remote/adb/adb.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/board/remote/adb/adb.go b/pkg/board/remote/adb/adb.go index acbd8d89..1be9f92e 100644 --- a/pkg/board/remote/adb/adb.go +++ b/pkg/board/remote/adb/adb.go @@ -47,11 +47,11 @@ var _ remote.RemoteConn = (*ADBConnection)(nil) const username = "arduino" var ( - // NotFoundErr is returned when the ADB device is not found. - NotFoundErr = fmt.Errorf("ADB device not found") - // DeviceOfflineErr is returned when the ADB device is not reachable. + // ErrNotFound is returned when the ADB device is not found. + ErrNotFound = fmt.Errorf("ADB device not found") + // ErrDeviceOffline is returned when the ADB device is not reachable. // This usually requires a restart of the adbd server daemon on the device. - DeviceOfflineErr = fmt.Errorf("ADB device is offline") + ErrDeviceOffline = fmt.Errorf("ADB device is offline") ) // FromSerial creates an ADBConnection from a device serial number. @@ -70,9 +70,9 @@ func FromSerial(serial string, adbPath string) (*ADBConnection, error) { output, err := cmd.RunAndCaptureCombinedOutput(context.TODO()) if err != nil { if bytes.Contains(output, []byte("device offline")) { - return false, DeviceOfflineErr + return false, ErrDeviceOffline } else if bytes.Contains(output, []byte("not found")) { - return false, NotFoundErr + return false, ErrNotFound } return false, fmt.Errorf("failed to get ADB device state: %w: %s", err, output) } From e3aa26f41b090b063f2ddb99ee02f3055bf85f18 Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Fri, 21 Nov 2025 18:15:00 +0100 Subject: [PATCH 5/6] fixup! rename errors --- pkg/board/remote/adb/adb.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/board/remote/adb/adb.go b/pkg/board/remote/adb/adb.go index 1be9f92e..973ce16a 100644 --- a/pkg/board/remote/adb/adb.go +++ b/pkg/board/remote/adb/adb.go @@ -36,6 +36,8 @@ import ( "github.com/arduino/arduino-app-cli/pkg/x/ports" ) +const username = "arduino" + type ADBConnection struct { adbPath string host string @@ -44,8 +46,6 @@ type ADBConnection struct { // Ensures ADBConnection implements the RemoteConn interface at compile time. var _ remote.RemoteConn = (*ADBConnection)(nil) -const username = "arduino" - var ( // ErrNotFound is returned when the ADB device is not found. ErrNotFound = fmt.Errorf("ADB device not found") From 368e3a814d852fe7d6efd4a55fb486c707450b3f Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Fri, 21 Nov 2025 18:15:55 +0100 Subject: [PATCH 6/6] fixup! don't expose the function --- pkg/board/remote/adb/adb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/board/remote/adb/adb.go b/pkg/board/remote/adb/adb.go index 973ce16a..5d50a63a 100644 --- a/pkg/board/remote/adb/adb.go +++ b/pkg/board/remote/adb/adb.go @@ -79,7 +79,7 @@ func FromSerial(serial string, adbPath string) (*ADBConnection, error) { return string(bytes.TrimSpace(output)) == "device", nil } - if connected, err := isConnected(adbPath, serial); err != nil { + if connected, err := isConnected(serial, adbPath); err != nil { return nil, err } else if !connected { return nil, fmt.Errorf("device %s is not connected", serial)