in apps/rush-lib/src/logic/installManager/RushInstallManager.ts [445:631]
protected async installAsync(cleanInstall: boolean): Promise<void> {
// Since we are actually running npm/pnpm/yarn install, recreate all the temp project tarballs.
// This ensures that any existing tarballs with older header bits will be regenerated.
// It is safe to assume that temp project pacakge.jsons already exist.
for (const rushProject of this.rushConfiguration.projects) {
this._tempProjectHelper.createTempProjectTarball(rushProject);
}
// NOTE: The PNPM store is supposed to be transactionally safe, so we don't delete it automatically.
// The user must request that via the command line.
if (cleanInstall) {
if (this.rushConfiguration.packageManager === 'npm') {
console.log(`Deleting the "npm-cache" folder`);
// This is faster and more thorough than "npm cache clean"
this.installRecycler.moveFolder(this.rushConfiguration.npmCacheFolder);
console.log(`Deleting the "npm-tmp" folder`);
this.installRecycler.moveFolder(this.rushConfiguration.npmTmpFolder);
}
}
// Example: "C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm"
const packageManagerFilename: string = this.rushConfiguration.packageManagerToolFilename;
const packageManagerEnv: NodeJS.ProcessEnv = InstallHelpers.getPackageManagerEnvironment(
this.rushConfiguration,
this.options
);
const commonNodeModulesFolder: string = path.join(
this.rushConfiguration.commonTempFolder,
RushConstants.nodeModulesFolderName
);
// Is there an existing "node_modules" folder to consider?
if (FileSystem.exists(commonNodeModulesFolder)) {
// Should we delete the entire "node_modules" folder?
if (cleanInstall) {
// YES: Delete "node_modules"
// Explain to the user why we are hosing their node_modules folder
console.log('Deleting files from ' + commonNodeModulesFolder);
this.installRecycler.moveFolder(commonNodeModulesFolder);
Utilities.createFolderWithRetry(commonNodeModulesFolder);
} else {
// NO: Prepare to do an incremental install in the "node_modules" folder
// note: it is not necessary to run "prune" with pnpm
if (this.rushConfiguration.packageManager === 'npm') {
console.log(
`Running "${this.rushConfiguration.packageManager} prune"` +
` in ${this.rushConfiguration.commonTempFolder}`
);
const args: string[] = ['prune'];
this.pushConfigurationArgs(args, this.options);
Utilities.executeCommandWithRetry(
{
command: packageManagerFilename,
args: args,
workingDirectory: this.rushConfiguration.commonTempFolder,
environment: packageManagerEnv
},
this.options.maxInstallAttempts
);
// Delete the (installed image of) the temp projects, since "npm install" does not
// detect changes for "file:./" references.
// We recognize the temp projects by their names, which always start with "rush-".
// Example: "C:\MyRepo\common\temp\node_modules\@rush-temp"
const pathToDeleteWithoutStar: string = path.join(
commonNodeModulesFolder,
RushConstants.rushTempNpmScope
);
console.log(`Deleting ${pathToDeleteWithoutStar}\\*`);
// Glob can't handle Windows paths
const normalizedpathToDeleteWithoutStar: string = Text.replaceAll(
pathToDeleteWithoutStar,
'\\',
'/'
);
// Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/*"
for (const tempModulePath of glob.sync(globEscape(normalizedpathToDeleteWithoutStar) + '/*')) {
// We could potentially use AsyncRecycler here, but in practice these folders tend
// to be very small
Utilities.dangerouslyDeletePath(tempModulePath);
}
}
}
}
if (this.rushConfiguration.packageManager === 'yarn') {
// Yarn does not correctly detect changes to a tarball, so we need to forcibly clear its cache
const yarnRushTempCacheFolder: string = path.join(
this.rushConfiguration.yarnCacheFolder,
'v2',
'npm-@rush-temp'
);
if (FileSystem.exists(yarnRushTempCacheFolder)) {
console.log('Deleting ' + yarnRushTempCacheFolder);
Utilities.dangerouslyDeletePath(yarnRushTempCacheFolder);
}
}
// Run "npm install" in the common folder
const installArgs: string[] = ['install'];
this.pushConfigurationArgs(installArgs, this.options);
console.log(
os.EOL +
colors.bold(
`Running "${this.rushConfiguration.packageManager} install" in` +
` ${this.rushConfiguration.commonTempFolder}`
) +
os.EOL
);
// If any diagnostic options were specified, then show the full command-line
if (this.options.debug || this.options.collectLogFile || this.options.networkConcurrency) {
console.log(
os.EOL +
colors.green('Invoking package manager: ') +
FileSystem.getRealPath(packageManagerFilename) +
' ' +
installArgs.join(' ') +
os.EOL
);
}
try {
Utilities.executeCommandWithRetry(
{
command: packageManagerFilename,
args: installArgs,
workingDirectory: this.rushConfiguration.commonTempFolder,
environment: packageManagerEnv,
suppressOutput: false
},
this.options.maxInstallAttempts,
() => {
if (this.rushConfiguration.packageManager === 'pnpm') {
console.log(colors.yellow(`Deleting the "node_modules" folder`));
this.installRecycler.moveFolder(commonNodeModulesFolder);
// Leave the pnpm-store as is for the retry. This ensures that packages that have already
// been downloaded need not be downloaded again, thereby potentially increasing the chances
// of a subsequent successful install.
Utilities.createFolderWithRetry(commonNodeModulesFolder);
}
}
);
} catch (error) {
// All the install attempts failed.
if (
this.rushConfiguration.packageManager === 'pnpm' &&
this.rushConfiguration.pnpmOptions.pnpmStore === 'local'
) {
// If the installation has failed even after the retries, then pnpm store may
// have got into a corrupted, irrecoverable state. Delete the store so that a
// future install can create the store afresh.
console.log(colors.yellow(`Deleting the "pnpm-store" folder`));
this.installRecycler.moveFolder(this.rushConfiguration.pnpmOptions.pnpmStorePath);
}
throw error;
}
if (this.rushConfiguration.packageManager === 'npm') {
console.log(os.EOL + colors.bold('Running "npm shrinkwrap"...'));
const npmArgs: string[] = ['shrinkwrap'];
this.pushConfigurationArgs(npmArgs, this.options);
Utilities.executeCommand({
command: this.rushConfiguration.packageManagerToolFilename,
args: npmArgs,
workingDirectory: this.rushConfiguration.commonTempFolder
});
console.log('"npm shrinkwrap" completed' + os.EOL);
this._fixupNpm5Regression();
}
}