UNPKG

@microsoft/rush

Version:

A professional solution for consolidating all your JavaScript projects in one Git repo

80 lines 4.76 kB
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. import * as path from 'node:path'; import * as semver from 'semver'; import { LockFile, Import } from '@rushstack/node-core-library'; import { Utilities } from '@microsoft/rush-lib/lib/utilities/Utilities'; import { _FlagFile, _RushGlobalFolder } from '@microsoft/rush-lib'; import { RushCommandSelector } from './RushCommandSelector'; const MAX_INSTALL_ATTEMPTS = 3; export class RushVersionSelector { constructor(currentPackageVersion) { this._rushGlobalFolder = new _RushGlobalFolder(); this._currentPackageVersion = currentPackageVersion; } async ensureRushVersionInstalledAsync(version, configuration, executeOptions) { const isLegacyRushVersion = semver.lt(version, '4.0.0'); const expectedRushPath = path.join(this._rushGlobalFolder.nodeSpecificPath, `rush-${version}`); const installMarker = new _FlagFile(expectedRushPath, 'last-install', { node: process.versions.node }); let installIsValid = await installMarker.isValidAsync(); if (!installIsValid) { // Need to install Rush console.log(`Rush version ${version} is not currently installed. Installing...`); const resourceName = `rush-${version}`; console.log(`Trying to acquire lock for ${resourceName}`); const lock = await LockFile.acquireAsync(expectedRushPath, resourceName); installIsValid = await installMarker.isValidAsync(); if (installIsValid) { console.log('Another process performed the installation.'); } else { await Utilities.installPackageInDirectoryAsync({ directory: expectedRushPath, packageName: isLegacyRushVersion ? '@microsoft/rush' : '@microsoft/rush-lib', version: version, tempPackageTitle: 'rush-local-install', maxInstallAttempts: MAX_INSTALL_ATTEMPTS, // This is using a local configuration to install a package in a shared global location. // Generally that's a bad practice, but in this case if we can successfully install // the package at all, we can reasonably assume it's good for all the repositories. // In particular, we'll assume that two different NPM registries cannot have two // different implementations of the same version of the same package. // This was needed for: https://github.com/microsoft/rushstack/issues/691 commonRushConfigFolder: configuration ? configuration.commonRushConfigFolder : undefined, suppressOutput: true }); console.log(`Successfully installed Rush version ${version} in ${expectedRushPath}.`); // If we've made it here without exception, write the flag file await installMarker.createAsync(); lock.release(); } } if (semver.lt(version, '3.0.20')) { // In old versions, requiring the entry point invoked the command-line parser immediately, // so fail if "rushx" or "rush-pnpm" was used RushCommandSelector.failIfNotInvokedAsRush(version); require(path.join(expectedRushPath, 'node_modules', '@microsoft', 'rush', 'lib', 'rush')); } else if (semver.lt(version, '4.0.0')) { // In old versions, requiring the entry point invoked the command-line parser immediately, // so fail if "rushx" or "rush-pnpm" was used RushCommandSelector.failIfNotInvokedAsRush(version); require(path.join(expectedRushPath, 'node_modules', '@microsoft', 'rush', 'lib', 'start')); } else { // Explicitly resolve the entry point for rush-lib, rather than using a simple require, because // newer versions of rush-lib use the package.json `exports` field, which maps // `lib/index` to `lib-commonjs/index.js` const rushLibEntrypoint = await Import.resolveModuleAsync({ modulePath: '@microsoft/rush-lib/lib/index', baseFolderPath: expectedRushPath }); const rushCliEntrypoint = require(rushLibEntrypoint); // For newer rush-lib, RushCommandSelector can test whether "rushx" is supported or not RushCommandSelector.execute(this._currentPackageVersion, rushCliEntrypoint, executeOptions); } } } //# sourceMappingURL=RushVersionSelector.js.map