Skip to content

Commit e169cba

Browse files
committed
revert build cache integration
1 parent c8c1bb7 commit e169cba

6 files changed

Lines changed: 87 additions & 124 deletions

File tree

common/changes/@microsoft/rush/bmiddha-zipsync-3_2025-09-16-00-42.json

Lines changed: 0 additions & 10 deletions
This file was deleted.

common/config/subspaces/build-tests-subspace/repo-state.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
{
33
"pnpmShrinkwrapHash": "2ac01ba33e09661dc0e7d7faa36d215bb3d3b91e",
44
"preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9",
5-
"packageJsonInjectedDependenciesHash": "73ac91f09601cd919fddc7f1d193a03eab37102a"
5+
"packageJsonInjectedDependenciesHash": "79ac135cb61506457e8d49c7ec1342d419bde3e2"
66
}

common/config/subspaces/default/pnpm-lock.yaml

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libraries/rush-lib/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
"@rushstack/stream-collator": "workspace:*",
4343
"@rushstack/terminal": "workspace:*",
4444
"@rushstack/ts-command-line": "workspace:*",
45-
"@rushstack/zipsync": "workspace:*",
4645
"@yarnpkg/lockfile": "~1.0.2",
4746
"builtin-modules": "~3.1.0",
4847
"cli-table": "~0.3.1",

libraries/rush-lib/src/logic/RushConstants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ export class RushConstants {
226226
* Build cache version number, incremented when the logic to create cache entries changes.
227227
* Changing this ensures that cache entries generated by an old version will no longer register as a cache hit.
228228
*/
229-
public static readonly buildCacheVersion: 2 = 2;
229+
public static readonly buildCacheVersion: 1 = 1;
230230

231231
/**
232232
* Cobuild configuration file.

libraries/rush-lib/src/logic/buildCache/OperationBuildCache.ts

Lines changed: 85 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@
33

44
import * as path from 'path';
55
import * as crypto from 'crypto';
6-
import * as fs from 'fs';
76

87
import { FileSystem, type FolderItem, InternalError, Async } from '@rushstack/node-core-library';
98
import type { ITerminal } from '@rushstack/terminal';
10-
import { packWorkerAsync, type IZipSyncPackWorkerResult } from '@rushstack/zipsync/lib/packWorkerAsync';
11-
import { unpackWorkerAsync, type IZipSyncUnpackWorkerResult } from '@rushstack/zipsync/lib/unpackWorkerAsync';
129

1310
import type { RushConfigurationProject } from '../../api/RushConfigurationProject';
1411
import type { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration';
1512
import type { ICloudBuildCacheProvider } from './ICloudBuildCacheProvider';
1613
import type { FileSystemBuildCacheProvider } from './FileSystemBuildCacheProvider';
14+
import { TarExecutable } from '../../utilities/TarExecutable';
15+
import { EnvironmentVariableNames } from '../../api/EnvironmentConfiguration';
1716
import type { IOperationExecutionResult } from '../operations/IOperationExecutionResult';
1817

1918
/**
@@ -61,6 +60,8 @@ interface IPathsToCache {
6160
* @internal
6261
*/
6362
export class OperationBuildCache {
63+
private static _tarUtilityPromise: Promise<TarExecutable | undefined> | undefined;
64+
6465
private readonly _project: RushConfigurationProject;
6566
private readonly _localBuildCacheProvider: FileSystemBuildCacheProvider;
6667
private readonly _cloudBuildCacheProvider: ICloudBuildCacheProvider | undefined;
@@ -89,6 +90,14 @@ export class OperationBuildCache {
8990
this._cacheId = cacheId;
9091
}
9192

93+
private static _tryGetTarUtility(terminal: ITerminal): Promise<TarExecutable | undefined> {
94+
if (!OperationBuildCache._tarUtilityPromise) {
95+
OperationBuildCache._tarUtilityPromise = TarExecutable.tryInitializeAsync(terminal);
96+
}
97+
98+
return OperationBuildCache._tarUtilityPromise;
99+
}
100+
92101
public get cacheId(): string | undefined {
93102
return this._cacheId;
94103
}
@@ -167,52 +176,32 @@ export class OperationBuildCache {
167176

168177
const projectFolderPath: string = this._project.projectFolder;
169178

179+
// Purge output folders
180+
terminal.writeVerboseLine(`Clearing cached folders: ${this._projectOutputFolderNames.join(', ')}`);
181+
await Promise.all(
182+
this._projectOutputFolderNames.map((outputFolderName: string) =>
183+
FileSystem.deleteFolderAsync(`${projectFolderPath}/${outputFolderName}`)
184+
)
185+
);
186+
187+
const tarUtility: TarExecutable | undefined = await OperationBuildCache._tryGetTarUtility(terminal);
170188
let restoreSuccess: boolean = false;
171-
try {
172-
const logFilePath: string = this._getLogFilePath(cacheId, 'unpack');
173-
let unpackWorkerResult: IZipSyncUnpackWorkerResult;
174-
try {
175-
unpackWorkerResult = await unpackWorkerAsync({
176-
archivePath: localCacheEntryPath!,
177-
targetDirectories: this._projectOutputFolderNames,
178-
baseDir: projectFolderPath
179-
});
180-
} catch (e) {
181-
const { zipSyncLogs } = e as { zipSyncLogs: string | undefined };
182-
if (zipSyncLogs) {
183-
fs.writeFileSync(logFilePath, zipSyncLogs);
184-
terminal.writeVerboseLine(`The zipsync log has been written to: ${logFilePath}`);
185-
}
186-
throw e;
187-
}
188-
const {
189-
zipSyncReturn: { filesDeleted, filesExtracted, filesSkipped, foldersDeleted, otherEntriesDeleted },
190-
zipSyncLogs
191-
} = unpackWorkerResult;
192-
fs.writeFileSync(logFilePath, zipSyncLogs);
193-
terminal.writeVerboseLine(`The zipsync log has been written to: ${logFilePath}`);
194-
terminal.writeVerboseLine(`Restored ${filesExtracted + filesSkipped} files from cache.`);
195-
if (filesExtracted > 0) {
196-
terminal.writeVerboseLine(`Extracted ${filesExtracted} files to target folders.`);
197-
}
198-
if (filesSkipped > 0) {
199-
terminal.writeVerboseLine(`Skipped ${filesSkipped} files that were already up to date.`);
200-
}
201-
if (filesDeleted > 0) {
202-
terminal.writeVerboseLine(`Deleted ${filesDeleted} files from target folders.`);
203-
}
204-
if (foldersDeleted > 0) {
205-
terminal.writeVerboseLine(`Deleted ${foldersDeleted} empty folders from target folders.`);
206-
}
207-
if (otherEntriesDeleted > 0) {
208-
terminal.writeVerboseLine(
209-
`Deleted ${otherEntriesDeleted} items (e.g. symbolic links) from target folders.`
189+
if (tarUtility && localCacheEntryPath) {
190+
const logFilePath: string = this._getTarLogFilePath(cacheId, 'untar');
191+
const tarExitCode: number = await tarUtility.tryUntarAsync({
192+
archivePath: localCacheEntryPath,
193+
outputFolderPath: projectFolderPath,
194+
logFilePath
195+
});
196+
if (tarExitCode === 0) {
197+
restoreSuccess = true;
198+
terminal.writeLine('Successfully restored output from the build cache.');
199+
} else {
200+
terminal.writeWarningLine(
201+
'Unable to restore output from the build cache. ' +
202+
`See "${logFilePath}" for logs from the tar process.`
210203
);
211204
}
212-
restoreSuccess = true;
213-
terminal.writeLine('Successfully restored output from the build cache.');
214-
} catch (e) {
215-
terminal.writeWarningLine(`Unable to restore output from the build cache: ${e}`);
216205
}
217206

218207
if (updateLocalCacheSuccess === false) {
@@ -245,71 +234,59 @@ export class OperationBuildCache {
245234

246235
let localCacheEntryPath: string | undefined;
247236

248-
const finalLocalCacheEntryPath: string = this._localBuildCacheProvider.getCacheEntryPath(cacheId);
249-
250-
// Derive the temp file from the destination path to ensure they are on the same volume
251-
// In the case of a shared network drive containing the build cache, we also need to make
252-
// sure the the temp path won't be shared by two parallel rush builds.
253-
const randomSuffix: string = crypto.randomBytes(8).toString('hex');
254-
const tempLocalCacheEntryPath: string = `${finalLocalCacheEntryPath}-${randomSuffix}.temp`;
237+
const tarUtility: TarExecutable | undefined = await OperationBuildCache._tryGetTarUtility(terminal);
238+
if (tarUtility) {
239+
const finalLocalCacheEntryPath: string = this._localBuildCacheProvider.getCacheEntryPath(cacheId);
240+
241+
// Derive the temp file from the destination path to ensure they are on the same volume
242+
// In the case of a shared network drive containing the build cache, we also need to make
243+
// sure the the temp path won't be shared by two parallel rush builds.
244+
const randomSuffix: string = crypto.randomBytes(8).toString('hex');
245+
const tempLocalCacheEntryPath: string = `${finalLocalCacheEntryPath}-${randomSuffix}.temp`;
246+
247+
const logFilePath: string = this._getTarLogFilePath(cacheId, 'tar');
248+
const tarExitCode: number = await tarUtility.tryCreateArchiveFromProjectPathsAsync({
249+
archivePath: tempLocalCacheEntryPath,
250+
paths: filesToCache.outputFilePaths,
251+
project: this._project,
252+
logFilePath
253+
});
255254

256-
terminal.writeVerboseLine(`Using zipsync to create cache archive.`);
257-
try {
258-
const logFilePath: string = this._getLogFilePath(cacheId, 'pack');
259-
let packWorkerResult: IZipSyncPackWorkerResult;
260-
try {
261-
packWorkerResult = await packWorkerAsync({
262-
compression: 'auto',
263-
archivePath: tempLocalCacheEntryPath,
264-
targetDirectories: this._projectOutputFolderNames,
265-
baseDir: this._project.projectFolder
266-
});
267-
} catch (e) {
268-
const { zipSyncLogs } = e as { zipSyncLogs: string | undefined };
269-
if (zipSyncLogs) {
270-
fs.writeFileSync(logFilePath, zipSyncLogs);
271-
terminal.writeVerboseLine(`The zipsync log has been written to: ${logFilePath}`);
272-
}
273-
throw e;
274-
}
275-
const {
276-
zipSyncReturn: { filesPacked },
277-
zipSyncLogs
278-
} = packWorkerResult;
279-
fs.writeFileSync(logFilePath, zipSyncLogs);
280-
terminal.writeVerboseLine(`The zipsync log has been written to: ${logFilePath}`);
281-
terminal.writeVerboseLine(`Packed ${filesPacked} files for caching.`);
282-
283-
// Move after the archive is finished so that if the process is interrupted we aren't left with an invalid file
284-
try {
285-
await Async.runWithRetriesAsync({
286-
action: () =>
287-
new Promise<void>((resolve, reject) => {
288-
fs.rename(tempLocalCacheEntryPath, finalLocalCacheEntryPath, (err) => {
289-
if (err) {
290-
reject(err);
291-
} else {
292-
resolve();
293-
}
294-
});
295-
}),
296-
maxRetries: 2,
297-
retryDelayMs: 500
298-
});
299-
} catch (moveError) {
255+
if (tarExitCode === 0) {
256+
// Move after the archive is finished so that if the process is interrupted we aren't left with an invalid file
300257
try {
301-
await FileSystem.deleteFileAsync(tempLocalCacheEntryPath);
302-
} catch (deleteError) {
303-
// Ignored
258+
await Async.runWithRetriesAsync({
259+
action: () =>
260+
FileSystem.moveAsync({
261+
sourcePath: tempLocalCacheEntryPath,
262+
destinationPath: finalLocalCacheEntryPath,
263+
overwrite: true
264+
}),
265+
maxRetries: 2,
266+
retryDelayMs: 500
267+
});
268+
} catch (moveError) {
269+
try {
270+
await FileSystem.deleteFileAsync(tempLocalCacheEntryPath);
271+
} catch (deleteError) {
272+
// Ignored
273+
}
274+
throw moveError;
304275
}
305-
throw moveError;
276+
localCacheEntryPath = finalLocalCacheEntryPath;
277+
} else {
278+
terminal.writeWarningLine(
279+
`"tar" exited with code ${tarExitCode} while attempting to create the cache entry. ` +
280+
`See "${logFilePath}" for logs from the tar process.`
281+
);
282+
return false;
306283
}
307-
localCacheEntryPath = finalLocalCacheEntryPath;
308-
} catch (e) {
309-
await FileSystem.deleteFileAsync(tempLocalCacheEntryPath).catch(() => {
310-
/* ignore delete error */
311-
});
312-
throw e;
284+
} else {
285+
terminal.writeWarningLine(
286+
`Unable to locate "tar". Please ensure that "tar" is on your PATH environment variable, or set the ` +
287+
`${EnvironmentVariableNames.RUSH_TAR_BINARY_PATH} environment variable to the full path to the "tar" binary.`
288+
);
289+
return false;
313290
}
314291

315292
let cacheEntryBuffer: Buffer | undefined;
@@ -418,7 +395,7 @@ export class OperationBuildCache {
418395
};
419396
}
420397

421-
private _getLogFilePath(cacheId: string, mode: 'pack' | 'unpack'): string {
398+
private _getTarLogFilePath(cacheId: string, mode: 'tar' | 'untar'): string {
422399
return path.join(this._project.projectRushTempFolder, `${cacheId}.${mode}.log`);
423400
}
424401

0 commit comments

Comments
 (0)