@rushstack/zipsync 0.2.14 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +52 -0
- package/CHANGELOG.md +15 -1
- package/bin/zipsync +1 -1
- package/lib-esm/cli/ZipSyncCommandLineParser.js +93 -0
- package/lib-esm/cli/ZipSyncCommandLineParser.js.map +1 -0
- package/lib-esm/compress.js +115 -0
- package/lib-esm/compress.js.map +1 -0
- package/lib-esm/crc32.js +32 -0
- package/lib-esm/crc32.js.map +1 -0
- package/lib-esm/fs.js +48 -0
- package/lib-esm/fs.js.map +1 -0
- package/lib-esm/hash.js +39 -0
- package/lib-esm/hash.js.map +1 -0
- package/lib-esm/index.js +5 -0
- package/lib-esm/index.js.map +1 -0
- package/lib-esm/pack.js +379 -0
- package/lib-esm/pack.js.map +1 -0
- package/lib-esm/packWorker.js +58 -0
- package/lib-esm/packWorker.js.map +1 -0
- package/lib-esm/packWorkerAsync.js +43 -0
- package/lib-esm/packWorkerAsync.js.map +1 -0
- package/lib-esm/perf.js +49 -0
- package/lib-esm/perf.js.map +1 -0
- package/lib-esm/start.js +17 -0
- package/lib-esm/start.js.map +1 -0
- package/lib-esm/unpack.js +334 -0
- package/lib-esm/unpack.js.map +1 -0
- package/lib-esm/unpackWorker.js +54 -0
- package/lib-esm/unpackWorker.js.map +1 -0
- package/lib-esm/unpackWorkerAsync.js +43 -0
- package/lib-esm/unpackWorkerAsync.js.map +1 -0
- package/lib-esm/zipSyncUtils.js +6 -0
- package/lib-esm/zipSyncUtils.js.map +1 -0
- package/lib-esm/zipUtils.js +292 -0
- package/lib-esm/zipUtils.js.map +1 -0
- package/package.json +34 -5
- /package/{lib → lib-commonjs}/cli/ZipSyncCommandLineParser.js +0 -0
- /package/{lib → lib-commonjs}/cli/ZipSyncCommandLineParser.js.map +0 -0
- /package/{lib → lib-commonjs}/compress.js +0 -0
- /package/{lib → lib-commonjs}/compress.js.map +0 -0
- /package/{lib → lib-commonjs}/crc32.js +0 -0
- /package/{lib → lib-commonjs}/crc32.js.map +0 -0
- /package/{lib → lib-commonjs}/fs.js +0 -0
- /package/{lib → lib-commonjs}/fs.js.map +0 -0
- /package/{lib → lib-commonjs}/hash.js +0 -0
- /package/{lib → lib-commonjs}/hash.js.map +0 -0
- /package/{lib → lib-commonjs}/index.js +0 -0
- /package/{lib → lib-commonjs}/index.js.map +0 -0
- /package/{lib → lib-commonjs}/pack.js +0 -0
- /package/{lib → lib-commonjs}/pack.js.map +0 -0
- /package/{lib → lib-commonjs}/packWorker.js +0 -0
- /package/{lib → lib-commonjs}/packWorker.js.map +0 -0
- /package/{lib → lib-commonjs}/packWorkerAsync.js +0 -0
- /package/{lib → lib-commonjs}/packWorkerAsync.js.map +0 -0
- /package/{lib → lib-commonjs}/perf.js +0 -0
- /package/{lib → lib-commonjs}/perf.js.map +0 -0
- /package/{lib → lib-commonjs}/start.js +0 -0
- /package/{lib → lib-commonjs}/start.js.map +0 -0
- /package/{lib → lib-commonjs}/unpack.js +0 -0
- /package/{lib → lib-commonjs}/unpack.js.map +0 -0
- /package/{lib → lib-commonjs}/unpackWorker.js +0 -0
- /package/{lib → lib-commonjs}/unpackWorker.js.map +0 -0
- /package/{lib → lib-commonjs}/unpackWorkerAsync.js +0 -0
- /package/{lib → lib-commonjs}/unpackWorkerAsync.js.map +0 -0
- /package/{lib → lib-commonjs}/zipSyncUtils.js +0 -0
- /package/{lib → lib-commonjs}/zipSyncUtils.js.map +0 -0
- /package/{lib → lib-commonjs}/zipUtils.js +0 -0
- /package/{lib → lib-commonjs}/zipUtils.js.map +0 -0
- /package/{lib → lib-dts}/cli/ZipSyncCommandLineParser.d.ts +0 -0
- /package/{lib → lib-dts}/cli/ZipSyncCommandLineParser.d.ts.map +0 -0
- /package/{lib → lib-dts}/compress.d.ts +0 -0
- /package/{lib → lib-dts}/compress.d.ts.map +0 -0
- /package/{lib → lib-dts}/crc32.d.ts +0 -0
- /package/{lib → lib-dts}/crc32.d.ts.map +0 -0
- /package/{lib → lib-dts}/fs.d.ts +0 -0
- /package/{lib → lib-dts}/fs.d.ts.map +0 -0
- /package/{lib → lib-dts}/hash.d.ts +0 -0
- /package/{lib → lib-dts}/hash.d.ts.map +0 -0
- /package/{lib → lib-dts}/index.d.ts +0 -0
- /package/{lib → lib-dts}/index.d.ts.map +0 -0
- /package/{lib → lib-dts}/pack.d.ts +0 -0
- /package/{lib → lib-dts}/pack.d.ts.map +0 -0
- /package/{lib → lib-dts}/packWorker.d.ts +0 -0
- /package/{lib → lib-dts}/packWorker.d.ts.map +0 -0
- /package/{lib → lib-dts}/packWorkerAsync.d.ts +0 -0
- /package/{lib → lib-dts}/packWorkerAsync.d.ts.map +0 -0
- /package/{lib → lib-dts}/perf.d.ts +0 -0
- /package/{lib → lib-dts}/perf.d.ts.map +0 -0
- /package/{lib → lib-dts}/start.d.ts +0 -0
- /package/{lib → lib-dts}/start.d.ts.map +0 -0
- /package/{lib → lib-dts}/unpack.d.ts +0 -0
- /package/{lib → lib-dts}/unpack.d.ts.map +0 -0
- /package/{lib → lib-dts}/unpackWorker.d.ts +0 -0
- /package/{lib → lib-dts}/unpackWorker.d.ts.map +0 -0
- /package/{lib → lib-dts}/unpackWorkerAsync.d.ts +0 -0
- /package/{lib → lib-dts}/unpackWorkerAsync.d.ts.map +0 -0
- /package/{lib → lib-dts}/zipSyncUtils.d.ts +0 -0
- /package/{lib → lib-dts}/zipSyncUtils.d.ts.map +0 -0
- /package/{lib → lib-dts}/zipUtils.d.ts +0 -0
- /package/{lib → lib-dts}/zipUtils.d.ts.map +0 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
2
|
+
// See LICENSE in the project root for license information.
|
|
3
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
4
|
+
if (value !== null && value !== void 0) {
|
|
5
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
6
|
+
var dispose, inner;
|
|
7
|
+
if (async) {
|
|
8
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
9
|
+
dispose = value[Symbol.asyncDispose];
|
|
10
|
+
}
|
|
11
|
+
if (dispose === void 0) {
|
|
12
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
13
|
+
dispose = value[Symbol.dispose];
|
|
14
|
+
if (async) inner = dispose;
|
|
15
|
+
}
|
|
16
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
17
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
18
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
19
|
+
}
|
|
20
|
+
else if (async) {
|
|
21
|
+
env.stack.push({ async: true });
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
25
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
26
|
+
return function (env) {
|
|
27
|
+
function fail(e) {
|
|
28
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
29
|
+
env.hasError = true;
|
|
30
|
+
}
|
|
31
|
+
var r, s = 0;
|
|
32
|
+
function next() {
|
|
33
|
+
while (r = env.stack.pop()) {
|
|
34
|
+
try {
|
|
35
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
36
|
+
if (r.dispose) {
|
|
37
|
+
var result = r.dispose.call(r.value);
|
|
38
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
39
|
+
}
|
|
40
|
+
else s |= 1;
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
fail(e);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
47
|
+
if (env.hasError) throw env.error;
|
|
48
|
+
}
|
|
49
|
+
return next();
|
|
50
|
+
};
|
|
51
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
52
|
+
var e = new Error(message);
|
|
53
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
54
|
+
});
|
|
55
|
+
import * as fs from 'node:fs';
|
|
56
|
+
import * as path from 'node:path';
|
|
57
|
+
import * as zlib from 'node:zlib';
|
|
58
|
+
import { LookupByPath } from '@rushstack/lookup-by-path/lib/LookupByPath';
|
|
59
|
+
import { getDisposableFileHandle, rmdirSync, unlinkSync } from './fs';
|
|
60
|
+
import { createIncrementalZlib } from './compress';
|
|
61
|
+
import { markStart, markEnd, getDuration, emitSummary, formatDuration } from './perf';
|
|
62
|
+
import { findEndOfCentralDirectory, parseCentralDirectoryHeader, getFileFromZip, ZSTD_COMPRESSION, DEFLATE_COMPRESSION, STORE_COMPRESSION } from './zipUtils';
|
|
63
|
+
import { computeFileHash } from './hash';
|
|
64
|
+
import { defaultBufferSize, METADATA_FILENAME, METADATA_VERSION } from './zipSyncUtils';
|
|
65
|
+
const zlibUnpackModes = {
|
|
66
|
+
[ZSTD_COMPRESSION]: 'zstd-decompress',
|
|
67
|
+
[DEFLATE_COMPRESSION]: 'inflate',
|
|
68
|
+
[STORE_COMPRESSION]: undefined
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Unpack a zipsync archive into the provided target directories.
|
|
72
|
+
*/
|
|
73
|
+
export function unpack({ archivePath, targetDirectories: rawTargetDirectories, baseDir: rawBaseDir, terminal, outputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize) }) {
|
|
74
|
+
var _a;
|
|
75
|
+
const baseDir = path.resolve(rawBaseDir);
|
|
76
|
+
const targetDirectories = rawTargetDirectories.map((dir) => path.join(baseDir, dir));
|
|
77
|
+
terminal.writeLine(`Unpacking to ${rawTargetDirectories.join(', ')} from ${archivePath}`);
|
|
78
|
+
markStart('unpack.total');
|
|
79
|
+
terminal.writeDebugLine('Starting unpackZip');
|
|
80
|
+
// Read entire archive into memory (build cache entries are expected to be relatively small/medium).
|
|
81
|
+
markStart('unpack.read.archive');
|
|
82
|
+
const zipBuffer = fs.readFileSync(archivePath);
|
|
83
|
+
terminal.writeDebugLine(`Archive size=${zipBuffer.length} bytes`);
|
|
84
|
+
markEnd('unpack.read.archive');
|
|
85
|
+
// Locate & parse central directory so we have random-access metadata for all entries.
|
|
86
|
+
markStart('unpack.parse.centralDirectory');
|
|
87
|
+
const zipTree = new LookupByPath();
|
|
88
|
+
const endOfCentralDir = findEndOfCentralDirectory(zipBuffer);
|
|
89
|
+
const centralDirBuffer = zipBuffer.subarray(endOfCentralDir.centralDirOffset, endOfCentralDir.centralDirOffset + endOfCentralDir.centralDirSize);
|
|
90
|
+
terminal.writeDebugLine(`Central directory slice size=${centralDirBuffer.length} (expected=${endOfCentralDir.centralDirSize})`);
|
|
91
|
+
let metadataEntry;
|
|
92
|
+
const entries = [];
|
|
93
|
+
let offset = 0;
|
|
94
|
+
for (let i = 0; i < endOfCentralDir.totalCentralDirRecords; i++) {
|
|
95
|
+
const result = parseCentralDirectoryHeader(centralDirBuffer, offset);
|
|
96
|
+
zipTree.setItem(result.filename, true);
|
|
97
|
+
if (result.filename === METADATA_FILENAME) {
|
|
98
|
+
if (metadataEntry) {
|
|
99
|
+
throw new Error('Multiple metadata entries found in archive');
|
|
100
|
+
}
|
|
101
|
+
metadataEntry = result;
|
|
102
|
+
}
|
|
103
|
+
entries.push(result);
|
|
104
|
+
offset = result.nextOffset;
|
|
105
|
+
terminal.writeDebugLine(`Parsed central entry ${result.filename} (method=${result.header.compressionMethod}, compSize=${result.header.compressedSize})`);
|
|
106
|
+
}
|
|
107
|
+
markEnd('unpack.parse.centralDirectory');
|
|
108
|
+
if (!metadataEntry) {
|
|
109
|
+
throw new Error(`Metadata entry not found in archive`);
|
|
110
|
+
}
|
|
111
|
+
markStart('unpack.read.metadata');
|
|
112
|
+
terminal.writeDebugLine('Metadata entry found, reading');
|
|
113
|
+
const metadataZipBuffer = getFileFromZip(zipBuffer, metadataEntry);
|
|
114
|
+
let metadataBuffer;
|
|
115
|
+
if (metadataEntry.header.compressionMethod === STORE_COMPRESSION) {
|
|
116
|
+
metadataBuffer = metadataZipBuffer;
|
|
117
|
+
}
|
|
118
|
+
else if (metadataEntry.header.compressionMethod === DEFLATE_COMPRESSION) {
|
|
119
|
+
metadataBuffer = zlib.inflateRawSync(metadataZipBuffer);
|
|
120
|
+
if (metadataBuffer.length !== metadataEntry.header.uncompressedSize) {
|
|
121
|
+
throw new Error(`Metadata size mismatch (expected ${metadataEntry.header.uncompressedSize}, got ${metadataBuffer.length})`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
throw new Error(`Unsupported compression method for metadata: ${metadataEntry.header.compressionMethod}`);
|
|
126
|
+
}
|
|
127
|
+
const metadata = JSON.parse(metadataBuffer.toString('utf8'));
|
|
128
|
+
if (metadata.version !== METADATA_VERSION) {
|
|
129
|
+
throw new Error(`Unsupported metadata version: ${metadata.version}`);
|
|
130
|
+
}
|
|
131
|
+
terminal.writeDebugLine(`Metadata (version=${metadata.version}) parsed (fileCount=${Object.keys(metadata.files).length}, rawSize=${metadataBuffer.length})`);
|
|
132
|
+
markEnd('unpack.read.metadata');
|
|
133
|
+
terminal.writeLine(`Found ${entries.length} files in archive`);
|
|
134
|
+
// Ensure root target directories exist (they may be empty initially for cache misses).
|
|
135
|
+
for (const targetDirectory of targetDirectories) {
|
|
136
|
+
fs.mkdirSync(targetDirectory, { recursive: true });
|
|
137
|
+
terminal.writeDebugLine(`Ensured target directory: ${targetDirectory}`);
|
|
138
|
+
}
|
|
139
|
+
let extractedCount = 0;
|
|
140
|
+
let skippedCount = 0;
|
|
141
|
+
let deletedFilesCount = 0;
|
|
142
|
+
let deletedOtherCount = 0;
|
|
143
|
+
let deletedFoldersCount = 0;
|
|
144
|
+
let scanCount = 0;
|
|
145
|
+
const dirsToCleanup = [];
|
|
146
|
+
// Phase: scan filesystem to delete entries not present in archive and record empty dirs for later removal.
|
|
147
|
+
markStart('unpack.scan.existing');
|
|
148
|
+
const queue = targetDirectories.map((dir) => ({
|
|
149
|
+
dir,
|
|
150
|
+
depth: 0,
|
|
151
|
+
node: zipTree.getNodeAtPrefix(path.relative(baseDir, dir))
|
|
152
|
+
}));
|
|
153
|
+
while (queue.length) {
|
|
154
|
+
const { dir: currentDir, depth, node } = queue.shift();
|
|
155
|
+
terminal.writeDebugLine(`Enumerating directory: ${currentDir}`);
|
|
156
|
+
const padding = depth === 0 ? '' : '-↳'.repeat(depth);
|
|
157
|
+
let items;
|
|
158
|
+
try {
|
|
159
|
+
items = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
terminal.writeWarningLine(`Failed to read directory: ${currentDir}`);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
for (const item of items) {
|
|
166
|
+
scanCount++;
|
|
167
|
+
// check if exists in zipTree, if not delete
|
|
168
|
+
const relativePath = path
|
|
169
|
+
.relative(baseDir, path.join(currentDir, item.name))
|
|
170
|
+
.replace(/\\/g, '/');
|
|
171
|
+
const childNode = (_a = node === null || node === void 0 ? void 0 : node.children) === null || _a === void 0 ? void 0 : _a.get(item.name);
|
|
172
|
+
if (item.isFile()) {
|
|
173
|
+
terminal.writeVerboseLine(`${padding}${item.name}`);
|
|
174
|
+
if (!(childNode === null || childNode === void 0 ? void 0 : childNode.value)) {
|
|
175
|
+
terminal.writeDebugLine(`Deleting file: ${relativePath}`);
|
|
176
|
+
if (unlinkSync(relativePath)) {
|
|
177
|
+
deletedFilesCount++;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (item.isDirectory()) {
|
|
182
|
+
terminal.writeVerboseLine(`${padding}${item.name}/`);
|
|
183
|
+
queue.push({ dir: relativePath, depth: depth + 1, node: childNode });
|
|
184
|
+
if (!childNode || childNode.value) {
|
|
185
|
+
dirsToCleanup.push(relativePath);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
terminal.writeVerboseLine(`${padding}${item.name} (not file or directory, deleting)`);
|
|
190
|
+
if (unlinkSync(relativePath)) {
|
|
191
|
+
deletedOtherCount++;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Try to delete now-empty directories (created in previous builds but not in this archive).
|
|
197
|
+
for (const dir of dirsToCleanup) {
|
|
198
|
+
// Try to remove the directory. If it is not empty, this will throw and we can ignore the error.
|
|
199
|
+
if (rmdirSync(dir)) {
|
|
200
|
+
terminal.writeDebugLine(`Deleted empty directory: ${dir}`);
|
|
201
|
+
deletedFoldersCount++;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
terminal.writeDebugLine(`Existing entries tracked: ${scanCount}`);
|
|
205
|
+
markEnd('unpack.scan.existing');
|
|
206
|
+
markStart('unpack.extract.loop');
|
|
207
|
+
/**
|
|
208
|
+
* Stream-decompress (or copy) an individual file from the archive into place.
|
|
209
|
+
* We allocate a single large output buffer reused for all inflation operations to limit GC.
|
|
210
|
+
*/
|
|
211
|
+
function extractFileFromZip(targetPath, entry) {
|
|
212
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
213
|
+
try {
|
|
214
|
+
terminal.writeDebugLine(`Extracting file: ${entry.filename}`);
|
|
215
|
+
const fileZipBuffer = getFileFromZip(zipBuffer, entry);
|
|
216
|
+
let fileData;
|
|
217
|
+
const fileHandle = __addDisposableResource(env_1, getDisposableFileHandle(targetPath, 'w'), false);
|
|
218
|
+
if (entry.header.compressionMethod === STORE_COMPRESSION) {
|
|
219
|
+
fileData = fileZipBuffer;
|
|
220
|
+
let writeOffset = 0;
|
|
221
|
+
while (writeOffset < fileData.length && !isNaN(fileHandle.fd)) {
|
|
222
|
+
const written = fs.writeSync(fileHandle.fd, fileData, writeOffset, fileData.length - writeOffset);
|
|
223
|
+
writeOffset += written;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else if (entry.header.compressionMethod === DEFLATE_COMPRESSION ||
|
|
227
|
+
entry.header.compressionMethod === ZSTD_COMPRESSION) {
|
|
228
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
229
|
+
try {
|
|
230
|
+
const incrementalZlib = __addDisposableResource(env_2, createIncrementalZlib(outputBuffer, (chunk, lengthBytes) => {
|
|
231
|
+
let writeOffset = 0;
|
|
232
|
+
while (lengthBytes > 0 && writeOffset < chunk.byteLength) {
|
|
233
|
+
const written = fs.writeSync(fileHandle.fd, chunk, writeOffset, lengthBytes);
|
|
234
|
+
lengthBytes -= written;
|
|
235
|
+
writeOffset += written;
|
|
236
|
+
}
|
|
237
|
+
}, zlibUnpackModes[entry.header.compressionMethod]), false);
|
|
238
|
+
incrementalZlib.update(fileZipBuffer);
|
|
239
|
+
incrementalZlib.update(Buffer.alloc(0));
|
|
240
|
+
}
|
|
241
|
+
catch (e_1) {
|
|
242
|
+
env_2.error = e_1;
|
|
243
|
+
env_2.hasError = true;
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
__disposeResources(env_2);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
throw new Error(`Unsupported compression method: ${entry.header.compressionMethod} for ${entry.filename}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (e_2) {
|
|
254
|
+
env_1.error = e_2;
|
|
255
|
+
env_1.hasError = true;
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
__disposeResources(env_1);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Decide whether a file needs extraction by comparing existing file SHA‑1 vs metadata.
|
|
263
|
+
* If file is missing or hash differs we extract; otherwise we skip to preserve existing inode/data.
|
|
264
|
+
*/
|
|
265
|
+
function shouldExtract(targetPath, entry) {
|
|
266
|
+
if (metadata) {
|
|
267
|
+
const metadataFile = metadata.files[entry.filename];
|
|
268
|
+
if (metadataFile) {
|
|
269
|
+
try {
|
|
270
|
+
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
271
|
+
try {
|
|
272
|
+
const existingFile = __addDisposableResource(env_3, getDisposableFileHandle(targetPath, 'r'), false);
|
|
273
|
+
const existingHash = computeFileHash(existingFile.fd);
|
|
274
|
+
if (existingHash === metadataFile.sha1Hash) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch (e_3) {
|
|
279
|
+
env_3.error = e_3;
|
|
280
|
+
env_3.hasError = true;
|
|
281
|
+
}
|
|
282
|
+
finally {
|
|
283
|
+
__disposeResources(env_3);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch (e) {
|
|
287
|
+
if (e.code === 'ENOENT') {
|
|
288
|
+
terminal.writeDebugLine(`File does not exist, will extract: ${entry.filename}`);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
throw e;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
const dirsCreated = new Set();
|
|
299
|
+
// Iterate all entries excluding metadata; create parent dirs lazily; selective extraction.
|
|
300
|
+
for (const entry of entries) {
|
|
301
|
+
if (entry.filename === METADATA_FILENAME) {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
const targetPath = path.join(baseDir, entry.filename);
|
|
305
|
+
const targetDir = path.dirname(targetPath);
|
|
306
|
+
if (!dirsCreated.has(targetDir)) {
|
|
307
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
308
|
+
dirsCreated.add(targetDir);
|
|
309
|
+
}
|
|
310
|
+
if (shouldExtract(targetPath, entry)) {
|
|
311
|
+
extractFileFromZip(targetPath, entry);
|
|
312
|
+
extractedCount++;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
skippedCount++;
|
|
316
|
+
terminal.writeDebugLine(`Skip unchanged file: ${entry.filename}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
markEnd('unpack.extract.loop');
|
|
320
|
+
markEnd('unpack.total');
|
|
321
|
+
const unpackTotal = getDuration('unpack.total');
|
|
322
|
+
terminal.writeLine(`Extraction complete: ${extractedCount} extracted, ${skippedCount} skipped, ${deletedFilesCount} deleted, ${deletedFoldersCount} folders deleted, ${deletedOtherCount} other entries deleted in ${formatDuration(unpackTotal)}`);
|
|
323
|
+
emitSummary('unpack', terminal);
|
|
324
|
+
terminal.writeDebugLine('unpackZip finished');
|
|
325
|
+
return {
|
|
326
|
+
metadata,
|
|
327
|
+
filesExtracted: extractedCount,
|
|
328
|
+
filesSkipped: skippedCount,
|
|
329
|
+
filesDeleted: deletedFilesCount,
|
|
330
|
+
foldersDeleted: deletedFoldersCount,
|
|
331
|
+
otherEntriesDeleted: deletedOtherCount
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=unpack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unpack.js","sourceRoot":"","sources":["../src/unpack.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as zlib from 'node:zlib';\n\nimport { type IReadonlyPathTrieNode, LookupByPath } from '@rushstack/lookup-by-path/lib/LookupByPath';\nimport type { ITerminal } from '@rushstack/terminal';\n\nimport { getDisposableFileHandle, rmdirSync, unlinkSync, type IDisposableFileHandle } from './fs';\nimport { type IIncrementalZlib, type IncrementalZlibMode, createIncrementalZlib } from './compress';\nimport { markStart, markEnd, getDuration, emitSummary, formatDuration } from './perf';\nimport {\n findEndOfCentralDirectory,\n parseCentralDirectoryHeader,\n getFileFromZip,\n ZSTD_COMPRESSION,\n DEFLATE_COMPRESSION,\n STORE_COMPRESSION,\n type IEndOfCentralDirectory,\n type ICentralDirectoryHeaderParseResult,\n type ZipMetaCompressionMethod\n} from './zipUtils';\nimport { computeFileHash } from './hash';\nimport {\n defaultBufferSize,\n METADATA_FILENAME,\n METADATA_VERSION,\n type IDirQueueItem,\n type IMetadata\n} from './zipSyncUtils';\n\nconst zlibUnpackModes: Record<ZipMetaCompressionMethod, IncrementalZlibMode | undefined> = {\n [ZSTD_COMPRESSION]: 'zstd-decompress',\n [DEFLATE_COMPRESSION]: 'inflate',\n [STORE_COMPRESSION]: undefined\n} as const;\n\n/**\n * @public\n * Options for zipsync\n */\nexport interface IZipSyncUnpackOptions {\n /**\n * \\@rushstack/terminal compatible terminal for logging\n */\n terminal: ITerminal;\n /**\n * Zip file path\n */\n archivePath: string;\n /**\n * Target directories to unpack, relative to baseDir\n */\n targetDirectories: ReadonlyArray<string>;\n /**\n * Base directory for relative paths within the archive (defaults to common parent of targetDirectories)\n */\n baseDir: string;\n /**\n * Optional buffer that can be provided to avoid internal allocations.\n */\n outputBuffer?: Buffer<ArrayBuffer>;\n}\n\nexport interface IZipSyncUnpackResult {\n metadata: IMetadata;\n filesExtracted: number;\n filesSkipped: number;\n filesDeleted: number;\n foldersDeleted: number;\n otherEntriesDeleted: number;\n}\n\n/**\n * Unpack a zipsync archive into the provided target directories.\n */\nexport function unpack({\n archivePath,\n targetDirectories: rawTargetDirectories,\n baseDir: rawBaseDir,\n terminal,\n outputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize)\n}: IZipSyncUnpackOptions): IZipSyncUnpackResult {\n const baseDir: string = path.resolve(rawBaseDir);\n const targetDirectories: string[] = rawTargetDirectories.map((dir) => path.join(baseDir, dir));\n terminal.writeLine(`Unpacking to ${rawTargetDirectories.join(', ')} from ${archivePath}`);\n\n markStart('unpack.total');\n terminal.writeDebugLine('Starting unpackZip');\n\n // Read entire archive into memory (build cache entries are expected to be relatively small/medium).\n markStart('unpack.read.archive');\n const zipBuffer: Buffer = fs.readFileSync(archivePath);\n terminal.writeDebugLine(`Archive size=${zipBuffer.length} bytes`);\n markEnd('unpack.read.archive');\n\n // Locate & parse central directory so we have random-access metadata for all entries.\n markStart('unpack.parse.centralDirectory');\n const zipTree: LookupByPath<boolean> = new LookupByPath();\n const endOfCentralDir: IEndOfCentralDirectory = findEndOfCentralDirectory(zipBuffer);\n\n const centralDirBuffer: Buffer = zipBuffer.subarray(\n endOfCentralDir.centralDirOffset,\n endOfCentralDir.centralDirOffset + endOfCentralDir.centralDirSize\n );\n terminal.writeDebugLine(\n `Central directory slice size=${centralDirBuffer.length} (expected=${endOfCentralDir.centralDirSize})`\n );\n\n let metadataEntry: ICentralDirectoryHeaderParseResult | undefined;\n const entries: Array<ICentralDirectoryHeaderParseResult> = [];\n let offset: number = 0;\n\n for (let i: number = 0; i < endOfCentralDir.totalCentralDirRecords; i++) {\n const result: ICentralDirectoryHeaderParseResult = parseCentralDirectoryHeader(centralDirBuffer, offset);\n zipTree.setItem(result.filename, true);\n\n if (result.filename === METADATA_FILENAME) {\n if (metadataEntry) {\n throw new Error('Multiple metadata entries found in archive');\n }\n metadataEntry = result;\n }\n\n entries.push(result);\n offset = result.nextOffset;\n terminal.writeDebugLine(\n `Parsed central entry ${result.filename} (method=${result.header.compressionMethod}, compSize=${result.header.compressedSize})`\n );\n }\n markEnd('unpack.parse.centralDirectory');\n\n if (!metadataEntry) {\n throw new Error(`Metadata entry not found in archive`);\n }\n\n markStart('unpack.read.metadata');\n terminal.writeDebugLine('Metadata entry found, reading');\n const metadataZipBuffer: Buffer = getFileFromZip(zipBuffer, metadataEntry);\n\n let metadataBuffer: Buffer;\n if (metadataEntry.header.compressionMethod === STORE_COMPRESSION) {\n metadataBuffer = metadataZipBuffer;\n } else if (metadataEntry.header.compressionMethod === DEFLATE_COMPRESSION) {\n metadataBuffer = zlib.inflateRawSync(metadataZipBuffer);\n if (metadataBuffer.length !== metadataEntry.header.uncompressedSize) {\n throw new Error(\n `Metadata size mismatch (expected ${metadataEntry.header.uncompressedSize}, got ${metadataBuffer.length})`\n );\n }\n } else {\n throw new Error(`Unsupported compression method for metadata: ${metadataEntry.header.compressionMethod}`);\n }\n\n const metadata: IMetadata = JSON.parse(metadataBuffer.toString('utf8')) as IMetadata;\n\n if (metadata.version !== METADATA_VERSION) {\n throw new Error(`Unsupported metadata version: ${metadata.version}`);\n }\n\n terminal.writeDebugLine(\n `Metadata (version=${metadata.version}) parsed (fileCount=${Object.keys(metadata.files).length}, rawSize=${metadataBuffer.length})`\n );\n markEnd('unpack.read.metadata');\n\n terminal.writeLine(`Found ${entries.length} files in archive`);\n\n // Ensure root target directories exist (they may be empty initially for cache misses).\n for (const targetDirectory of targetDirectories) {\n fs.mkdirSync(targetDirectory, { recursive: true });\n terminal.writeDebugLine(`Ensured target directory: ${targetDirectory}`);\n }\n\n let extractedCount: number = 0;\n let skippedCount: number = 0;\n let deletedFilesCount: number = 0;\n let deletedOtherCount: number = 0;\n let deletedFoldersCount: number = 0;\n let scanCount: number = 0;\n\n const dirsToCleanup: string[] = [];\n\n // Phase: scan filesystem to delete entries not present in archive and record empty dirs for later removal.\n markStart('unpack.scan.existing');\n const queue: IDirQueueItem[] = targetDirectories.map((dir) => ({\n dir,\n depth: 0,\n node: zipTree.getNodeAtPrefix(path.relative(baseDir, dir))\n }));\n\n while (queue.length) {\n const { dir: currentDir, depth, node } = queue.shift()!;\n terminal.writeDebugLine(`Enumerating directory: ${currentDir}`);\n\n const padding: string = depth === 0 ? '' : '-↳'.repeat(depth);\n\n let items: fs.Dirent[];\n try {\n items = fs.readdirSync(currentDir, { withFileTypes: true });\n } catch (e) {\n terminal.writeWarningLine(`Failed to read directory: ${currentDir}`);\n continue;\n }\n\n for (const item of items) {\n scanCount++;\n // check if exists in zipTree, if not delete\n const relativePath: string = path\n .relative(baseDir, path.join(currentDir, item.name))\n .replace(/\\\\/g, '/');\n\n const childNode: IReadonlyPathTrieNode<boolean> | undefined = node?.children?.get(item.name);\n\n if (item.isFile()) {\n terminal.writeVerboseLine(`${padding}${item.name}`);\n if (!childNode?.value) {\n terminal.writeDebugLine(`Deleting file: ${relativePath}`);\n if (unlinkSync(relativePath)) {\n deletedFilesCount++;\n }\n }\n } else if (item.isDirectory()) {\n terminal.writeVerboseLine(`${padding}${item.name}/`);\n queue.push({ dir: relativePath, depth: depth + 1, node: childNode });\n if (!childNode || childNode.value) {\n dirsToCleanup.push(relativePath);\n }\n } else {\n terminal.writeVerboseLine(`${padding}${item.name} (not file or directory, deleting)`);\n if (unlinkSync(relativePath)) {\n deletedOtherCount++;\n }\n }\n }\n }\n\n // Try to delete now-empty directories (created in previous builds but not in this archive).\n for (const dir of dirsToCleanup) {\n // Try to remove the directory. If it is not empty, this will throw and we can ignore the error.\n if (rmdirSync(dir)) {\n terminal.writeDebugLine(`Deleted empty directory: ${dir}`);\n deletedFoldersCount++;\n }\n }\n\n terminal.writeDebugLine(`Existing entries tracked: ${scanCount}`);\n markEnd('unpack.scan.existing');\n\n markStart('unpack.extract.loop');\n\n /**\n * Stream-decompress (or copy) an individual file from the archive into place.\n * We allocate a single large output buffer reused for all inflation operations to limit GC.\n */\n function extractFileFromZip(targetPath: string, entry: ICentralDirectoryHeaderParseResult): void {\n terminal.writeDebugLine(`Extracting file: ${entry.filename}`);\n const fileZipBuffer: Buffer = getFileFromZip(zipBuffer, entry);\n let fileData: Buffer;\n using fileHandle: IDisposableFileHandle = getDisposableFileHandle(targetPath, 'w');\n if (entry.header.compressionMethod === STORE_COMPRESSION) {\n fileData = fileZipBuffer;\n let writeOffset: number = 0;\n while (writeOffset < fileData.length && !isNaN(fileHandle.fd)) {\n const written: number = fs.writeSync(\n fileHandle.fd,\n fileData,\n writeOffset,\n fileData.length - writeOffset\n );\n writeOffset += written;\n }\n } else if (\n entry.header.compressionMethod === DEFLATE_COMPRESSION ||\n entry.header.compressionMethod === ZSTD_COMPRESSION\n ) {\n using incrementalZlib: IIncrementalZlib = createIncrementalZlib(\n outputBuffer,\n (chunk, lengthBytes) => {\n let writeOffset: number = 0;\n while (lengthBytes > 0 && writeOffset < chunk.byteLength) {\n const written: number = fs.writeSync(fileHandle.fd, chunk, writeOffset, lengthBytes);\n lengthBytes -= written;\n writeOffset += written;\n }\n },\n zlibUnpackModes[entry.header.compressionMethod]!\n );\n incrementalZlib.update(fileZipBuffer);\n incrementalZlib.update(Buffer.alloc(0));\n } else {\n throw new Error(\n `Unsupported compression method: ${entry.header.compressionMethod} for ${entry.filename}`\n );\n }\n }\n\n /**\n * Decide whether a file needs extraction by comparing existing file SHA‑1 vs metadata.\n * If file is missing or hash differs we extract; otherwise we skip to preserve existing inode/data.\n */\n function shouldExtract(targetPath: string, entry: ICentralDirectoryHeaderParseResult): boolean {\n if (metadata) {\n const metadataFile: { size: number; sha1Hash: string } | undefined = metadata.files[entry.filename];\n\n if (metadataFile) {\n try {\n using existingFile: IDisposableFileHandle = getDisposableFileHandle(targetPath, 'r');\n const existingHash: string | false = computeFileHash(existingFile.fd);\n if (existingHash === metadataFile.sha1Hash) {\n return false;\n }\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === 'ENOENT') {\n terminal.writeDebugLine(`File does not exist, will extract: ${entry.filename}`);\n } else {\n throw e;\n }\n }\n }\n }\n return true;\n }\n\n const dirsCreated: Set<string> = new Set<string>();\n\n // Iterate all entries excluding metadata; create parent dirs lazily; selective extraction.\n for (const entry of entries) {\n if (entry.filename === METADATA_FILENAME) {\n continue;\n }\n\n const targetPath: string = path.join(baseDir, entry.filename);\n const targetDir: string = path.dirname(targetPath);\n if (!dirsCreated.has(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n dirsCreated.add(targetDir);\n }\n\n if (shouldExtract(targetPath, entry)) {\n extractFileFromZip(targetPath, entry);\n extractedCount++;\n } else {\n skippedCount++;\n terminal.writeDebugLine(`Skip unchanged file: ${entry.filename}`);\n }\n }\n markEnd('unpack.extract.loop');\n\n markEnd('unpack.total');\n const unpackTotal: number = getDuration('unpack.total');\n terminal.writeLine(\n `Extraction complete: ${extractedCount} extracted, ${skippedCount} skipped, ${deletedFilesCount} deleted, ${deletedFoldersCount} folders deleted, ${deletedOtherCount} other entries deleted in ${formatDuration(\n unpackTotal\n )}`\n );\n emitSummary('unpack', terminal);\n terminal.writeDebugLine('unpackZip finished');\n return {\n metadata,\n filesExtracted: extractedCount,\n filesSkipped: skippedCount,\n filesDeleted: deletedFilesCount,\n foldersDeleted: deletedFoldersCount,\n otherEntriesDeleted: deletedOtherCount\n };\n}\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
2
|
+
// See LICENSE in the project root for license information.
|
|
3
|
+
import { parentPort as rawParentPort } from 'node:worker_threads';
|
|
4
|
+
import { Terminal } from '@rushstack/terminal/lib/Terminal';
|
|
5
|
+
import { StringBufferTerminalProvider } from '@rushstack/terminal/lib/StringBufferTerminalProvider';
|
|
6
|
+
import { unpack } from './unpack';
|
|
7
|
+
import { defaultBufferSize } from './zipSyncUtils';
|
|
8
|
+
if (!rawParentPort) {
|
|
9
|
+
throw new Error('This module must be run in a worker thread.');
|
|
10
|
+
}
|
|
11
|
+
const parentPort = rawParentPort;
|
|
12
|
+
let outputBuffer = undefined;
|
|
13
|
+
function handleMessage(message) {
|
|
14
|
+
if (message === false) {
|
|
15
|
+
parentPort.removeAllListeners();
|
|
16
|
+
parentPort.close();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const terminalProvider = new StringBufferTerminalProvider();
|
|
20
|
+
const terminal = new Terminal(terminalProvider);
|
|
21
|
+
try {
|
|
22
|
+
switch (message.type) {
|
|
23
|
+
case 'zipsync-unpack': {
|
|
24
|
+
const { options } = message;
|
|
25
|
+
if (!outputBuffer) {
|
|
26
|
+
outputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize);
|
|
27
|
+
}
|
|
28
|
+
const successMessage = {
|
|
29
|
+
type: message.type,
|
|
30
|
+
id: message.id,
|
|
31
|
+
result: {
|
|
32
|
+
zipSyncReturn: unpack({ ...options, terminal, outputBuffer }),
|
|
33
|
+
zipSyncLogs: terminalProvider.getOutput()
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return parentPort.postMessage(successMessage);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
const errorMessage = {
|
|
42
|
+
type: 'error',
|
|
43
|
+
id: message.id,
|
|
44
|
+
args: {
|
|
45
|
+
message: err.message,
|
|
46
|
+
stack: err.stack || '',
|
|
47
|
+
zipSyncLogs: terminalProvider.getOutput()
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
parentPort.postMessage(errorMessage);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
parentPort.on('message', handleMessage);
|
|
54
|
+
//# sourceMappingURL=unpackWorker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unpackWorker.js","sourceRoot":"","sources":["../src/unpackWorker.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAE3D,OAAO,EAAE,UAAU,IAAI,aAAa,EAAoB,MAAM,qBAAqB,CAAC;AAEpF,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,4BAA4B,EAAE,MAAM,sDAAsD,CAAC;AAEpG,OAAO,EAAyD,MAAM,EAAE,MAAM,UAAU,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAsCnD,IAAI,CAAC,aAAa,EAAE,CAAC;IACnB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AACjE,CAAC;AACD,MAAM,UAAU,GAAgB,aAAa,CAAC;AAE9C,IAAI,YAAY,GAAoC,SAAS,CAAC;AAE9D,SAAS,aAAa,CAAC,OAAqC;IAC1D,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,UAAU,CAAC,kBAAkB,EAAE,CAAC;QAChC,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,GAAiC,IAAI,4BAA4B,EAAE,CAAC;IAC1F,MAAM,QAAQ,GAAa,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAE1D,IAAI,CAAC;QACH,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,gBAAgB,CAAC,CAAC,CAAC;gBACtB,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;gBAC5B,IAAI,CAAC,YAAY,EAAE,CAAC;oBAClB,YAAY,GAAG,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;gBAC3D,CAAC;gBAED,MAAM,cAAc,GAAiC;oBACnD,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,EAAE,EAAE,OAAO,CAAC,EAAE;oBACd,MAAM,EAAE;wBACN,aAAa,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;wBAC7D,WAAW,EAAE,gBAAgB,CAAC,SAAS,EAAE;qBAC1C;iBACF,CAAC;gBACF,OAAO,UAAU,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,YAAY,GAA+B;YAC/C,IAAI,EAAE,OAAO;YACb,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE;gBACJ,OAAO,EAAG,GAAa,CAAC,OAAO;gBAC/B,KAAK,EAAG,GAAa,CAAC,KAAK,IAAI,EAAE;gBACjC,WAAW,EAAE,gBAAgB,CAAC,SAAS,EAAE;aAC1C;SACF,CAAC;QACF,UAAU,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { parentPort as rawParentPort, type MessagePort } from 'node:worker_threads';\n\nimport { Terminal } from '@rushstack/terminal/lib/Terminal';\nimport { StringBufferTerminalProvider } from '@rushstack/terminal/lib/StringBufferTerminalProvider';\n\nimport { type IZipSyncUnpackOptions, type IZipSyncUnpackResult, unpack } from './unpack';\nimport { defaultBufferSize } from './zipSyncUtils';\n\nexport { type IZipSyncUnpackOptions, type IZipSyncUnpackResult } from './unpack';\n\nexport interface IHashWorkerData {\n basePath: string;\n}\n\nexport interface IZipSyncUnpackCommandMessage {\n type: 'zipsync-unpack';\n id: number;\n options: Omit<IZipSyncUnpackOptions, 'terminal'>;\n}\n\nexport interface IZipSyncUnpackWorkerResult {\n zipSyncReturn: IZipSyncUnpackResult;\n zipSyncLogs: string;\n}\n\ninterface IZipSyncUnpackSuccessMessage {\n id: number;\n type: 'zipsync-unpack';\n result: IZipSyncUnpackWorkerResult;\n}\n\nexport interface IZipSyncUnpackErrorMessage {\n type: 'error';\n id: number;\n args: {\n message: string;\n stack: string;\n zipSyncLogs: string;\n };\n}\n\nexport type IHostToWorkerMessage = IZipSyncUnpackCommandMessage;\nexport type IWorkerToHostMessage = IZipSyncUnpackSuccessMessage | IZipSyncUnpackErrorMessage;\n\nif (!rawParentPort) {\n throw new Error('This module must be run in a worker thread.');\n}\nconst parentPort: MessagePort = rawParentPort;\n\nlet outputBuffer: Buffer<ArrayBuffer> | undefined = undefined;\n\nfunction handleMessage(message: IHostToWorkerMessage | false): void {\n if (message === false) {\n parentPort.removeAllListeners();\n parentPort.close();\n return;\n }\n\n const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider();\n const terminal: Terminal = new Terminal(terminalProvider);\n\n try {\n switch (message.type) {\n case 'zipsync-unpack': {\n const { options } = message;\n if (!outputBuffer) {\n outputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize);\n }\n\n const successMessage: IZipSyncUnpackSuccessMessage = {\n type: message.type,\n id: message.id,\n result: {\n zipSyncReturn: unpack({ ...options, terminal, outputBuffer }),\n zipSyncLogs: terminalProvider.getOutput()\n }\n };\n return parentPort.postMessage(successMessage);\n }\n }\n } catch (err) {\n const errorMessage: IZipSyncUnpackErrorMessage = {\n type: 'error',\n id: message.id,\n args: {\n message: (err as Error).message,\n stack: (err as Error).stack || '',\n zipSyncLogs: terminalProvider.getOutput()\n }\n };\n parentPort.postMessage(errorMessage);\n }\n}\n\nparentPort.on('message', handleMessage);\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
2
|
+
// See LICENSE in the project root for license information.
|
|
3
|
+
export async function unpackWorkerAsync(options) {
|
|
4
|
+
const { Worker } = await import('node:worker_threads');
|
|
5
|
+
const worker = new Worker(require.resolve('./unpackWorker'));
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
worker.on('message', (message) => {
|
|
8
|
+
switch (message.type) {
|
|
9
|
+
case 'zipsync-unpack': {
|
|
10
|
+
resolve(message.result);
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
case 'error': {
|
|
14
|
+
const error = new Error(message.args.message);
|
|
15
|
+
error.stack = message.args.stack;
|
|
16
|
+
reject(error);
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
default: {
|
|
20
|
+
const exhaustiveCheck = message;
|
|
21
|
+
throw new Error(`Unexpected message type: ${JSON.stringify(exhaustiveCheck)}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
worker.on('error', (err) => {
|
|
26
|
+
reject(err);
|
|
27
|
+
});
|
|
28
|
+
worker.on('exit', (code) => {
|
|
29
|
+
if (code !== 0) {
|
|
30
|
+
reject(new Error(`Worker stopped with exit code ${code}`));
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const commandMessage = {
|
|
34
|
+
type: 'zipsync-unpack',
|
|
35
|
+
id: 0,
|
|
36
|
+
options
|
|
37
|
+
};
|
|
38
|
+
worker.postMessage(commandMessage);
|
|
39
|
+
}).finally(() => {
|
|
40
|
+
worker.postMessage(false);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=unpackWorkerAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unpackWorkerAsync.js","sourceRoot":"","sources":["../src/unpackWorkerAsync.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAa3D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAgD;IAEhD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAEvD,MAAM,MAAM,GAAW,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAErE,OAAO,IAAI,OAAO,CAA6B,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACjE,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAA6B,EAAE,EAAE;YACrD,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;gBACrB,KAAK,gBAAgB,CAAC,CAAC,CAAC;oBACtB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACxB,MAAM;gBACR,CAAC;gBACD,KAAK,OAAO,CAAC,CAAC,CAAC;oBACb,MAAM,KAAK,GAAU,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACrD,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;oBACjC,MAAM,CAAC,KAAK,CAAC,CAAC;oBACd,MAAM;gBACR,CAAC;gBACD,OAAO,CAAC,CAAC,CAAC;oBACR,MAAM,eAAe,GAAU,OAAO,CAAC;oBACvC,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;gBACjF,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,cAAc,GAAyB;YAC3C,IAAI,EAAE,gBAAgB;YACtB,EAAE,EAAE,CAAC;YACL,OAAO;SACR,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;QACd,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { Worker } from 'node:worker_threads';\n\nimport type {\n IWorkerToHostMessage,\n IHostToWorkerMessage,\n IZipSyncUnpackWorkerResult,\n IZipSyncUnpackOptions\n} from './unpackWorker';\n\nexport type { IZipSyncUnpackWorkerResult } from './unpackWorker';\n\nexport async function unpackWorkerAsync(\n options: Omit<IZipSyncUnpackOptions, 'terminal'>\n): Promise<IZipSyncUnpackWorkerResult> {\n const { Worker } = await import('node:worker_threads');\n\n const worker: Worker = new Worker(require.resolve('./unpackWorker'));\n\n return new Promise<IZipSyncUnpackWorkerResult>((resolve, reject) => {\n worker.on('message', (message: IWorkerToHostMessage) => {\n switch (message.type) {\n case 'zipsync-unpack': {\n resolve(message.result);\n break;\n }\n case 'error': {\n const error: Error = new Error(message.args.message);\n error.stack = message.args.stack;\n reject(error);\n break;\n }\n default: {\n const exhaustiveCheck: never = message;\n throw new Error(`Unexpected message type: ${JSON.stringify(exhaustiveCheck)}`);\n }\n }\n });\n\n worker.on('error', (err) => {\n reject(err);\n });\n\n worker.on('exit', (code) => {\n if (code !== 0) {\n reject(new Error(`Worker stopped with exit code ${code}`));\n }\n });\n\n const commandMessage: IHostToWorkerMessage = {\n type: 'zipsync-unpack',\n id: 0,\n options\n };\n worker.postMessage(commandMessage);\n }).finally(() => {\n worker.postMessage(false);\n });\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
2
|
+
// See LICENSE in the project root for license information.
|
|
3
|
+
export const METADATA_FILENAME = '__zipsync_metadata__.json';
|
|
4
|
+
export const METADATA_VERSION = '1.0';
|
|
5
|
+
export const defaultBufferSize = 1 << 25; // 32 MiB
|
|
6
|
+
//# sourceMappingURL=zipSyncUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zipSyncUtils.js","sourceRoot":"","sources":["../src/zipSyncUtils.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAI3D,MAAM,CAAC,MAAM,iBAAiB,GAAW,2BAA2B,CAAC;AACrE,MAAM,CAAC,MAAM,gBAAgB,GAAW,KAAK,CAAC;AAsB9C,MAAM,CAAC,MAAM,iBAAiB,GAAW,CAAC,IAAI,EAAE,CAAC,CAAC,SAAS","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { IReadonlyPathTrieNode } from '@rushstack/lookup-by-path/lib/LookupByPath';\n\nexport const METADATA_FILENAME: string = '__zipsync_metadata__.json';\nexport const METADATA_VERSION: string = '1.0';\n\nexport interface IDirQueueItem {\n dir: string;\n depth: number;\n node?: IReadonlyPathTrieNode<boolean> | undefined;\n}\n\nexport interface IMetadataFileRecord {\n size: number;\n sha1Hash: string;\n}\n\nexport interface IMetadata {\n version: string;\n files: Record<string, IMetadataFileRecord>;\n}\n\nexport type IZipSyncMode = 'pack' | 'unpack';\n\nexport type ZipSyncOptionCompression = 'store' | 'deflate' | 'zstd' | 'auto';\n\nexport const defaultBufferSize: number = 1 << 25; // 32 MiB\n"]}
|