Skip to content

Commit

Permalink
fix: evaluate 'which' via shell if Node.js is not in PATH (fallback) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mxschmitt authored Jan 9, 2024
1 parent 68472bc commit f025947
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/playwrightTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class PlaywrightTest {
// Playwright will restart itself as child process in the ESM mode and won't inherit the 3/4 pipes.
// Always use ws transport to mitigate it.
const reporterServer = new ReporterServer(this._vscode);
const node = await findNode();
const node = await findNode(this._vscode);
if (token?.isCancellationRequested)
return;
const configFolder = path.dirname(config.configFile);
Expand Down Expand Up @@ -269,7 +269,7 @@ export class PlaywrightTest {
}

private async _runNode(args: string[], cwd: string): Promise<string> {
return await spawnAsync(await findNode(), args, cwd, this._envProvider());
return await spawnAsync(await findNode(this._vscode), args, cwd, this._envProvider());
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/reusedBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class ReusedBrowser implements vscodeTypes.Disposable {
return;
}

const node = await findNode();
const node = await findNode(this._vscode);
const allArgs = [
config.cli,
'run-server',
Expand Down
2 changes: 1 addition & 1 deletion src/traceViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class TraceViewer implements vscodeTypes.Disposable {
}

private async _startIfNeeded(config: TestConfig, file: string) {
const node = await findNode();
const node = await findNode(this._vscode);
if (this._traceViewerProcess)
return;
const allArgs = [config.cli, 'show-trace', `--stdin`];
Expand Down
36 changes: 33 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import fs from 'fs';
import path from 'path';
import readline from 'readline';
import which from 'which';
import * as vscodeTypes from './vscodeTypes';

export function calculateSha1(buffer: Buffer | string): string {
const hash = crypto.createHash('sha1');
Expand Down Expand Up @@ -138,18 +139,47 @@ export async function resolveSourceMap(file: string, fileToSources: Map<string,

let pathToNodeJS: string | undefined;

export async function findNode(): Promise<string> {
export async function findNode(vscode: vscodeTypes.VSCode): Promise<string> {
if (pathToNodeJS)
return pathToNodeJS;

// Stage 1: Try to find Node.js via process.env.PATH
let node = await which('node').catch(e => undefined);
// When extension host boots, it does not have the right env set, so we might need to wait.
// Stage 2: When extension host boots, it does not have the right env set, so we might need to wait.
for (let i = 0; i < 5 && !node; ++i) {
await new Promise(f => setTimeout(f, 1000));
await new Promise(f => setTimeout(f, 200));
node = await which('node').catch(e => undefined);
}
// Stage 3: If we still haven't found Node.js, try to find it via a subprocess.
// This evaluates shell rc/profile files and makes nvm work.
node ??= await findNodeViaShell(vscode);
if (!node)
throw new Error('Unable to launch `node`, make sure it is in your PATH');
pathToNodeJS = node;
return node;
}

async function findNodeViaShell(vscode: vscodeTypes.VSCode): Promise<string | undefined> {
if (process.platform === 'win32')
return undefined;
return new Promise<string | undefined>(resolve => {
const startToken = '___START_PW_SHELL__';
const endToken = '___END_PW_SHELL__';
const childProcess = spawn(`${vscode.env.shell} -i -c 'echo ${startToken} && which node && echo ${endToken}'`, {
stdio: 'pipe',
shell: true
});
let output = '';
childProcess.stdout.on('data', data => output += data.toString());
childProcess.on('error', () => resolve(undefined));
childProcess.on('exit', exitCode => {
if (exitCode !== 0)
return resolve(undefined);
const start = output.indexOf(startToken);
const end = output.indexOf(endToken);
if (start === -1 || end === -1)
return resolve(undefined);
return resolve(output.substring(start + startToken.length, end).trim());
});
});
}

0 comments on commit f025947

Please sign in to comment.