diff --git a/src/main/crypto/random-uuid.global-override-for-injectable.ts b/src/main/crypto/random-uuid.global-override-for-injectable.ts new file mode 100644 index 0000000000..63e5364a8a --- /dev/null +++ b/src/main/crypto/random-uuid.global-override-for-injectable.ts @@ -0,0 +1,11 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getGlobalOverride } from "../../common/test-utils/get-global-override"; +import randomUUIDInjectable from "./random-uuid.injectable"; + +export default getGlobalOverride(randomUUIDInjectable, () => () => { + throw new Error("Tried to get a randomUUID without override"); +}); diff --git a/src/main/crypto/random-uuid.injectable.ts b/src/main/crypto/random-uuid.injectable.ts new file mode 100644 index 0000000000..cecee487e2 --- /dev/null +++ b/src/main/crypto/random-uuid.injectable.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { randomUUID } from "crypto"; + +const randomUUIDInjectable = getInjectable({ + id: "random-uuid", + instantiate: () => randomUUID, + causesSideEffects: true, +}); + +export default randomUUIDInjectable; diff --git a/src/main/utils/shell-env/compute-unix-shell-environment.injectable.ts b/src/main/utils/shell-env/compute-unix-shell-environment.injectable.ts index aaf546fd87..668fa95aea 100644 --- a/src/main/utils/shell-env/compute-unix-shell-environment.injectable.ts +++ b/src/main/utils/shell-env/compute-unix-shell-environment.injectable.ts @@ -2,11 +2,11 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { spawn } from "child_process"; -import { randomUUID } from "crypto"; -import { basename } from "path"; import type { EnvironmentVariables } from "./compute-shell-environment.injectable"; import { getInjectable } from "@ogre-tools/injectable"; +import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable"; +import spawnInjectable from "../../child-process/spawn.injectable"; +import randomUUIDInjectable from "../../crypto/random-uuid.injectable"; export interface UnixShellEnvOptions { signal?: AbortSignal; @@ -16,11 +16,37 @@ export type ComputeUnixShellEnvironment = (shell: string, opts?: UnixShellEnvOpt const computeUnixShellEnvironmentInjectable = getInjectable({ id: "compute-unix-shell-environment", - instantiate: (): ComputeUnixShellEnvironment => { + instantiate: (di): ComputeUnixShellEnvironment => { const powerShellName = /^pwsh(-preview)?$/; const nonBashLikeShellName = /^t?csh$/; - return async (shell, opts = {}) => { + const getBasenameOfPath = di.inject(getBasenameOfPathInjectable); + const spawn = di.inject(spawnInjectable); + const randomUUID = di.inject(randomUUIDInjectable); + + const getShellSpecifices = (shellPath: string, mark: string) => { + const shellName = getBasenameOfPath(shellPath); + + if (powerShellName.test(shellName)) { + // Older versions of PowerShell removes double quotes sometimes so we use "double single quotes" which is how + // you escape single quotes inside of a single quoted string. + return { + command: `Command '${process.execPath}' -p '\\"${mark}\\" + JSON.stringify(process.env) + \\"${mark}\\"'`, + shellArgs: ["-Login"], + }; + } + + return { + command: `'${process.execPath}' -p '"${mark}" + JSON.stringify(process.env) + "${mark}"'`, + shellArgs: nonBashLikeShellName.test(shellName) + // tcsh and csh don't support any other options when providing the -l (login) shell option + ? ["-l"] + // zsh (at least, maybe others) don't load RC files when in non-interactive mode, even when using -l (login) option + : ["-li"], + }; + }; + + return async (shellPath, opts = {}) => { const runAsNode = process.env["ELECTRON_RUN_AS_NODE"]; const noAttach = process.env["ELECTRON_NO_ATTACH_CONSOLE"]; const env = { @@ -30,29 +56,10 @@ const computeUnixShellEnvironmentInjectable = getInjectable({ }; const mark = randomUUID().replace(/-/g, ""); const regex = new RegExp(`${mark}(\\{.*\\})${mark}`); - const shellName = basename(shell); - const { command, shellArgs } = (() => { - if (powerShellName.test(shellName)) { - // Older versions of PowerShell removes double quotes sometimes so we use "double single quotes" which is how - // you escape single quotes inside of a single quoted string. - return { - command: `Command '${process.execPath}' -p '\\"${mark}\\" + JSON.stringify(process.env) + \\"${mark}\\"'`, - shellArgs: ["-Login"], - }; - } - - return { - command: `'${process.execPath}' -p '"${mark}" + JSON.stringify(process.env) + "${mark}"'`, - shellArgs: nonBashLikeShellName.test(shellName) - // tcsh and csh don't support any other options when providing the -l (login) shell option - ? ["-l"] - // zsh (at least, maybe others) don't load RC files when in non-interactive mode, even when using -l (login) option - : ["-li"], - }; - })(); + const { command, shellArgs } = getShellSpecifices(shellPath, mark); return new Promise((resolve, reject) => { - const shellProcess = spawn(shell, shellArgs, { + const shellProcess = spawn(shellPath, shellArgs, { detached: true, env, });