From a8f6bc2c81d90f4771c9956164564a11cde58bed Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 15 Sep 2026 23:26:47 -0500 Subject: [PATCH] fix(server): detect unsupported legacy Android command-line tools --- .../server/src/device/LocalDeviceHost.test.ts | 57 +++++++++++++++++-- apps/server/src/device/LocalDeviceHost.ts | 14 ++++- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/apps/server/src/device/LocalDeviceHost.test.ts b/apps/server/src/device/LocalDeviceHost.test.ts index 17d274e73529..4442b8f66ab0 100644 --- a/apps/server/src/device/LocalDeviceHost.test.ts +++ b/apps/server/src/device/LocalDeviceHost.test.ts @@ -14,17 +14,21 @@ import * as NetService from "@t3tools/shared/Net"; import * as ServerConfig from "../config.ts"; import * as ProcessRunner from "../processRunner.ts"; -const diagnose = (files: ReadonlyArray, environment: NodeJS.ProcessEnv) => +const diagnose = ( + files: ReadonlyArray, + environment: NodeJS.ProcessEnv, + platform: NodeJS.Platform = "darwin", +) => LocalDeviceHost.__testing.platformReason("android").pipe( Effect.provideService(HostProcessEnvironment, environment), - Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(HostProcessPlatform, platform), Effect.provideService( FileSystem.FileSystem, FileSystem.makeNoop({ exists: (file) => Effect.succeed(files.includes(file)), }), ), - Effect.provide(NodePath.layer), + Effect.provide(platform === "win32" ? NodePath.layerWin32 : NodePath.layerPosix), ); describe("Android SDK availability", () => { @@ -40,7 +44,52 @@ describe("Android SDK availability", () => { const reason = yield* diagnose(["/sdk/platform-tools/adb", "/sdk/emulator/emulator"], { ANDROID_HOME: "/sdk", }); - expect(reason).toContain("Command-line Tools (latest)"); + expect(reason).toContain("Command-line Tools (latest) are missing"); + }), + ); + + it.effect("explains how to upgrade legacy command-line tools in the standard macOS SDK", () => + Effect.gen(function* () { + const root = "/test/home/Library/Android/sdk"; + const reason = yield* diagnose( + [`${root}/platform-tools/adb`, `${root}/emulator/emulator`, `${root}/tools/bin/avdmanager`], + { HOME: "/test/home" }, + ); + expect(reason).toContain("older, unsupported version"); + expect(reason).toContain(root); + expect(reason).toContain( + "Install Android SDK Command-line Tools (latest) in Android Studio's SDK Manager under SDK Tools.", + ); + }), + ); + + it.effect("recognizes legacy command-line tools on Windows", () => + Effect.gen(function* () { + const reason = yield* diagnose( + [ + "C:\\Android\\Sdk\\platform-tools\\adb.exe", + "C:\\Android\\Sdk\\emulator\\emulator.exe", + "C:\\Android\\Sdk\\tools\\bin\\avdmanager.bat", + ], + { ANDROID_HOME: "C:\\Android\\Sdk" }, + "win32", + ); + expect(reason).toContain("older, unsupported version"); + }), + ); + + it.effect("accepts the latest command-line tools when legacy tools are also installed", () => + Effect.gen(function* () { + const reason = yield* diagnose( + [ + "/sdk/platform-tools/adb", + "/sdk/emulator/emulator", + "/sdk/tools/bin/avdmanager", + "/sdk/cmdline-tools/latest/bin/avdmanager", + ], + { ANDROID_HOME: "/sdk" }, + ); + expect(reason).toBeNull(); }), ); diff --git a/apps/server/src/device/LocalDeviceHost.ts b/apps/server/src/device/LocalDeviceHost.ts index 5a18d6e826a6..2ad2961f0936 100644 --- a/apps/server/src/device/LocalDeviceHost.ts +++ b/apps/server/src/device/LocalDeviceHost.ts @@ -104,8 +104,11 @@ const platformReason = Effect.fn("LocalDeviceHost.platformReason")(function* ( return `Android SDK Platform-Tools are missing from ${sdk.root}. Install them in Android Studio's SDK Manager.`; if (!sdk.emulator) return `Android Emulator is missing from ${sdk.root}. Install it in Android Studio's SDK Manager.`; - if (!sdk.avdmanager) + if (!sdk.avdmanager) { + if (sdk.legacyAvdmanager) + return `The Android SDK command-line tools in ${sdk.root} appear to be an older, unsupported version. Install Android SDK Command-line Tools (latest) in Android Studio's SDK Manager under SDK Tools.`; return `Android SDK Command-line Tools (latest) are missing from ${sdk.root}. Install them in Android Studio's SDK Manager.`; + } return null; }); @@ -155,10 +158,15 @@ const androidSdk = Effect.gen(function* () { platform === "win32" ? "avdmanager.bat" : "avdmanager", ), ); - return { root, adb, emulator, avdmanager }; + const legacyAvdmanager = + !avdmanager && + (yield* exists( + path.join(root, "tools", "bin", platform === "win32" ? "avdmanager.bat" : "avdmanager"), + )); + return { root, adb, emulator, avdmanager, legacyAvdmanager }; } } - return { root: null, adb: false, emulator: false, avdmanager: false }; + return { root: null, adb: false, emulator: false, avdmanager: false, legacyAvdmanager: false }; }); const deviceHostEnvironment = (