diff --git a/common/changes/@microsoft/rush/fix-rush-bug_2022-09-28-20-55.json b/common/changes/@microsoft/rush/fix-rush-bug_2022-09-28-20-55.json new file mode 100644 index 00000000000..0b148a1ac80 --- /dev/null +++ b/common/changes/@microsoft/rush/fix-rush-bug_2022-09-28-20-55.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Fix an error message that always says to run \"rush update --purge\" even if the user only needs to run \"rush install --purge.\"", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/changes/@microsoft/rush/main_2022-09-28-20-46.json b/common/changes/@microsoft/rush/main_2022-09-28-20-46.json new file mode 100644 index 00000000000..ec9292780e3 --- /dev/null +++ b/common/changes/@microsoft/rush/main_2022-09-28-20-46.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Fix an issue where a \"Current PNPM store path does not match the last one used.\" error will erroneously get thrown on Windows with an unchanged path, but with a forward slash instead of a backslash.", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/changes/@rushstack/node-core-library/main_2022-09-28-20-46.json b/common/changes/@rushstack/node-core-library/main_2022-09-28-20-46.json new file mode 100644 index 00000000000..0b9eac753d2 --- /dev/null +++ b/common/changes/@rushstack/node-core-library/main_2022-09-28-20-46.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/node-core-library", + "comment": "Add a Path.convertToPlatformDefault API to convert a path to use the platform-default slashes.", + "type": "minor" + } + ], + "packageName": "@rushstack/node-core-library" +} \ No newline at end of file diff --git a/common/reviews/api/node-core-library.api.md b/common/reviews/api/node-core-library.api.md index 9207013425b..2c01fe5142c 100644 --- a/common/reviews/api/node-core-library.api.md +++ b/common/reviews/api/node-core-library.api.md @@ -781,6 +781,7 @@ export class PackageNameParser { // @public export class Path { static convertToBackslashes(inputPath: string): string; + static convertToPlatformDefault(inputPath: string): string; static convertToSlashes(inputPath: string): string; static formatConcisely(options: IPathFormatConciselyOptions): string; static formatFileLocation(options: IPathFormatFileLocationOptions): string; diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 09ce5c202cb..111da3cf7d1 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -526,7 +526,7 @@ export interface _IYarnOptionsJson extends IPackageManagerOptionsJsonBase { // @internal export class _LastInstallFlag { constructor(folderPath: string, state?: JsonObject); - checkValidAndReportStoreIssues(): boolean; + checkValidAndReportStoreIssues(rushVerb: string): boolean; clear(): void; create(): void; protected get flagName(): string; diff --git a/libraries/node-core-library/src/Path.ts b/libraries/node-core-library/src/Path.ts index b25d7e83b88..6ebcb907795 100644 --- a/libraries/node-core-library/src/Path.ts +++ b/libraries/node-core-library/src/Path.ts @@ -229,6 +229,12 @@ export class Path { public static convertToBackslashes(inputPath: string): string { return inputPath.replace(/\//g, '\\'); } + /** + * Replaces slashes or backslashes with the appropriate slash for the current operating system. + */ + public static convertToPlatformDefault(inputPath: string): string { + return path.sep === '/' ? Path.convertToSlashes(inputPath) : Path.convertToBackslashes(inputPath); + } /** * Returns true if the specified path is a relative path and does not use `..` to walk upwards. diff --git a/libraries/rush-lib/src/api/LastInstallFlag.ts b/libraries/rush-lib/src/api/LastInstallFlag.ts index 5631834482c..5808e3dc73a 100644 --- a/libraries/rush-lib/src/api/LastInstallFlag.ts +++ b/libraries/rush-lib/src/api/LastInstallFlag.ts @@ -3,7 +3,7 @@ import * as path from 'path'; -import { FileSystem, JsonFile, JsonObject, Import } from '@rushstack/node-core-library'; +import { FileSystem, JsonFile, JsonObject, Import, Path } from '@rushstack/node-core-library'; import { PackageManagerName } from './packageManager/PackageManager'; import { RushConfiguration } from './RushConfiguration'; @@ -46,11 +46,13 @@ export class LastInstallFlag { * * @internal */ - public checkValidAndReportStoreIssues(): boolean { - return this._isValid(true); + public checkValidAndReportStoreIssues(rushVerb: string): boolean { + return this._isValid(true, rushVerb); } - private _isValid(checkValidAndReportStoreIssues: boolean): boolean { + private _isValid(checkValidAndReportStoreIssues: false, rushVerb?: string): boolean; + private _isValid(checkValidAndReportStoreIssues: true, rushVerb: string): boolean; + private _isValid(checkValidAndReportStoreIssues: boolean, rushVerb: string = 'update'): boolean { let oldState: JsonObject; try { oldState = JsonFile.load(this._path); @@ -66,19 +68,25 @@ export class LastInstallFlag { if (pkgManager === 'pnpm') { if ( // Only throw an error if the package manager hasn't changed from PNPM - oldState.packageManager === pkgManager && - // Throw if the store path changed - oldState.storePath !== newState.storePath + oldState.packageManager === pkgManager ) { - const oldStorePath: string = oldState.storePath || ''; - const newStorePath: string = newState.storePath || ''; - - throw new Error( - 'Current PNPM store path does not match the last one used. This may cause inconsistency in your builds.\n\n' + - 'If you wish to install with the new store path, please run "rush update --purge"\n\n' + - `Old Path: ${oldStorePath}\n` + - `New Path: ${newStorePath}` - ); + const normalizedOldStorePath: string = oldState.storePath + ? Path.convertToPlatformDefault(oldState.storePath) + : ''; + const normalizedNewStorePath: string = newState.storePath + ? Path.convertToPlatformDefault(newState.storePath) + : ''; + if ( + // Throw if the store path changed + normalizedOldStorePath !== normalizedNewStorePath + ) { + throw new Error( + 'Current PNPM store path does not match the last one used. This may cause inconsistency in your builds.\n\n' + + `If you wish to install with the new store path, please run "rush ${rushVerb} --purge"\n\n` + + `Old Path: ${normalizedOldStorePath}\n` + + `New Path: ${normalizedNewStorePath}` + ); + } } } } diff --git a/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts b/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts index 136f99ced8b..291366c1bde 100644 --- a/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts +++ b/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts @@ -82,7 +82,7 @@ describe(LastInstallFlag.name, () => { flag1.create(); expect(() => { - flag2.checkValidAndReportStoreIssues(); + flag2.checkValidAndReportStoreIssues('install'); }).toThrowError(/PNPM store path/); }); @@ -97,8 +97,8 @@ describe(LastInstallFlag.name, () => { flag1.create(); expect(() => { - flag2.checkValidAndReportStoreIssues(); + flag2.checkValidAndReportStoreIssues('install'); }).not.toThrow(); - expect(flag2.checkValidAndReportStoreIssues()).toEqual(false); + expect(flag2.checkValidAndReportStoreIssues('install')).toEqual(false); }); }); diff --git a/libraries/rush-lib/src/logic/base/BaseInstallManager.ts b/libraries/rush-lib/src/logic/base/BaseInstallManager.ts index 43d6b67ad40..ef29e819b6b 100644 --- a/libraries/rush-lib/src/logic/base/BaseInstallManager.ts +++ b/libraries/rush-lib/src/logic/base/BaseInstallManager.ts @@ -217,7 +217,10 @@ export abstract class BaseInstallManager { // "--purge" was specified, or if the last install was interrupted, then we will // need to perform a clean install. Otherwise, we can do an incremental install. const cleanInstall: boolean = - isFilteredInstall || !this._commonTempInstallFlag.checkValidAndReportStoreIssues(); + isFilteredInstall || + !this._commonTempInstallFlag.checkValidAndReportStoreIssues( + this.options.allowShrinkwrapUpdates ? 'update' : 'install' + ); // Allow us to defer the file read until we need it const canSkipInstall: () => boolean = () => {