in packages/libs/extension/src/main.ts [413:498]
public async start(extension: Extension, enableDebugger = false): Promise<ChildProcess> {
const PathVar = getPathVariableName();
await this.validateExtensionSystemRequirements(extension);
if (!extension.definition.scripts) {
throw new MissingStartCommandException(extension);
}
const script =
enableDebugger && extension.definition.scripts.debug
? extension.definition.scripts.debug
: extension.definition.scripts.start;
// look at the extension for the
if (!script) {
throw new MissingStartCommandException(extension);
}
const command = cmdlineToArray(script);
if (command.length === 0) {
throw new MissingStartCommandException(extension);
}
// add each engine into the front of the path.
const env = { ...process.env };
// add potential .bin folders (depends on platform and npm version)
env[PathVar] = `${join(extension.modulePath, "node_modules", ".bin")}${delimiter}${env[PathVar]}`;
env[PathVar] = `${join(extension.location, "node_modules", ".bin")}${delimiter}${env[PathVar]}`;
// find appropriate path for interpreter
switch (command[0].toLowerCase()) {
case "node":
case "node.exe":
command[0] = nodePath;
break;
case "python":
case "python.exe":
case "python3":
case "python3.exe":
await patchPythonPath(command as PythonCommandLine, { version: ">=3.6" });
break;
}
// ensure parameters requiring quotes have them.
for (let i = 0; i < command.length; i++) {
command[i] = quoteIfNecessary(command[i]);
}
// spawn the command via the shell (since that how npm would have done it anyway.)
const fullCommandPath = await getFullPath(command[0], env[getPathVariableName()]);
if (!fullCommandPath) {
throw new Exception(
`Unable to resolve full path for executable '${command[0]}' -- (cmdline '${command.join(" ")}')`,
);
}
// == special case ==
// on Windows, if this command has a space in the name, and it's not an .EXE
// then we're going to have to add the folder to the PATH
// and execute it by just the filename
// and set the path back when we're done.
if (process.platform === "win32" && fullCommandPath.indexOf(" ") > -1 && !/.exe$/gi.exec(fullCommandPath)) {
// preserve the current path
const originalPath = process.env[PathVar];
try {
// insert the dir into the path
process.env[PathVar] = `${dirname(fullCommandPath)}${delimiter}${env[PathVar]}`;
// call spawn and return
return spawn(basename(fullCommandPath), command.slice(1), {
env,
cwd: extension.modulePath,
stdio: ["pipe", "pipe", "pipe"],
});
} finally {
// regardless, restore the original path on the way out!
process.env[PathVar] = originalPath;
}
}
return spawn(fullCommandPath, command.slice(1), {
env,
cwd: extension.modulePath,
stdio: ["pipe", "pipe", "pipe"],
});
}