Skip to content

Commit b3d83c8

Browse files
committed
Handle command too long failure in typings installer
1 parent b363240 commit b3d83c8

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

src/harness/unittests/typingsInstaller.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,4 +1593,32 @@ namespace ts.projectSystem {
15931593
checkProjectActualFiles(projectService.inferredProjects[0], [f1.path]);
15941594
});
15951595
});
1596+
1597+
describe("typing installer's npm installation command", () => {
1598+
const npmPath = "npm", tsVersion = "2.9.0-dev.20180410";
1599+
const packageNames = ["@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]", "@types/[email protected]"];
1600+
const expectedCommands = [
1601+
TI.getNpmCommandForInstallation(npmPath, tsVersion, packageNames, packageNames.length).command,
1602+
TI.getNpmCommandForInstallation(npmPath, tsVersion, packageNames, packageNames.length - Math.ceil(packageNames.length / 2)).command
1603+
];
1604+
it("works when the command is too long to install all packages at once", () => {
1605+
const commands: string[] = [];
1606+
const hasError = TI.installNpmPackages(npmPath, tsVersion, packageNames, command => {
1607+
commands.push(command);
1608+
return false;
1609+
});
1610+
assert.isFalse(hasError);
1611+
assert.deepEqual(commands, expectedCommands, "commands");
1612+
});
1613+
1614+
it("installs remaining packages when one of the partial command fails", () => {
1615+
const commands: string[] = [];
1616+
const hasError = TI.installNpmPackages(npmPath, tsVersion, packageNames, command => {
1617+
commands.push(command);
1618+
return commands.length === 1;
1619+
});
1620+
assert.isTrue(hasError);
1621+
assert.deepEqual(commands, expectedCommands, "commands");
1622+
});
1623+
});
15961624
}

src/server/typingsInstaller/nodeTypingsInstaller.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,8 @@ namespace ts.server.typingsInstaller {
184184
if (this.log.isEnabled()) {
185185
this.log.writeLine(`#${requestId} with arguments'${JSON.stringify(packageNames)}'.`);
186186
}
187-
const command = `${this.npmPath} install --ignore-scripts ${packageNames.join(" ")} --save-dev --user-agent="typesInstaller/${version}"`;
188187
const start = Date.now();
189-
const hasError = this.execSyncAndLog(command, { cwd });
188+
const hasError = installNpmPackages(this.npmPath, version, packageNames, command => this.execSyncAndLog(command, { cwd }));
190189
if (this.log.isEnabled()) {
191190
this.log.writeLine(`npm install #${requestId} took: ${Date.now() - start} ms`);
192191
}

src/server/typingsInstaller/typingsInstaller.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,31 @@ namespace ts.server.typingsInstaller {
3030
}
3131
}
3232

33+
/*@internal*/
34+
export function installNpmPackages(npmPath: string, tsVersion: string, packageNames: string[], install: (command: string) => boolean) {
35+
let hasError = false;
36+
for (let remaining = packageNames.length; remaining > 0;) {
37+
const result = getNpmCommandForInstallation(npmPath, tsVersion, packageNames, remaining);
38+
remaining = result.remaining;
39+
hasError = install(result.command) || hasError;
40+
}
41+
return hasError;
42+
}
43+
44+
/*@internal*/
45+
export function getNpmCommandForInstallation(npmPath: string, tsVersion: string, packageNames: string[], remaining: number) {
46+
const sliceStart = packageNames.length - remaining;
47+
let command: string, toSlice = remaining;
48+
while (true) {
49+
command = `${npmPath} install --ignore-scripts ${(toSlice === packageNames.length ? packageNames : packageNames.slice(sliceStart, sliceStart + toSlice)).join(" ")} --save-dev --user-agent="typesInstaller/${tsVersion}"`;
50+
if (command.length < 8000) {
51+
break;
52+
}
53+
54+
toSlice = toSlice - Math.floor(toSlice / 2);
55+
}
56+
return { command, remaining: remaining - toSlice };
57+
}
3358

3459
export type RequestCompletedAction = (success: boolean) => void;
3560
interface PendingRequest {

0 commit comments

Comments
 (0)