mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix syncing shell env on TCSH and CSH (#6453)
* Fix syncing shell env on TCSH and CSH Signed-off-by: Sebastian Malton <sebastian@malton.name> * Refactor computeUnixShellEnvironment to be clearer Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
dbed58cfe5
commit
d84d2e28a1
@ -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");
|
||||||
|
});
|
||||||
14
src/main/crypto/random-uuid.injectable.ts
Normal file
14
src/main/crypto/random-uuid.injectable.ts
Normal file
@ -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;
|
||||||
@ -2,13 +2,13 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* 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 type { EnvironmentVariables } from "./compute-shell-environment.injectable";
|
||||||
import { getInjectable } from "@ogre-tools/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";
|
||||||
|
|
||||||
interface UnixShellEnvOptions {
|
export interface UnixShellEnvOptions {
|
||||||
signal?: AbortSignal;
|
signal?: AbortSignal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,7 +16,37 @@ export type ComputeUnixShellEnvironment = (shell: string, opts?: UnixShellEnvOpt
|
|||||||
|
|
||||||
const computeUnixShellEnvironmentInjectable = getInjectable({
|
const computeUnixShellEnvironmentInjectable = getInjectable({
|
||||||
id: "compute-unix-shell-environment",
|
id: "compute-unix-shell-environment",
|
||||||
instantiate: (): ComputeUnixShellEnvironment => async (shell, opts) => {
|
instantiate: (di): ComputeUnixShellEnvironment => {
|
||||||
|
const powerShellName = /^pwsh(-preview)?$/;
|
||||||
|
const nonBashLikeShellName = /^t?csh$/;
|
||||||
|
|
||||||
|
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 runAsNode = process.env["ELECTRON_RUN_AS_NODE"];
|
||||||
const noAttach = process.env["ELECTRON_NO_ATTACH_CONSOLE"];
|
const noAttach = process.env["ELECTRON_NO_ATTACH_CONSOLE"];
|
||||||
const env = {
|
const env = {
|
||||||
@ -25,38 +55,21 @@ const computeUnixShellEnvironmentInjectable = getInjectable({
|
|||||||
ELECTRON_NO_ATTACH_CONSOLE: "1",
|
ELECTRON_NO_ATTACH_CONSOLE: "1",
|
||||||
};
|
};
|
||||||
const mark = randomUUID().replace(/-/g, "");
|
const mark = randomUUID().replace(/-/g, "");
|
||||||
const regex = new RegExp(`${mark}(.*)${mark}`);
|
const regex = new RegExp(`${mark}(\\{.*\\})${mark}`);
|
||||||
const shellName = basename(shell);
|
const { command, shellArgs } = getShellSpecifices(shellPath, mark);
|
||||||
let command: string;
|
|
||||||
let shellArgs: string[];
|
|
||||||
|
|
||||||
if (/^pwsh(-preview)?$/.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.
|
|
||||||
command = `& '${process.execPath}' -p '''${mark}'' + JSON.stringify(process.env) + ''${mark}'''`;
|
|
||||||
shellArgs = ["-Login", "-Command"];
|
|
||||||
} else {
|
|
||||||
command = `'${process.execPath}' -p '"${mark}" + JSON.stringify(process.env) + "${mark}"'`;
|
|
||||||
|
|
||||||
if (shellName === "tcsh") {
|
|
||||||
shellArgs = ["-ic"];
|
|
||||||
} else {
|
|
||||||
shellArgs = ["-ilc"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const shellProcess = spawn(shell, [...shellArgs, command], {
|
const shellProcess = spawn(shellPath, shellArgs, {
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: ["ignore", "pipe", "pipe"],
|
|
||||||
env,
|
env,
|
||||||
});
|
});
|
||||||
const stdout: Buffer[] = [];
|
const stdout: Buffer[] = [];
|
||||||
|
|
||||||
opts?.signal?.addEventListener("abort", () => shellProcess.kill());
|
opts.signal?.addEventListener("abort", () => shellProcess.kill());
|
||||||
|
|
||||||
|
shellProcess.stdout.on("data", b => stdout.push(b));
|
||||||
|
|
||||||
shellProcess.on("error", (err) => reject(err));
|
shellProcess.on("error", (err) => reject(err));
|
||||||
shellProcess.stdout.on("data", b => stdout.push(b));
|
|
||||||
shellProcess.on("close", (code, signal) => {
|
shellProcess.on("close", (code, signal) => {
|
||||||
if (code || signal) {
|
if (code || signal) {
|
||||||
return reject(new Error(`Unexpected return code from spawned shell (code: ${code}, signal: ${signal})`));
|
return reject(new Error(`Unexpected return code from spawned shell (code: ${code}, signal: ${signal})`));
|
||||||
@ -81,11 +94,13 @@ const computeUnixShellEnvironmentInjectable = getInjectable({
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolve(resolvedEnv);
|
resolve(resolvedEnv);
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
shellProcess.stdin.end(command);
|
||||||
});
|
});
|
||||||
|
};
|
||||||
},
|
},
|
||||||
causesSideEffects: true,
|
causesSideEffects: true,
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user