@microsoft/rush
Version:
A professional solution for consolidating all your JavaScript projects in one Git repo
80 lines • 4.76 kB
JavaScript
// 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