Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions apps/desktop/src/shell/DesktopShellEnvironment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,42 @@ describe("DesktopShellEnvironment", () => {
}),
);

it.effect.each([
{
name: "hydrates both Android SDK names when neither is inherited",
inherited: {},
expected: {
ANDROID_HOME: "/Volumes/Work/android-sdk",
ANDROID_SDK_ROOT: "/Volumes/Work/android-sdk",
},
},
{
// The device host reads ANDROID_HOME before ANDROID_SDK_ROOT, so a shell
// ANDROID_HOME next to an inherited ANDROID_SDK_ROOT would change the SDK.
name: "keeps an inherited ANDROID_SDK_ROOT selected over a login-shell ANDROID_HOME",
inherited: { ANDROID_SDK_ROOT: "/inherited/android-sdk" },
expected: { ANDROID_HOME: undefined, ANDROID_SDK_ROOT: "/inherited/android-sdk" },
},
])("$name", ({ inherited, expected }) =>
Effect.gen(function* () {
const env: NodeJS.ProcessEnv = { SHELL: "/bin/zsh", PATH: "/usr/bin", ...inherited };

yield* runShellEnvironment({
env,
platform: "darwin",
handler: () =>
envOutput({
PATH: "/usr/bin",
ANDROID_HOME: "/Volumes/Work/android-sdk",
ANDROID_SDK_ROOT: "/Volumes/Work/android-sdk",
}),
});

assert.equal(env.ANDROID_HOME, expected.ANDROID_HOME);
assert.equal(env.ANDROID_SDK_ROOT, expected.ANDROID_SDK_ROOT);
}),
);

it.effect("preserves inherited POSIX values when present", () =>
Effect.gen(function* () {
const env: NodeJS.ProcessEnv = {
Expand Down
14 changes: 14 additions & 0 deletions apps/desktop/src/shell/DesktopShellEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export class DesktopShellEnvironment extends Context.Service<

const LOGIN_SHELL_ENV_NAMES = [
"PATH",
"ANDROID_HOME",
"ANDROID_SDK_ROOT",
"DBUS_SESSION_BUS_ADDRESS",
"DISPLAY",
"LANG",
Expand All @@ -95,6 +97,7 @@ const LOGIN_SHELL_ENV_NAMES = [
] as const;
const WINDOWS_PROFILE_ENV_NAMES = ["PATH", "FNM_DIR", "FNM_MULTISHELL_PATH"] as const;
const LOCALE_ENV_NAMES = ["LANG", "LC_ALL", "LC_CTYPE"] as const;
const ANDROID_SDK_ENV_NAMES = ["ANDROID_HOME", "ANDROID_SDK_ROOT"] as const;
const FALLBACK_LC_CTYPE = "en_US.UTF-8";
const WINDOWS_SHELL_CANDIDATES = ["pwsh.exe", "powershell.exe"] as const;
const LOGIN_SHELL_TIMEOUT = Duration.seconds(5);
Expand Down Expand Up @@ -472,6 +475,17 @@ const installPosixEnvironment = Effect.fn("desktop.shellEnvironment.installPosix
}
}

// The device host picks the Android SDK from ANDROID_HOME before ANDROID_SDK_ROOT,
// so a profile-only ANDROID_HOME must not shadow an inherited ANDROID_SDK_ROOT.
if (ANDROID_SDK_ENV_NAMES.every((name) => Option.isNone(trimNonEmpty(config.env[name])))) {
for (const name of ANDROID_SDK_ENV_NAMES) {
const value = trimNonEmpty(shellEnvironment[name]);
if (Option.isSome(value)) {
config.env[name] = value.value;
}
}
}

// Locale variables form one precedence group: LC_ALL can override an inherited
// LANG or LC_CTYPE, so only hydrate the group when the process has none of them.
if (
Expand Down
Loading