@datatruck/cli 0.13.1 → 0.14.0
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/Repository/DatatruckRepository.d.ts +1 -0
- package/Repository/DatatruckRepository.js +199 -89
- package/config.schema.json +3 -0
- package/package.json +1 -1
- package/util/fs-util.d.ts +15 -20
- package/util/fs-util.js +50 -92
- package/util/math-util.js +2 -0
- package/util/process-util.d.ts +1 -0
- package/util/process-util.js +20 -4
- package/util/string-util.d.ts +1 -0
- package/util/string-util.js +8 -1
- package/util/zip-util.d.ts +45 -19
- package/util/zip-util.js +90 -51
|
@@ -50,6 +50,7 @@ exports.datatruckPackageRepositoryDefinition = {
|
|
|
50
50
|
additionalProperties: false,
|
|
51
51
|
required: ["include"],
|
|
52
52
|
properties: {
|
|
53
|
+
name: { type: "string" },
|
|
53
54
|
include: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
54
55
|
exclude: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
55
56
|
onePackByResult: { type: "boolean" },
|
|
@@ -160,7 +161,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
160
161
|
}
|
|
161
162
|
normalizeCompressConfig(packageConfig) {
|
|
162
163
|
let compress = packageConfig?.compress ?? this.config.compress;
|
|
163
|
-
if (compress === true) {
|
|
164
|
+
if (compress === true || (compress && !Array.isArray(compress.packs))) {
|
|
164
165
|
return {
|
|
165
166
|
packs: [
|
|
166
167
|
{
|
|
@@ -202,74 +203,78 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
202
203
|
cwd: sourcePath,
|
|
203
204
|
ignore: exclude,
|
|
204
205
|
dot: true,
|
|
205
|
-
onlyFiles:
|
|
206
|
+
onlyFiles: false,
|
|
206
207
|
markDirectories: true,
|
|
208
|
+
stats: true,
|
|
207
209
|
});
|
|
210
|
+
const packs = compress?.packs || [];
|
|
211
|
+
const tmpDir = await (0, fs_util_1.mkTmpDir)("path-lists");
|
|
212
|
+
const nonPackStream = (0, fs_1.createWriteStream)((0, path_1.join)(tmpDir, "nonpack.txt"));
|
|
213
|
+
const singlePackStream = (0, fs_1.createWriteStream)((0, path_1.join)(tmpDir, "single-pack.txt"));
|
|
214
|
+
const packStreams = Array.from({ length: packs.length }).map((v, i) => (0, fs_1.createWriteStream)((0, path_1.join)(tmpDir, `pack-${i}.txt`)));
|
|
215
|
+
let totalFiles = 0;
|
|
216
|
+
const streams = [nonPackStream, singlePackStream, ...packStreams];
|
|
208
217
|
if (data.options.verbose)
|
|
209
|
-
(0, cli_util_1.logExec)(`Writing
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
packs: compress?.packs,
|
|
218
|
+
(0, cli_util_1.logExec)(`Writing file lists in ${tmpDir}`);
|
|
219
|
+
await data.onProgress({
|
|
220
|
+
step: "Writing the file lists...",
|
|
213
221
|
});
|
|
214
|
-
|
|
215
|
-
(0,
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
222
|
+
await Promise.all([
|
|
223
|
+
...streams.map((p) => (0, fs_util_1.waitForClose)(p)),
|
|
224
|
+
(async () => {
|
|
225
|
+
for await (const entry of (0, fs_util_1.pathIterator)(stream)) {
|
|
226
|
+
const pathSubject = entry.stats.isDirectory()
|
|
227
|
+
? entry.path.slice(0, -1)
|
|
228
|
+
: entry.path;
|
|
229
|
+
let stream = nonPackStream;
|
|
230
|
+
let successPackIndex;
|
|
231
|
+
for (const [packIndex, pack] of packs.entries()) {
|
|
232
|
+
if ((0, string_util_1.checkPath)(pathSubject, pack.include, pack.exclude)) {
|
|
233
|
+
stream = pack.onePackByResult
|
|
234
|
+
? singlePackStream
|
|
235
|
+
: packStreams[packIndex];
|
|
236
|
+
successPackIndex = packIndex;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const isNonPackStream = stream === nonPackStream;
|
|
241
|
+
const isPackStream = stream !== nonPackStream;
|
|
242
|
+
const isSinglePackStream = stream === singlePackStream;
|
|
243
|
+
const include = isPackStream
|
|
244
|
+
? entry.stats.isDirectory()
|
|
245
|
+
? await (0, fs_util_1.isEmptyDir)(entry.path)
|
|
246
|
+
: true
|
|
247
|
+
: true;
|
|
248
|
+
if (include) {
|
|
249
|
+
let value = entry.path;
|
|
250
|
+
if (isNonPackStream) {
|
|
251
|
+
value += `:${entry.stats.uid}:${entry.stats.gid}:${entry.stats.mode}`;
|
|
252
|
+
}
|
|
253
|
+
else if (isSinglePackStream) {
|
|
254
|
+
value += `:${successPackIndex}`;
|
|
255
|
+
}
|
|
256
|
+
if (!entry.stats.isDirectory())
|
|
257
|
+
totalFiles++;
|
|
258
|
+
stream.write(`${value}\n`);
|
|
245
259
|
}
|
|
246
260
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const stats = await (0, zip_util_1.zip)({
|
|
250
|
-
path: sourcePath,
|
|
251
|
-
output: target,
|
|
252
|
-
includeList: packsPath,
|
|
253
|
-
excludeList: pathLists.excludedPackPaths[packIndex],
|
|
254
|
-
verbose: data.options.verbose,
|
|
255
|
-
onStream: async (stream) => await data.onProgress({
|
|
256
|
-
total: pathLists.total.all,
|
|
257
|
-
current: currentFiles + stream.data.files,
|
|
258
|
-
percent: (0, math_util_1.progressPercent)(pathLists.total.all, currentFiles + stream.data.files),
|
|
259
|
-
step: stream.type === "progress" ? stream.data.path : "",
|
|
260
|
-
}),
|
|
261
|
-
});
|
|
262
|
-
currentFiles += stats.files;
|
|
261
|
+
for (const stream of streams) {
|
|
262
|
+
stream.end();
|
|
263
263
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
})(),
|
|
265
|
+
]);
|
|
266
|
+
let currentFiles = 0;
|
|
267
|
+
const dttFolder = `.dtt-${data.snapshot.id.slice(0, 8)}`;
|
|
268
|
+
const dttPath = (0, path_1.join)(outPath, dttFolder);
|
|
269
|
+
await (0, promises_1.mkdir)(dttPath);
|
|
270
|
+
// Non pack
|
|
267
271
|
if (data.options.verbose)
|
|
268
272
|
(0, cli_util_1.logExec)(`Copying files to ${outPath}`);
|
|
273
|
+
await (0, promises_1.copyFile)(nonPackStream.path, (0, path_1.join)(dttPath, "permissions.txt"));
|
|
269
274
|
await (0, fs_util_1.cpy)({
|
|
270
275
|
input: {
|
|
271
276
|
type: "pathList",
|
|
272
|
-
path:
|
|
277
|
+
path: nonPackStream.path.toString(),
|
|
273
278
|
basePath: sourcePath,
|
|
274
279
|
},
|
|
275
280
|
targetPath: outPath,
|
|
@@ -280,13 +285,66 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
280
285
|
return;
|
|
281
286
|
currentFiles++;
|
|
282
287
|
await data.onProgress({
|
|
283
|
-
total:
|
|
288
|
+
total: totalFiles,
|
|
284
289
|
current: currentFiles,
|
|
285
|
-
percent: (0, math_util_1.progressPercent)(
|
|
290
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, currentFiles),
|
|
286
291
|
step: entryPath,
|
|
287
292
|
});
|
|
288
293
|
},
|
|
289
294
|
});
|
|
295
|
+
// Single pack
|
|
296
|
+
const singleReader = (0, readline_1.createInterface)({
|
|
297
|
+
input: (0, fs_1.createReadStream)(singlePackStream.path),
|
|
298
|
+
});
|
|
299
|
+
for await (const line of singleReader) {
|
|
300
|
+
let [packPath, packIndex] = line.split(":");
|
|
301
|
+
const pack = packs[packIndex];
|
|
302
|
+
if (packPath.endsWith("/"))
|
|
303
|
+
packPath = packPath.slice(0, -1);
|
|
304
|
+
const outBasename = (`pack${pack.name ? `-${encodeURIComponent(pack.name)}` : ""}` +
|
|
305
|
+
`-${encodeURIComponent(packPath.replace(/[\\/]/g, "-"))}` +
|
|
306
|
+
`.zip`).slice(0, 255);
|
|
307
|
+
const target = (0, path_1.join)(dttPath, outBasename);
|
|
308
|
+
const stats = await (0, zip_util_1.zip)({
|
|
309
|
+
path: pkg.path,
|
|
310
|
+
output: target,
|
|
311
|
+
filter: [{ patterns: [packPath] }],
|
|
312
|
+
verbose: data.options.verbose,
|
|
313
|
+
onStream: async (stream) => {
|
|
314
|
+
if (stream.type === "progress")
|
|
315
|
+
await data.onProgress({
|
|
316
|
+
total: totalFiles,
|
|
317
|
+
current: currentFiles + stream.data.files,
|
|
318
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, currentFiles + stream.data.files),
|
|
319
|
+
step: stream.data.path,
|
|
320
|
+
stepPercent: stream.data.progress,
|
|
321
|
+
});
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
currentFiles += stats.files;
|
|
325
|
+
}
|
|
326
|
+
// Packs
|
|
327
|
+
for (const [packIndex, packStream] of packStreams.entries()) {
|
|
328
|
+
const pack = packs[packIndex];
|
|
329
|
+
const target = (0, path_1.join)(dttPath, `pack-${packIndex}${pack.name ? `-${pack.name}` : ""}.zip`);
|
|
330
|
+
const stats = await (0, zip_util_1.zip)({
|
|
331
|
+
path: sourcePath,
|
|
332
|
+
output: target,
|
|
333
|
+
includeList: packStream.path.toString(),
|
|
334
|
+
verbose: data.options.verbose,
|
|
335
|
+
onStream: async (stream) => {
|
|
336
|
+
if (stream.type === "progress")
|
|
337
|
+
await data.onProgress({
|
|
338
|
+
total: totalFiles,
|
|
339
|
+
current: currentFiles + stream.data.files,
|
|
340
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, currentFiles + stream.data.files),
|
|
341
|
+
step: stream.data.path,
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
currentFiles += stats.files;
|
|
346
|
+
}
|
|
347
|
+
// Meta
|
|
290
348
|
const metaPath = `${outPath}.json`;
|
|
291
349
|
const nodePkg = (0, fs_util_1.parsePackageFile)();
|
|
292
350
|
const meta = {
|
|
@@ -296,7 +354,8 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
296
354
|
package: data.package.name,
|
|
297
355
|
task: data.package.task?.name,
|
|
298
356
|
version: nodePkg.version,
|
|
299
|
-
size: await (0, fs_util_1.fastFolderSizeAsync)(outPath)
|
|
357
|
+
size: (await (0, fs_util_1.fastFolderSizeAsync)(outPath)) -
|
|
358
|
+
(await (0, fs_util_1.fastFolderSizeAsync)(dttPath)),
|
|
300
359
|
};
|
|
301
360
|
if (data.options.verbose)
|
|
302
361
|
(0, cli_util_1.logExec)(`Writing metadata into ${metaPath}`);
|
|
@@ -313,7 +372,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
313
372
|
const sourceMetaPath = `${sourcePath}.json`;
|
|
314
373
|
const targetMetaPath = `${targetPath}.json`;
|
|
315
374
|
if (data.options.verbose)
|
|
316
|
-
(0, cli_util_1.logExec)(`Copying files to ${targetPath}`);
|
|
375
|
+
(0, cli_util_1.logExec)(`Copying backup files to ${targetPath}`);
|
|
317
376
|
await (0, promises_1.mkdir)(targetPath);
|
|
318
377
|
await (0, fs_util_1.cpy)({
|
|
319
378
|
input: {
|
|
@@ -342,49 +401,100 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
342
401
|
});
|
|
343
402
|
const sourcePath = (0, path_1.join)(this.config.outPath, snapshotName);
|
|
344
403
|
let totalFiles = 0;
|
|
345
|
-
let currentFiles =
|
|
346
|
-
await
|
|
404
|
+
let currentFiles = 0;
|
|
405
|
+
await data.onProgress({
|
|
406
|
+
step: "Counting files...",
|
|
407
|
+
});
|
|
408
|
+
const dttFolder = `.dtt-${data.snapshot.id.slice(0, 8)}`;
|
|
409
|
+
const dttPath = (0, path_1.join)(sourcePath, dttFolder);
|
|
410
|
+
const dttPathExists = await (0, fs_util_1.checkDir)(dttPath);
|
|
411
|
+
if (dttPathExists) {
|
|
412
|
+
const it = await (0, promises_1.opendir)(dttPath);
|
|
413
|
+
for await (const dirent of it) {
|
|
414
|
+
const path = (0, path_1.join)(dttPath, dirent.name);
|
|
415
|
+
if (dirent.name === "permissions.txt") {
|
|
416
|
+
totalFiles++;
|
|
417
|
+
}
|
|
418
|
+
else if (dirent.name.endsWith(".zip")) {
|
|
419
|
+
await (0, zip_util_1.listZip)({
|
|
420
|
+
path,
|
|
421
|
+
verbose: data.options.verbose,
|
|
422
|
+
onStream: (item) => {
|
|
423
|
+
const isDir = item.Folder === "+";
|
|
424
|
+
if (!isDir)
|
|
425
|
+
totalFiles++;
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const allFiles = fast_glob_1.default.stream(["**"], {
|
|
432
|
+
cwd: sourcePath,
|
|
433
|
+
ignore: [dttFolder],
|
|
434
|
+
dot: true,
|
|
435
|
+
onlyFiles: true,
|
|
436
|
+
});
|
|
437
|
+
for await (const _file of allFiles) {
|
|
347
438
|
totalFiles++;
|
|
348
|
-
}
|
|
439
|
+
}
|
|
349
440
|
if (data.options.verbose)
|
|
350
441
|
(0, cli_util_1.logExec)(`Copying files to ${restorePath}`);
|
|
351
442
|
await (0, fs_util_1.cpy)({
|
|
352
443
|
input: {
|
|
353
444
|
type: "glob",
|
|
354
445
|
sourcePath,
|
|
446
|
+
exclude: [dttFolder],
|
|
355
447
|
},
|
|
356
448
|
targetPath: restorePath,
|
|
357
449
|
concurrency: this.config.fileCopyConcurrency,
|
|
358
|
-
onPath: async ({ entryPath,
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
450
|
+
onPath: async ({ entryPath, isDir }) => {
|
|
451
|
+
if (!isDir) {
|
|
452
|
+
currentFiles++;
|
|
453
|
+
await data.onProgress({
|
|
454
|
+
total: totalFiles,
|
|
455
|
+
current: Math.max(currentFiles, 0),
|
|
456
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
|
|
457
|
+
step: entryPath,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
});
|
|
462
|
+
if (dttPathExists) {
|
|
463
|
+
const it = await (0, promises_1.opendir)(dttPath);
|
|
464
|
+
for await (const dirent of it) {
|
|
465
|
+
const path = (0, path_1.join)(dttPath, dirent.name);
|
|
466
|
+
if (dirent.name === "permissions.txt") {
|
|
467
|
+
if (data.options.verbose)
|
|
468
|
+
(0, cli_util_1.logExec)(`Applying permissions (${path})`);
|
|
469
|
+
currentFiles++;
|
|
470
|
+
await data.onProgress({
|
|
471
|
+
total: totalFiles,
|
|
472
|
+
current: currentFiles,
|
|
473
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, currentFiles),
|
|
474
|
+
step: "Applying permissions",
|
|
475
|
+
});
|
|
476
|
+
await (0, fs_util_1.applyPermissions)(restorePath, path);
|
|
477
|
+
}
|
|
478
|
+
else if (dirent.name.endsWith(".zip")) {
|
|
370
479
|
await (0, zip_util_1.unzip)({
|
|
371
|
-
input:
|
|
480
|
+
input: path,
|
|
372
481
|
output: restorePath,
|
|
373
482
|
verbose: data.options.verbose,
|
|
374
|
-
onStream: async (stream) =>
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
483
|
+
onStream: async (stream) => {
|
|
484
|
+
await data.onProgress({
|
|
485
|
+
total: totalFiles,
|
|
486
|
+
current: currentFiles + stream.data.files,
|
|
487
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, currentFiles + stream.data.files),
|
|
488
|
+
step: stream.type === "progress"
|
|
489
|
+
? `Extracting ${stream.data.path}`
|
|
490
|
+
: "",
|
|
491
|
+
stepPercent: stream.data.progress,
|
|
492
|
+
});
|
|
493
|
+
},
|
|
382
494
|
});
|
|
383
495
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
},
|
|
387
|
-
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
388
498
|
}
|
|
389
499
|
}
|
|
390
500
|
exports.DatatruckRepository = DatatruckRepository;
|
package/config.schema.json
CHANGED
package/package.json
CHANGED
package/util/fs-util.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
/// <reference types="node" />
|
|
4
|
-
|
|
4
|
+
/// <reference types="node" />
|
|
5
|
+
import { Dirent, Stats } from "fs";
|
|
6
|
+
import { WriteStream } from "fs";
|
|
5
7
|
import { Interface } from "readline";
|
|
6
8
|
export declare const isWSLSystem: boolean;
|
|
9
|
+
export declare function isEmptyDir(path: string): Promise<boolean>;
|
|
10
|
+
declare type EntryObject = {
|
|
11
|
+
name: string;
|
|
12
|
+
path: string;
|
|
13
|
+
dirent: Dirent;
|
|
14
|
+
stats: Stats;
|
|
15
|
+
};
|
|
16
|
+
export declare function applyPermissions(baseDir: string, permissionsPath: string): Promise<void>;
|
|
17
|
+
export declare function pathIterator(stream: AsyncIterable<string | Buffer>): AsyncIterable<EntryObject>;
|
|
7
18
|
export declare function isLocalDir(path: string): boolean;
|
|
8
19
|
export declare function isDirEmpty(path: string): Promise<boolean>;
|
|
9
20
|
export declare function mkdirIfNotExists(path: string): Promise<string>;
|
|
@@ -28,7 +39,7 @@ export declare function mkTmpDir(prefix: string, id?: string): Promise<string>;
|
|
|
28
39
|
export declare function readPartialFile(path: string, positions: [number, number?]): Promise<string>;
|
|
29
40
|
export declare function checkFile(path: string): Promise<boolean>;
|
|
30
41
|
export declare function checkDir(path: string): Promise<boolean>;
|
|
31
|
-
export declare function readDir(path: string): Promise<string[]>;
|
|
42
|
+
export declare function readDir(path: string, optional?: boolean): Promise<string[]>;
|
|
32
43
|
export declare function forEachFile(dirPath: string, cb: (path: string, dir: boolean) => void, includeDir?: boolean): Promise<void>;
|
|
33
44
|
/**
|
|
34
45
|
* @experimental
|
|
@@ -37,24 +48,7 @@ export declare function fastglobToGitIgnore(patterns: string[], baseDir: string)
|
|
|
37
48
|
export declare function writeGitIgnoreList(options: {
|
|
38
49
|
paths: NodeJS.ReadableStream | string[];
|
|
39
50
|
}): Promise<string>;
|
|
40
|
-
export declare function
|
|
41
|
-
paths: NodeJS.ReadableStream | string[];
|
|
42
|
-
packs?: {
|
|
43
|
-
include: string[];
|
|
44
|
-
exclude?: string[];
|
|
45
|
-
multiple?: boolean;
|
|
46
|
-
}[];
|
|
47
|
-
}): Promise<{
|
|
48
|
-
path: string;
|
|
49
|
-
includedPackPaths: string[];
|
|
50
|
-
excludedPackPaths: string[];
|
|
51
|
-
total: {
|
|
52
|
-
all: number;
|
|
53
|
-
path: number;
|
|
54
|
-
packsPaths: number[];
|
|
55
|
-
multipleStats: Record<string, number>;
|
|
56
|
-
};
|
|
57
|
-
}>;
|
|
51
|
+
export declare function waitForClose(stream: WriteStream): Promise<WriteStream>;
|
|
58
52
|
export declare function copyFileWithStreams(source: string, target: string): Promise<unknown>;
|
|
59
53
|
export declare function updateFileStats(path: string, fileInfo: Stats): Promise<void>;
|
|
60
54
|
export declare function isNotFoundError(error: unknown): boolean;
|
|
@@ -91,3 +85,4 @@ export declare function cpy(options: {
|
|
|
91
85
|
};
|
|
92
86
|
}) => Promise<boolean | void>;
|
|
93
87
|
}): Promise<void>;
|
|
88
|
+
export {};
|
package/util/fs-util.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.
|
|
6
|
+
exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = exports.tmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.existsFile = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.readdirIfExists = exports.writeJSONFile = exports.existsDir = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isDirEmpty = exports.isLocalDir = exports.pathIterator = exports.applyPermissions = exports.isEmptyDir = exports.isWSLSystem = void 0;
|
|
7
7
|
const globalData_1 = __importDefault(require("../globalData"));
|
|
8
8
|
const path_util_1 = require("./path-util");
|
|
9
9
|
const async_1 = require("async");
|
|
@@ -13,13 +13,49 @@ const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
|
13
13
|
const fs_1 = require("fs");
|
|
14
14
|
const fs_2 = require("fs");
|
|
15
15
|
const promises_1 = require("fs/promises");
|
|
16
|
-
const micromatch_1 = require("micromatch");
|
|
17
16
|
const os_1 = require("os");
|
|
18
17
|
const path_1 = require("path");
|
|
19
18
|
const path_2 = require("path");
|
|
20
19
|
const readline_1 = require("readline");
|
|
21
20
|
const util_1 = require("util");
|
|
22
21
|
exports.isWSLSystem = (0, os_1.release)().includes("microsoft-standard-WSL");
|
|
22
|
+
async function isEmptyDir(path) {
|
|
23
|
+
const iterator = await (0, promises_1.opendir)(path);
|
|
24
|
+
let done = false;
|
|
25
|
+
try {
|
|
26
|
+
const next = await iterator[Symbol.asyncIterator]().next();
|
|
27
|
+
done = !!next.done;
|
|
28
|
+
return done;
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
if (!done) {
|
|
32
|
+
await iterator.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.isEmptyDir = isEmptyDir;
|
|
37
|
+
async function applyPermissions(baseDir, permissionsPath) {
|
|
38
|
+
const singleReader = (0, readline_1.createInterface)({
|
|
39
|
+
input: (0, fs_1.createReadStream)(permissionsPath),
|
|
40
|
+
});
|
|
41
|
+
for await (const line of singleReader) {
|
|
42
|
+
const [rpath, rawUid, rawGui, rawMode] = line.split(":");
|
|
43
|
+
const path = (0, path_1.join)(baseDir, rpath);
|
|
44
|
+
if (!path.startsWith(baseDir)) {
|
|
45
|
+
throw new Error(`Entry path is out of the base dir: (${path}, ${baseDir})`);
|
|
46
|
+
}
|
|
47
|
+
const uid = Number(rawUid);
|
|
48
|
+
const guid = Number(rawGui);
|
|
49
|
+
await (0, promises_1.chown)(path, uid, guid);
|
|
50
|
+
const mode = Number(rawMode);
|
|
51
|
+
await (0, promises_1.chmod)(path, mode);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.applyPermissions = applyPermissions;
|
|
55
|
+
function pathIterator(stream) {
|
|
56
|
+
return stream;
|
|
57
|
+
}
|
|
58
|
+
exports.pathIterator = pathIterator;
|
|
23
59
|
function isLocalDir(path) {
|
|
24
60
|
return /^[\/\.]|([A-Z]:)/i.test(path);
|
|
25
61
|
}
|
|
@@ -59,9 +95,7 @@ async function writeJSONFile(path, json) {
|
|
|
59
95
|
}
|
|
60
96
|
exports.writeJSONFile = writeJSONFile;
|
|
61
97
|
async function readdirIfExists(path) {
|
|
62
|
-
|
|
63
|
-
return [];
|
|
64
|
-
return await readDir(path);
|
|
98
|
+
return await readDir(path, true);
|
|
65
99
|
}
|
|
66
100
|
exports.readdirIfExists = readdirIfExists;
|
|
67
101
|
exports.parseFileExtensions = ["json", "js", "ts", "yaml", "yml"];
|
|
@@ -187,13 +221,15 @@ async function checkDir(path) {
|
|
|
187
221
|
}
|
|
188
222
|
}
|
|
189
223
|
exports.checkDir = checkDir;
|
|
190
|
-
async function readDir(path) {
|
|
224
|
+
async function readDir(path, optional) {
|
|
191
225
|
try {
|
|
192
226
|
return await (0, promises_1.readdir)(path);
|
|
193
227
|
}
|
|
194
228
|
catch (anyError) {
|
|
195
229
|
const nodeError = anyError;
|
|
196
230
|
if (nodeError.code === "ENOENT") {
|
|
231
|
+
if (optional)
|
|
232
|
+
return [];
|
|
197
233
|
const error = new Error(nodeError.message);
|
|
198
234
|
error.code = nodeError.code;
|
|
199
235
|
error.errno = nodeError.errno;
|
|
@@ -262,93 +298,14 @@ async function writeGitIgnoreList(options) {
|
|
|
262
298
|
return path;
|
|
263
299
|
}
|
|
264
300
|
exports.writeGitIgnoreList = writeGitIgnoreList;
|
|
265
|
-
async function
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const multipleStats = {};
|
|
272
|
-
const total = new Array((options.packs?.length || 0) + 1).fill(0);
|
|
273
|
-
await Promise.all([
|
|
274
|
-
...new Array((options.packs?.length || 0) + 1).fill(null).map((_, index) => new Promise((resolve, reject) => {
|
|
275
|
-
const path = (0, path_1.join)(tempDir, `${index}-included.txt`);
|
|
276
|
-
const stream = (0, fs_2.createWriteStream)(path);
|
|
277
|
-
includedPaths.push(path);
|
|
278
|
-
included.push(stream);
|
|
279
|
-
stream.on("close", resolve);
|
|
280
|
-
stream.on("error", reject);
|
|
281
|
-
})),
|
|
282
|
-
...new Array(options.packs?.length || 0).fill(null).map((_, index) => new Promise((resolve, reject) => {
|
|
283
|
-
const path = (0, path_1.join)(tempDir, `${index}-excluded.txt`);
|
|
284
|
-
const stream = (0, fs_2.createWriteStream)(path);
|
|
285
|
-
excludedPaths.push(path);
|
|
286
|
-
excluded.push(stream);
|
|
287
|
-
stream.on("close", resolve);
|
|
288
|
-
stream.on("error", reject);
|
|
289
|
-
})),
|
|
290
|
-
new Promise(async (resolve) => {
|
|
291
|
-
const packDirectories = [];
|
|
292
|
-
for await (const value of options.paths) {
|
|
293
|
-
const entry = value.toString();
|
|
294
|
-
const isDir = entry.endsWith("/");
|
|
295
|
-
const matchEntry = isDir ? entry.slice(0, -1) : entry;
|
|
296
|
-
let packIndex = 1;
|
|
297
|
-
let matches = false;
|
|
298
|
-
for (const pack of options.packs || []) {
|
|
299
|
-
if ((0, micromatch_1.isMatch)(matchEntry, pack.include) &&
|
|
300
|
-
(!pack.exclude || !(0, micromatch_1.isMatch)(matchEntry, pack.exclude))) {
|
|
301
|
-
if (isDir)
|
|
302
|
-
packDirectories.push([packIndex - 1, entry]);
|
|
303
|
-
included[packIndex].write(`${entry}\n`);
|
|
304
|
-
if (!isDir)
|
|
305
|
-
total[packIndex]++;
|
|
306
|
-
matches = true;
|
|
307
|
-
break;
|
|
308
|
-
}
|
|
309
|
-
packIndex++;
|
|
310
|
-
}
|
|
311
|
-
if (!matches) {
|
|
312
|
-
const packDir = packDirectories.find(([, p]) => entry.startsWith(p));
|
|
313
|
-
if (packDir) {
|
|
314
|
-
const [i, v] = packDir;
|
|
315
|
-
const multipleExclude = options.packs?.[i].exclude;
|
|
316
|
-
if (multipleExclude && (0, micromatch_1.isMatch)(matchEntry, multipleExclude)) {
|
|
317
|
-
included[0].write(`${entry}\n`);
|
|
318
|
-
excluded[i].write(`${entry}\n`);
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
if (!multipleStats[v])
|
|
322
|
-
multipleStats[v] = 0;
|
|
323
|
-
multipleStats[v]++;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
included[0].write(`${entry}\n`);
|
|
328
|
-
}
|
|
329
|
-
if (!isDir)
|
|
330
|
-
total[0]++;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
for (const stream of [...included, ...excluded]) {
|
|
334
|
-
stream.end();
|
|
335
|
-
}
|
|
336
|
-
resolve();
|
|
337
|
-
}),
|
|
338
|
-
]);
|
|
339
|
-
return {
|
|
340
|
-
path: includedPaths[0],
|
|
341
|
-
includedPackPaths: includedPaths.slice(1),
|
|
342
|
-
excludedPackPaths: excludedPaths,
|
|
343
|
-
total: {
|
|
344
|
-
all: total.reduce((p, v) => p + v, 0),
|
|
345
|
-
path: total[0],
|
|
346
|
-
packsPaths: total.slice(1),
|
|
347
|
-
multipleStats,
|
|
348
|
-
},
|
|
349
|
-
};
|
|
301
|
+
async function waitForClose(stream) {
|
|
302
|
+
return new Promise(async (resolve, reject) => {
|
|
303
|
+
stream.on("close", resolve);
|
|
304
|
+
stream.on("error", reject);
|
|
305
|
+
return stream;
|
|
306
|
+
});
|
|
350
307
|
}
|
|
351
|
-
exports.
|
|
308
|
+
exports.waitForClose = waitForClose;
|
|
352
309
|
async function copyFileWithStreams(source, target) {
|
|
353
310
|
const r = (0, fs_1.createReadStream)(source);
|
|
354
311
|
const w = (0, fs_2.createWriteStream)(target);
|
|
@@ -391,6 +348,7 @@ async function cpy(options) {
|
|
|
391
348
|
}
|
|
392
349
|
};
|
|
393
350
|
const task = async (rawEntryPath, basePath) => {
|
|
351
|
+
[rawEntryPath] = rawEntryPath.split(":");
|
|
394
352
|
const isDir = rawEntryPath.endsWith("/");
|
|
395
353
|
const entryPath = (0, path_1.normalize)(rawEntryPath);
|
|
396
354
|
const entrySourcePath = (0, path_1.resolve)((0, path_1.join)(basePath, rawEntryPath));
|
package/util/math-util.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.progressPercent = void 0;
|
|
4
4
|
function progressPercent(total, current) {
|
|
5
|
+
if (total === 0 && current === 0)
|
|
6
|
+
return 0;
|
|
5
7
|
return Number(((current / total) * 100).toFixed(2));
|
|
6
8
|
}
|
|
7
9
|
exports.progressPercent = progressPercent;
|
package/util/process-util.d.ts
CHANGED
package/util/process-util.js
CHANGED
|
@@ -11,6 +11,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
11
11
|
const child_process_1 = require("child_process");
|
|
12
12
|
const fs_1 = require("fs");
|
|
13
13
|
const promises_1 = require("fs/promises");
|
|
14
|
+
const readline_1 = require("readline");
|
|
14
15
|
function logExecStdout(input) {
|
|
15
16
|
let text = input.colorize ? chalk_1.default.grey(input.data) : input.data;
|
|
16
17
|
if (input.lineSalt)
|
|
@@ -70,7 +71,11 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
70
71
|
stderr: "",
|
|
71
72
|
exitCode: 0,
|
|
72
73
|
};
|
|
73
|
-
let finishListeners =
|
|
74
|
+
let finishListeners = 1;
|
|
75
|
+
if (pipe?.stream instanceof fs_1.WriteStream)
|
|
76
|
+
finishListeners++;
|
|
77
|
+
if (settings.stdout?.parseLines)
|
|
78
|
+
finishListeners++;
|
|
74
79
|
let streamError;
|
|
75
80
|
const tryFinish = () => {
|
|
76
81
|
if (!--finishListeners)
|
|
@@ -129,10 +134,11 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
129
134
|
if (log.stdout || settings.stdout) {
|
|
130
135
|
if (!p.stdout)
|
|
131
136
|
throw new Error(`stdout is not defined`);
|
|
132
|
-
|
|
137
|
+
const parseLines = settings.stdout?.parseLines;
|
|
138
|
+
const onData = (data) => {
|
|
133
139
|
if (log.stdout)
|
|
134
140
|
logExecStdout({
|
|
135
|
-
data: data.toString(),
|
|
141
|
+
data: parseLines ? `${data}\n` : data.toString(),
|
|
136
142
|
stderr: log.allToStderr,
|
|
137
143
|
colorize: log.colorize,
|
|
138
144
|
});
|
|
@@ -140,7 +146,17 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
140
146
|
spawnData.stdout += data.toString();
|
|
141
147
|
if (settings.stdout?.onData)
|
|
142
148
|
settings.stdout.onData(data.toString());
|
|
143
|
-
}
|
|
149
|
+
};
|
|
150
|
+
if (parseLines) {
|
|
151
|
+
const rl = (0, readline_1.createInterface)({
|
|
152
|
+
input: p.stdout,
|
|
153
|
+
});
|
|
154
|
+
rl.on("line", onData);
|
|
155
|
+
rl.on("close", tryFinish);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
p.stdout.on("data", onData);
|
|
159
|
+
}
|
|
144
160
|
}
|
|
145
161
|
if (log.stderr || settings.stderr) {
|
|
146
162
|
if (!p.stderr)
|
package/util/string-util.d.ts
CHANGED
|
@@ -15,5 +15,6 @@ export declare type UriType = {
|
|
|
15
15
|
export declare function formatUri(input: UriType, hidePassword?: boolean): string;
|
|
16
16
|
export declare function formatSeconds(seconds: number): string;
|
|
17
17
|
export declare function makePathPatterns(values: string[] | undefined): string[] | undefined;
|
|
18
|
+
export declare function checkPath(path: string, include: string[], exclude?: string[]): boolean;
|
|
18
19
|
export declare function checkMatch(subject: string | undefined, patterns: string[]): boolean;
|
|
19
20
|
export declare function formatDateTime(datetime: string): string;
|
package/util/string-util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatDateTime = exports.checkMatch = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.lcfirst = exports.ucfirst = exports.serialize = void 0;
|
|
3
|
+
exports.formatDateTime = exports.checkMatch = exports.checkPath = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.lcfirst = exports.ucfirst = exports.serialize = void 0;
|
|
4
4
|
const AppError_1 = require("../Error/AppError");
|
|
5
5
|
const micromatch_1 = require("micromatch");
|
|
6
6
|
function serialize(message, data) {
|
|
@@ -99,6 +99,13 @@ function makePathPatterns(values) {
|
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
exports.makePathPatterns = makePathPatterns;
|
|
102
|
+
function checkPath(path, include, exclude) {
|
|
103
|
+
return ((0, micromatch_1.isMatch)(path, include, {
|
|
104
|
+
dot: true,
|
|
105
|
+
}) &&
|
|
106
|
+
(!exclude || !(0, micromatch_1.isMatch)(path, exclude, { dot: true })));
|
|
107
|
+
}
|
|
108
|
+
exports.checkPath = checkPath;
|
|
102
109
|
function checkMatch(subject, patterns) {
|
|
103
110
|
if (!subject?.length)
|
|
104
111
|
subject = "<empty>";
|
package/util/zip-util.d.ts
CHANGED
|
@@ -3,20 +3,6 @@ export interface ZipDataFilterType {
|
|
|
3
3
|
exclude?: boolean;
|
|
4
4
|
patterns: string[];
|
|
5
5
|
}
|
|
6
|
-
export declare type ZipStreamDataType = {
|
|
7
|
-
type: "progress";
|
|
8
|
-
data: {
|
|
9
|
-
progress: number;
|
|
10
|
-
files: number;
|
|
11
|
-
path: string;
|
|
12
|
-
};
|
|
13
|
-
} | {
|
|
14
|
-
type: "summary";
|
|
15
|
-
data: {
|
|
16
|
-
folders: number;
|
|
17
|
-
files: number;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
6
|
export interface ZipDataType {
|
|
21
7
|
command?: string;
|
|
22
8
|
path: string;
|
|
@@ -26,7 +12,7 @@ export interface ZipDataType {
|
|
|
26
12
|
includeList?: string;
|
|
27
13
|
excludeList?: string;
|
|
28
14
|
verbose?: boolean;
|
|
29
|
-
onStream?: (data:
|
|
15
|
+
onStream?: (data: ZipStream) => void;
|
|
30
16
|
}
|
|
31
17
|
export interface UnzipDataType {
|
|
32
18
|
command?: string;
|
|
@@ -34,20 +20,60 @@ export interface UnzipDataType {
|
|
|
34
20
|
files?: (ZipDataFilterType | string)[];
|
|
35
21
|
output: string;
|
|
36
22
|
verbose?: boolean;
|
|
37
|
-
onStream?: (data:
|
|
23
|
+
onStream?: (data: UnzipStream) => void;
|
|
38
24
|
}
|
|
39
|
-
export declare
|
|
25
|
+
export declare function buildArguments(filters: (ZipDataFilterType | string)[]): string[];
|
|
26
|
+
export declare function checkSSEOption(command?: string): Promise<boolean>;
|
|
27
|
+
declare type ListZipStream = {
|
|
28
|
+
Path?: string;
|
|
29
|
+
Folder?: string;
|
|
30
|
+
Size?: string;
|
|
31
|
+
"Packed Size"?: string;
|
|
32
|
+
Modified?: string;
|
|
33
|
+
Created?: string;
|
|
34
|
+
Accessed?: string;
|
|
35
|
+
Attributes?: string;
|
|
36
|
+
Encrypted?: string;
|
|
37
|
+
Comment?: string;
|
|
38
|
+
CRC?: string;
|
|
39
|
+
Method?: string;
|
|
40
|
+
Characteristics?: string;
|
|
41
|
+
"Host OS"?: string;
|
|
42
|
+
Version?: string;
|
|
43
|
+
Volume?: string;
|
|
44
|
+
Offset?: string;
|
|
45
|
+
};
|
|
46
|
+
export declare function listZip(data: {
|
|
47
|
+
command?: string;
|
|
48
|
+
path: string;
|
|
49
|
+
onStream: (item: ListZipStream) => void;
|
|
50
|
+
verbose?: boolean;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
export declare type ZipStream = {
|
|
40
53
|
type: "progress";
|
|
41
54
|
data: {
|
|
42
55
|
progress: number;
|
|
43
56
|
files: number;
|
|
44
57
|
path: string;
|
|
45
58
|
};
|
|
59
|
+
} | {
|
|
60
|
+
type: "summary";
|
|
61
|
+
data: {
|
|
62
|
+
folders: number;
|
|
63
|
+
files: number;
|
|
64
|
+
};
|
|
46
65
|
};
|
|
47
|
-
export declare function buildArguments(filters: (ZipDataFilterType | string)[]): string[];
|
|
48
|
-
export declare function checkSSEOption(command?: string): Promise<boolean>;
|
|
49
66
|
export declare function zip(data: ZipDataType): Promise<{
|
|
50
67
|
folders: number;
|
|
51
68
|
files: number;
|
|
52
69
|
}>;
|
|
70
|
+
export declare type UnzipStream = {
|
|
71
|
+
type: "progress";
|
|
72
|
+
data: {
|
|
73
|
+
progress: number;
|
|
74
|
+
files: number;
|
|
75
|
+
path: string;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
53
78
|
export declare function unzip(data: UnzipDataType): Promise<import("./process-util").ExecResultType>;
|
|
79
|
+
export {};
|
package/util/zip-util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unzip = exports.zip = exports.checkSSEOption = exports.buildArguments = void 0;
|
|
3
|
+
exports.unzip = exports.zip = exports.listZip = exports.checkSSEOption = exports.buildArguments = void 0;
|
|
4
4
|
const process_util_1 = require("./process-util");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
function buildArguments(filters) {
|
|
@@ -30,36 +30,6 @@ function buildArguments(filters) {
|
|
|
30
30
|
return args;
|
|
31
31
|
}
|
|
32
32
|
exports.buildArguments = buildArguments;
|
|
33
|
-
function parseZipStream(chunk, buffer, cb) {
|
|
34
|
-
const lines = chunk.replaceAll("\b", "").trim().split(/\r?\n/);
|
|
35
|
-
for (const line of lines) {
|
|
36
|
-
let matches = null;
|
|
37
|
-
if ((matches = /^(\d+)% (\d+ )?\+/.exec(line))) {
|
|
38
|
-
const path = line.slice(line.indexOf("+") + 1).trim();
|
|
39
|
-
const progress = Number(matches[1]);
|
|
40
|
-
if (!buffer.currentPaths)
|
|
41
|
-
buffer.currentPaths = 0;
|
|
42
|
-
if (path !== buffer.lastPath)
|
|
43
|
-
buffer.currentPaths++;
|
|
44
|
-
buffer.lastPath = path;
|
|
45
|
-
cb({
|
|
46
|
-
type: "progress",
|
|
47
|
-
data: { progress, path, files: buffer.currentPaths },
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
else if (line.startsWith("Add new data to archive:")) {
|
|
51
|
-
const [, folders] = /(\d+) folders?/i.exec(line) || [, 0];
|
|
52
|
-
const [, files] = /(\d+) files?/i.exec(line) || [, 0];
|
|
53
|
-
cb({
|
|
54
|
-
type: "summary",
|
|
55
|
-
data: {
|
|
56
|
-
folders: Number(folders),
|
|
57
|
-
files: Number(files),
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
33
|
let checkSSEOptionResult;
|
|
64
34
|
async function checkSSEOption(command = "7z") {
|
|
65
35
|
const result = await (0, process_util_1.exec)(command);
|
|
@@ -68,12 +38,81 @@ async function checkSSEOption(command = "7z") {
|
|
|
68
38
|
return (checkSSEOptionResult = result.stdout.includes(" -sse"));
|
|
69
39
|
}
|
|
70
40
|
exports.checkSSEOption = checkSSEOption;
|
|
41
|
+
const listZipLineEqChar = " = ";
|
|
42
|
+
function parseListZipLine(line, buffer) {
|
|
43
|
+
if (buffer.started) {
|
|
44
|
+
if (line === "") {
|
|
45
|
+
if (buffer.opened) {
|
|
46
|
+
const { stream } = buffer;
|
|
47
|
+
buffer.stream = {};
|
|
48
|
+
buffer.opened = false;
|
|
49
|
+
return stream;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const separator = line.indexOf(listZipLineEqChar);
|
|
54
|
+
const key = line.slice(0, separator);
|
|
55
|
+
const value = line.slice(separator + listZipLineEqChar.length);
|
|
56
|
+
buffer.opened = true;
|
|
57
|
+
buffer.stream[key] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (line.startsWith("----------")) {
|
|
61
|
+
buffer.started = true;
|
|
62
|
+
buffer.stream = {};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function listZip(data) {
|
|
66
|
+
const buffer = {};
|
|
67
|
+
await (0, process_util_1.exec)(data.command ?? "7z", ["l", data.path, "-slt"], {}, {
|
|
68
|
+
log: {
|
|
69
|
+
exec: data.verbose ?? false,
|
|
70
|
+
stderr: data.verbose ?? false,
|
|
71
|
+
stdout: false,
|
|
72
|
+
},
|
|
73
|
+
onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
|
|
74
|
+
stdout: {
|
|
75
|
+
parseLines: true,
|
|
76
|
+
onData: (line) => {
|
|
77
|
+
const stream = parseListZipLine(line, buffer);
|
|
78
|
+
if (stream) {
|
|
79
|
+
data.onStream?.(stream);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
exports.listZip = listZip;
|
|
86
|
+
function parseZipLine(line) {
|
|
87
|
+
let matches = null;
|
|
88
|
+
if (!line.trim().length)
|
|
89
|
+
return;
|
|
90
|
+
if ((matches = /^\s*(\d+)% (\d+ )?\+/.exec(line))) {
|
|
91
|
+
const path = line.slice(line.indexOf("+") + 1).trim();
|
|
92
|
+
const progress = Number(matches[1]);
|
|
93
|
+
const files = Number(matches[2]);
|
|
94
|
+
return {
|
|
95
|
+
type: "progress",
|
|
96
|
+
data: { progress, path, files },
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
else if (line.startsWith("Add new data to archive:")) {
|
|
100
|
+
const [, folders] = /(\d+) folders?/i.exec(line) || [, 0];
|
|
101
|
+
const [, files] = /(\d+) files?/i.exec(line) || [, 0];
|
|
102
|
+
return {
|
|
103
|
+
type: "summary",
|
|
104
|
+
data: {
|
|
105
|
+
folders: Number(folders),
|
|
106
|
+
files: Number(files),
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
71
111
|
async function zip(data) {
|
|
72
112
|
let result = {
|
|
73
113
|
folders: 0,
|
|
74
114
|
files: 0,
|
|
75
115
|
};
|
|
76
|
-
let buffer = {};
|
|
77
116
|
await (0, process_util_1.exec)(data.command ?? "7z", [
|
|
78
117
|
"a",
|
|
79
118
|
// https://sourceforge.net/p/sevenzip/bugs/2099/,
|
|
@@ -91,31 +130,29 @@ async function zip(data) {
|
|
|
91
130
|
log: data.verbose ?? false,
|
|
92
131
|
onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
|
|
93
132
|
stdout: {
|
|
94
|
-
onData: (
|
|
95
|
-
|
|
133
|
+
onData: (line) => {
|
|
134
|
+
const stream = parseZipLine(line);
|
|
135
|
+
if (stream) {
|
|
96
136
|
data.onStream?.(stream);
|
|
97
137
|
if (stream.type === "summary")
|
|
98
138
|
result = stream.data;
|
|
99
|
-
}
|
|
139
|
+
}
|
|
100
140
|
},
|
|
101
141
|
},
|
|
102
142
|
});
|
|
103
143
|
return result;
|
|
104
144
|
}
|
|
105
145
|
exports.zip = zip;
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
data: { progress, path, files },
|
|
117
|
-
});
|
|
118
|
-
}
|
|
146
|
+
function parseUnzipLine(line) {
|
|
147
|
+
let matches = null;
|
|
148
|
+
if ((matches = /^\s*(\d+)% (\d+) \-/.exec(line))) {
|
|
149
|
+
const progress = Number(matches[1]);
|
|
150
|
+
const files = Number(matches[2]);
|
|
151
|
+
const path = line.slice(line.indexOf("-") + 1).trim();
|
|
152
|
+
return {
|
|
153
|
+
type: "progress",
|
|
154
|
+
data: { progress, path, files },
|
|
155
|
+
};
|
|
119
156
|
}
|
|
120
157
|
}
|
|
121
158
|
async function unzip(data) {
|
|
@@ -131,9 +168,11 @@ async function unzip(data) {
|
|
|
131
168
|
stderr: { toExitCode: true },
|
|
132
169
|
stdout: {
|
|
133
170
|
...(data.onStream && {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
171
|
+
parseLines: true,
|
|
172
|
+
onData: (line) => {
|
|
173
|
+
const stream = parseUnzipLine(line);
|
|
174
|
+
if (stream)
|
|
175
|
+
data.onStream(stream);
|
|
137
176
|
},
|
|
138
177
|
}),
|
|
139
178
|
},
|