From 2412f8c6cfaadd769af9d81a813c60c7c0768fa4 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 26 May 2017 07:06:11 -0700 Subject: [PATCH] Allow configurable npmLocation for typingsInstaller (#16084) * Allow configurable npmLocation for typingsInstaller * Undo "export class" changes * Add log for npmLocation * Log whether '--npmLocation' was provided --- src/server/server.ts | 36 +++++++++++-------- src/server/shared.ts | 7 +++- .../typingsInstaller/nodeTypingsInstaller.ts | 11 +++--- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/server/server.ts b/src/server/server.ts index ed3e2dd820..390a0f2f6f 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -13,6 +13,7 @@ namespace ts.server { globalTypingsCacheLocation: string; logger: Logger; typingSafeListLocation: string; + npmLocation: string | undefined; telemetryEnabled: boolean; globalPlugins: string[]; pluginProbeLocations: string[]; @@ -234,6 +235,7 @@ namespace ts.server { eventPort: number, readonly globalTypingsCacheLocation: string, readonly typingSafeListLocation: string, + private readonly npmLocation: string | undefined, private newLine: string) { this.throttledOperations = new ThrottledOperations(host); if (eventPort) { @@ -278,19 +280,21 @@ namespace ts.server { if (this.typingSafeListLocation) { args.push(Arguments.TypingSafeListLocation, this.typingSafeListLocation); } + if (this.npmLocation) { + args.push(Arguments.NpmLocation, this.npmLocation); + } + const execArgv: string[] = []; - { - for (const arg of process.execArgv) { - const match = /^--(debug|inspect)(=(\d+))?$/.exec(arg); - if (match) { - // if port is specified - use port + 1 - // otherwise pick a default port depending on if 'debug' or 'inspect' and use its value + 1 - const currentPort = match[3] !== undefined - ? +match[3] - : match[1] === "debug" ? 5858 : 9229; - execArgv.push(`--${match[1]}=${currentPort + 1}`); - break; - } + for (const arg of process.execArgv) { + const match = /^--(debug|inspect)(=(\d+))?$/.exec(arg); + if (match) { + // if port is specified - use port + 1 + // otherwise pick a default port depending on if 'debug' or 'inspect' and use its value + 1 + const currentPort = match[3] !== undefined + ? +match[3] + : match[1] === "debug" ? 5858 : 9229; + execArgv.push(`--${match[1]}=${currentPort + 1}`); + break; } } @@ -389,10 +393,10 @@ namespace ts.server { class IOSession extends Session { constructor(options: IOSessionOptions) { - const { host, installerEventPort, globalTypingsCacheLocation, typingSafeListLocation, canUseEvents } = options; + const { host, installerEventPort, globalTypingsCacheLocation, typingSafeListLocation, npmLocation, canUseEvents } = options; const typingsInstaller = disableAutomaticTypingAcquisition ? undefined - : new NodeTypingsInstaller(telemetryEnabled, logger, host, installerEventPort, globalTypingsCacheLocation, typingSafeListLocation, host.newLine); + : new NodeTypingsInstaller(telemetryEnabled, logger, host, installerEventPort, globalTypingsCacheLocation, typingSafeListLocation, npmLocation, host.newLine); super({ host, @@ -741,7 +745,8 @@ namespace ts.server { validateLocaleAndSetLanguage(localeStr, sys); } - const typingSafeListLocation = findArgument("--typingSafeListLocation"); + const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation); + const npmLocation = findArgument(Arguments.NpmLocation); const globalPlugins = (findArgument("--globalPlugins") || "").split(","); const pluginProbeLocations = (findArgument("--pluginProbeLocations") || "").split(","); @@ -760,6 +765,7 @@ namespace ts.server { disableAutomaticTypingAcquisition, globalTypingsCacheLocation: getGlobalTypingsCacheLocation(), typingSafeListLocation, + npmLocation, telemetryEnabled, logger, globalPlugins, diff --git a/src/server/shared.ts b/src/server/shared.ts index 6dcf888192..1285eba06e 100644 --- a/src/server/shared.ts +++ b/src/server/shared.ts @@ -12,13 +12,18 @@ namespace ts.server { export const LogFile = "--logFile"; export const EnableTelemetry = "--enableTelemetry"; export const TypingSafeListLocation = "--typingSafeListLocation"; + /** + * This argument specifies the location of the NPM executable. + * typingsInstaller will run the command with `${npmLocation} install ...`. + */ + export const NpmLocation = "--npmLocation"; } export function hasArgument(argumentName: string) { return sys.args.indexOf(argumentName) >= 0; } - export function findArgument(argumentName: string) { + export function findArgument(argumentName: string): string | undefined { const index = sys.args.indexOf(argumentName); return index >= 0 && index < sys.args.length - 1 ? sys.args[index + 1] diff --git a/src/server/typingsInstaller/nodeTypingsInstaller.ts b/src/server/typingsInstaller/nodeTypingsInstaller.ts index 1182450ce8..797962cba0 100644 --- a/src/server/typingsInstaller/nodeTypingsInstaller.ts +++ b/src/server/typingsInstaller/nodeTypingsInstaller.ts @@ -30,7 +30,8 @@ namespace ts.server.typingsInstaller { } } - function getNPMLocation(processName: string) { + /** Used if `--npmLocation` is not passed. */ + function getDefaultNPMLocation(processName: string) { if (path.basename(processName).indexOf("node") === 0) { return `"${path.join(path.dirname(process.argv[0]), "npm")}"`; } @@ -76,17 +77,18 @@ namespace ts.server.typingsInstaller { private delayedInitializationError: InitializationFailedResponse; - constructor(globalTypingsCacheLocation: string, typingSafeListLocation: string, throttleLimit: number, log: Log) { + constructor(globalTypingsCacheLocation: string, typingSafeListLocation: string, npmLocation: string | undefined, throttleLimit: number, log: Log) { super( sys, globalTypingsCacheLocation, typingSafeListLocation ? toPath(typingSafeListLocation, "", createGetCanonicalFileName(sys.useCaseSensitiveFileNames)) : toPath("typingSafeList.json", __dirname, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)), throttleLimit, log); + this.npmPath = npmLocation !== undefined ? npmLocation : getDefaultNPMLocation(process.argv[0]); if (this.log.isEnabled()) { this.log.writeLine(`Process id: ${process.pid}`); + this.log.writeLine(`NPM location: ${this.npmPath} (explicit '${Arguments.NpmLocation}' ${npmLocation === undefined ? "not " : ""} provided)`); } - this.npmPath = getNPMLocation(process.argv[0]); ({ execSync: this.execSync } = require("child_process")); this.ensurePackageDirectoryExists(globalTypingsCacheLocation); @@ -168,6 +170,7 @@ namespace ts.server.typingsInstaller { const logFilePath = findArgument(server.Arguments.LogFile); const globalTypingsCacheLocation = findArgument(server.Arguments.GlobalCacheLocation); const typingSafeListLocation = findArgument(server.Arguments.TypingSafeListLocation); + const npmLocation = findArgument(server.Arguments.NpmLocation); const log = new FileLog(logFilePath); if (log.isEnabled()) { @@ -181,6 +184,6 @@ namespace ts.server.typingsInstaller { } process.exit(0); }); - const installer = new NodeTypingsInstaller(globalTypingsCacheLocation, typingSafeListLocation, /*throttleLimit*/5, log); + const installer = new NodeTypingsInstaller(globalTypingsCacheLocation, typingSafeListLocation, npmLocation, /*throttleLimit*/5, log); installer.listen(); } \ No newline at end of file