Skip to content

Commit 221ff94

Browse files
committed
Desktop boot: keep login-shell PATH capture off the read path
captureUserPath shells out to $SHELL -ilc on every bundled-executor call, including read-only `service status` that boot runs first. Skip the capture for `service status` (process env PATH is enough for a read) and memoize it for the rest of the process lifetime so install/restart pay the shell probe at most once instead of on every call.
1 parent 2cacd52 commit 221ff94

1 file changed

Lines changed: 29 additions & 11 deletions

File tree

apps/desktop/src/main/service.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export const bundledExecutorPath = (): string =>
3838

3939
const executorAvailable = (): boolean => app.isPackaged && existsSync(bundledExecutorPath());
4040

41+
let userPathCapture: Promise<string | undefined> | null = null;
42+
4143
const captureUserPath = async (): Promise<string | undefined> => {
4244
const shell = process.env.SHELL;
4345
if (!shell) return process.env.PATH;
@@ -53,24 +55,37 @@ const captureUserPath = async (): Promise<string | undefined> => {
5355
}
5456
};
5557

56-
const serviceEnv = async (dataDir: string): Promise<NodeJS.ProcessEnv> => ({
57-
...process.env,
58-
...(await captureUserPath().then((path) => (path ? { PATH: path } : {}))),
59-
EXECUTOR_DATA_DIR: dataDir,
60-
EXECUTOR_SCOPE_DIR: dataDir,
61-
EXECUTOR_CLIENT: "desktop",
62-
...sidecarCrashReportingEnv(),
63-
});
58+
const memoizedUserPath = (): Promise<string | undefined> => {
59+
userPathCapture ??= captureUserPath();
60+
return userPathCapture;
61+
};
62+
63+
const serviceEnv = async (
64+
dataDir: string,
65+
options: { readonly captureUserPath: boolean },
66+
): Promise<NodeJS.ProcessEnv> => {
67+
const path = options.captureUserPath ? await memoizedUserPath() : process.env.PATH;
68+
return {
69+
...process.env,
70+
...(path ? { PATH: path } : {}),
71+
EXECUTOR_DATA_DIR: dataDir,
72+
EXECUTOR_SCOPE_DIR: dataDir,
73+
EXECUTOR_CLIENT: "desktop",
74+
...sidecarCrashReportingEnv(),
75+
};
76+
};
6477

6578
const runExecutor = async (
6679
args: ReadonlyArray<string>,
67-
options: { readonly dataDir: string },
80+
options: { readonly dataDir: string; readonly captureUserPath?: boolean },
6881
): Promise<CommandResult> => {
6982
const bin = bundledExecutorPath();
7083
try {
7184
const { stdout, stderr } = await execFileAsync(bin, [...args], {
7285
encoding: "utf8",
73-
env: await serviceEnv(options.dataDir),
86+
env: await serviceEnv(options.dataDir, {
87+
captureUserPath: options.captureUserPath ?? true,
88+
}),
7489
});
7590
return { code: 0, stdout, stderr };
7691
} catch (error) {
@@ -92,7 +107,10 @@ const statusValue = (stdout: string, key: "Registered" | "Running"): boolean =>
92107
export const supervisedServiceStatus = async (): Promise<SupervisedServiceStatus> => {
93108
if (!executorAvailable()) return { supported: false, registered: false, running: false };
94109
const dataDir = join(app.getPath("home"), ".executor");
95-
const result = await runExecutor(["service", "status"], { dataDir });
110+
const result = await runExecutor(["service", "status"], {
111+
dataDir,
112+
captureUserPath: false,
113+
});
96114
if (result.code !== 0) {
97115
serviceLog.warn(`service status failed: ${result.stderr || result.stdout}`);
98116
return { supported: true, registered: false, running: false };

0 commit comments

Comments
 (0)