From 5c11d7f7fe283998d8c043123bd0cf8e86fc16f8 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 9 Aug 2022 07:08:56 -0700 Subject: [PATCH] Fix completely overriding PATH in shellSync (#5451) --- .../utils/__tests__/union-env-path.test.ts | 32 +++++++++++++++++++ src/common/utils/union-env-path.ts | 20 ++++++++++++ src/main/shell-sync.ts | 4 ++- src/main/utils/shell-env.ts | 2 +- 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/common/utils/__tests__/union-env-path.test.ts create mode 100644 src/common/utils/union-env-path.ts diff --git a/src/common/utils/__tests__/union-env-path.test.ts b/src/common/utils/__tests__/union-env-path.test.ts new file mode 100644 index 0000000000..ff8ca916d2 --- /dev/null +++ b/src/common/utils/__tests__/union-env-path.test.ts @@ -0,0 +1,32 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import path from "path"; +import { unionPATHs } from "../union-env-path"; + +describe("unionPATHs", () => { + it("return the same path if given only one with no double delimiters", () => { + expect(unionPATHs(`/bin/bar${path.delimiter}/usr/bin`)).toBe(`/bin/bar${path.delimiter}/usr/bin`); + }); + + it("return equivalent path if given only one with no double delimiters", () => { + expect(unionPATHs(`/bin/bar${path.delimiter}${path.delimiter}/usr/bin`)).toBe(`/bin/bar${path.delimiter}/usr/bin`); + }); + + it("should remove duplicate entries, appending non duplicates in order received", () => { + expect(unionPATHs( + `/bin/bar${path.delimiter}/usr/bin`, + `/bin/bar${path.delimiter}/usr/lens/bat`, + )).toBe(`/bin/bar${path.delimiter}/usr/bin${path.delimiter}/usr/lens/bat`); + }); + + it("should remove duplicate entries, appending non duplicates in order received, 3", () => { + expect(unionPATHs( + `/bin/bar${path.delimiter}/usr/bin`, + `/bin/bar${path.delimiter}/usr/lens/bat`, + `/usr/local/lens${path.delimiter}/usr/bin`, + )).toBe(`/bin/bar${path.delimiter}/usr/bin${path.delimiter}/usr/lens/bat${path.delimiter}/usr/local/lens`); + }); +}); diff --git a/src/common/utils/union-env-path.ts b/src/common/utils/union-env-path.ts new file mode 100644 index 0000000000..991e2c776c --- /dev/null +++ b/src/common/utils/union-env-path.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import path from "path"; +import * as iter from "./iter"; + +/** + * Join all entires with a PATH env var delimated string together + * @param PATHs Any number of PATH env variables + * + * NOTE: This function does not attempt to handle any sort of escape sequences since after testing + * it was found that `zsh` (at least on `macOS`) does not when trying to find programs + */ +export function unionPATHs(...PATHs: string[]): string { + const entries = new Set(iter.filterFlatMap(PATHs, PATH => PATH.split(path.delimiter))); + + return iter.join(entries.values(), path.delimiter); +} diff --git a/src/main/shell-sync.ts b/src/main/shell-sync.ts index 4f78d973ae..d2c58d0abe 100644 --- a/src/main/shell-sync.ts +++ b/src/main/shell-sync.ts @@ -8,6 +8,7 @@ import os from "os"; import { app } from "electron"; import logger from "./logger"; import { isSnap } from "../common/vars"; +import { unionPATHs } from "../common/utils/union-env-path"; /** * shellSync loads what would have been the environment if this application was @@ -25,7 +26,8 @@ export async function shellSync() { } if (!isSnap) { - process.env.PATH = env.PATH; + // Prefer the synced PATH over the initial one + process.env.PATH = unionPATHs(env.PATH ?? "", process.env.PATH ?? ""); } // The spread operator allows joining of objects. The precedence is last to first. diff --git a/src/main/utils/shell-env.ts b/src/main/utils/shell-env.ts index 63f3b53159..abcbeb5bed 100644 --- a/src/main/utils/shell-env.ts +++ b/src/main/utils/shell-env.ts @@ -6,7 +6,7 @@ import shellEnvironment from "shell-env"; import logger from "../logger"; -export type EnvironmentVariables = Record; +export type EnvironmentVariables = Partial>; let shellSyncFailed = false;