@datatruck/cli 0.13.0 → 0.15.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.
Files changed (36) hide show
  1. package/Action/BackupAction.js +3 -15
  2. package/Action/RestoreAction.js +2 -10
  3. package/Command/BackupCommand.js +2 -1
  4. package/Command/BackupSessionsCommand.js +1 -0
  5. package/Command/RestoreCommand.js +1 -1
  6. package/Command/RestoreSessionsCommand.js +1 -0
  7. package/Entity/StateEntityAbstract.d.ts +2 -1
  8. package/Repository/DatatruckRepository.d.ts +2 -0
  9. package/Repository/DatatruckRepository.js +239 -108
  10. package/Repository/RepositoryAbstract.d.ts +10 -5
  11. package/Repository/ResticRepository.js +34 -17
  12. package/SessionDriver/ConsoleSessionDriver.d.ts +2 -3
  13. package/SessionDriver/ConsoleSessionDriver.js +11 -10
  14. package/SessionManager/BackupSessionManager.d.ts +10 -11
  15. package/SessionManager/BackupSessionManager.js +24 -5
  16. package/SessionManager/RestoreSessionManager.d.ts +12 -11
  17. package/SessionManager/RestoreSessionManager.js +24 -5
  18. package/SessionManager/SessionManagerAbstract.d.ts +14 -0
  19. package/SessionManager/SessionManagerAbstract.js +21 -0
  20. package/Task/GitTask.js +23 -14
  21. package/Task/MariadbTask.js +9 -4
  22. package/Task/SqlDumpTaskAbstract.js +31 -10
  23. package/Task/TaskAbstract.d.ts +10 -5
  24. package/cli.js +1 -1
  25. package/config.schema.json +4 -0
  26. package/migrations/001-initial.sql +12 -6
  27. package/package.json +1 -1
  28. package/util/fs-util.d.ts +27 -21
  29. package/util/fs-util.js +89 -101
  30. package/util/math-util.js +2 -0
  31. package/util/process-util.d.ts +1 -0
  32. package/util/process-util.js +20 -4
  33. package/util/string-util.d.ts +1 -0
  34. package/util/string-util.js +8 -1
  35. package/util/zip-util.d.ts +64 -19
  36. package/util/zip-util.js +156 -59
@@ -77,11 +77,7 @@ class BackupAction {
77
77
  onProgress: async (data) => {
78
78
  await session.progressTask({
79
79
  id: taskId,
80
- progressCurrent: data.current,
81
- progressPercent: data.percent,
82
- progressStep: data.step,
83
- progressStepPercent: data.stepPercent,
84
- progressTotal: data.total,
80
+ ...data,
85
81
  });
86
82
  },
87
83
  });
@@ -123,11 +119,7 @@ class BackupAction {
123
119
  onProgress: async (data) => {
124
120
  await session.progressRepository({
125
121
  id: repositoryId,
126
- progressCurrent: data.current,
127
- progressPercent: data.percent,
128
- progressStep: data.step,
129
- progressStepPercent: data.stepPercent,
130
- progressTotal: data.total,
122
+ ...data,
131
123
  });
132
124
  },
133
125
  });
@@ -167,11 +159,7 @@ class BackupAction {
167
159
  onProgress: async (data) => {
168
160
  await session.progressRepository({
169
161
  id: repositoryId,
170
- progressCurrent: data.current,
171
- progressPercent: data.percent,
172
- progressStep: data.step,
173
- progressStepPercent: data.stepPercent,
174
- progressTotal: data.total,
162
+ ...data,
175
163
  });
176
164
  },
177
165
  });
@@ -114,11 +114,7 @@ class RestoreAction {
114
114
  onProgress: async (data) => {
115
115
  await session.progressTask({
116
116
  id: taskId,
117
- progressCurrent: data.current,
118
- progressPercent: data.percent,
119
- progressStep: data.step,
120
- progressStepPercent: data.stepPercent,
121
- progressTotal: data.total,
117
+ ...data,
122
118
  });
123
119
  },
124
120
  });
@@ -163,11 +159,7 @@ class RestoreAction {
163
159
  onProgress: async (data) => {
164
160
  await session.progressRepository({
165
161
  id: repositoryId,
166
- progressCurrent: data.current,
167
- progressPercent: data.percent,
168
- progressStep: data.step,
169
- progressStepPercent: data.stepPercent,
170
- progressTotal: data.total,
162
+ ...data,
171
163
  });
172
164
  },
173
165
  });
@@ -68,9 +68,10 @@ class BackupCommand extends CommandAbstract_1.CommandAbstract {
68
68
  new ConsoleSessionDriver_1.ConsoleSessionDriver({
69
69
  verbose: verbose > 0,
70
70
  progress: this.globalOptions.progress,
71
- progressInterval: this.globalOptions.progressInterval,
72
71
  }),
73
72
  ],
73
+ verbose: verbose > 1,
74
+ progressInterval: this.globalOptions.progressInterval,
74
75
  });
75
76
  const result = await backup.exec(sessionManager);
76
77
  if (result.errors) {
@@ -50,6 +50,7 @@ class BackupSessionsCommand extends CommandAbstract_1.CommandAbstract {
50
50
  verbose: verbose > 1,
51
51
  }),
52
52
  verbose: verbose > 1,
53
+ progressInterval: this.globalOptions.progressInterval,
53
54
  });
54
55
  const items = await action.exec(manager);
55
56
  const dataFormat = new DataFormat_1.DataFormat({
@@ -68,10 +68,10 @@ class RestoreCommand extends CommandAbstract_1.CommandAbstract {
68
68
  new ConsoleSessionDriver_1.ConsoleSessionDriver({
69
69
  verbose: verbose > 0,
70
70
  progress: this.globalOptions.progress,
71
- progressInterval: this.globalOptions.progressInterval,
72
71
  }),
73
72
  ],
74
73
  verbose: verbose > 1,
74
+ progressInterval: this.globalOptions.progressInterval,
75
75
  });
76
76
  const result = await restore.exec(sessionManager);
77
77
  return result ? 0 : 1;
@@ -49,6 +49,7 @@ class RestoreSessionsCommand extends CommandAbstract_1.CommandAbstract {
49
49
  driver: new SqliteSessionDriver_1.SqliteSessionDriver({
50
50
  verbose: verbose > 1,
51
51
  }),
52
+ progressInterval: this.globalOptions.progressInterval,
52
53
  });
53
54
  const items = await action.exec(manager);
54
55
  const dataFormat = new DataFormat_1.DataFormat({
@@ -7,6 +7,7 @@ export declare abstract class StateEntityAbstract extends CrudEntityAbstract {
7
7
  progressTotal?: number | null;
8
8
  progressCurrent?: number | null;
9
9
  progressPercent?: number | null;
10
- progressStep?: string | null;
10
+ progressStepDescription?: string | null;
11
+ progressStepItem?: string | null;
11
12
  progressStepPercent?: number | null;
12
13
  }
@@ -19,6 +19,7 @@ export declare type DatatruckRepositoryConfigType = {
19
19
  };
20
20
  declare type CompressObjectType = {
21
21
  packs?: {
22
+ name?: string;
22
23
  include: string[];
23
24
  exclude?: string[];
24
25
  onePackByResult?: boolean;
@@ -48,6 +49,7 @@ export declare class DatatruckRepository extends RepositoryAbstract<DatatruckRep
48
49
  static stringifyMetaData(data: MetaDataType): string;
49
50
  onGetSource(): string;
50
51
  onInit(data: InitDataType): Promise<void>;
52
+ private createFileScanner;
51
53
  onPrune(data: PruneDataType): Promise<void>;
52
54
  onSnapshots(data: SnapshotsDataType): Promise<SnapshotResultType[]>;
53
55
  private normalizeCompressConfig;
@@ -19,6 +19,7 @@ const fs_1 = require("fs");
19
19
  const promises_1 = require("fs/promises");
20
20
  const micromatch_1 = require("micromatch");
21
21
  const path_1 = require("path");
22
+ const perf_hooks_1 = require("perf_hooks");
22
23
  const readline_1 = require("readline");
23
24
  exports.datatruckRepositoryName = "datatruck";
24
25
  exports.datatruckRepositoryDefinition = {
@@ -50,6 +51,7 @@ exports.datatruckPackageRepositoryDefinition = {
50
51
  additionalProperties: false,
51
52
  required: ["include"],
52
53
  properties: {
54
+ name: { type: "string" },
53
55
  include: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
54
56
  exclude: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
55
57
  onePackByResult: { type: "boolean" },
@@ -102,6 +104,67 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
102
104
  async onInit(data) {
103
105
  await (0, fs_util_1.mkdirIfNotExists)(this.config.outPath);
104
106
  }
107
+ async createFileScanner(options) {
108
+ const object = {
109
+ total: 0,
110
+ current: 0,
111
+ progress: async (description, data) => {
112
+ await options.onProgress({
113
+ step: {
114
+ description,
115
+ item: data.path,
116
+ percent: data.percent,
117
+ },
118
+ stats: {
119
+ total: object.total,
120
+ current: object.current + data.current,
121
+ percent: (0, math_util_1.progressPercent)(object.total, object.current + data.current),
122
+ },
123
+ });
124
+ if (data.type === "end") {
125
+ object.current += data.current;
126
+ }
127
+ },
128
+ start: async (cb) => {
129
+ for await (const entry of (0, fs_util_1.pathIterator)(stream)) {
130
+ if (!options.disableCounting)
131
+ object.total++;
132
+ const currentTime = perf_hooks_1.performance.now();
133
+ const diff = currentTime - lastTime;
134
+ if (diff > 1000) {
135
+ await options.onProgress({
136
+ step: {
137
+ description: "Scanning files",
138
+ item: object.total.toString(),
139
+ },
140
+ });
141
+ lastTime = currentTime;
142
+ }
143
+ if (cb)
144
+ await cb(entry);
145
+ }
146
+ await options.onProgress({
147
+ step: {
148
+ description: "Scanned files",
149
+ item: object.total.toString(),
150
+ },
151
+ });
152
+ },
153
+ };
154
+ await options.onProgress({
155
+ step: {
156
+ description: "Scanning files",
157
+ },
158
+ });
159
+ const stream = fast_glob_1.default.stream(options.glob.include, {
160
+ dot: true,
161
+ markDirectories: true,
162
+ stats: true,
163
+ ...options.glob,
164
+ });
165
+ let lastTime = perf_hooks_1.performance.now();
166
+ return object;
167
+ }
105
168
  async onPrune(data) {
106
169
  const snapshotName = DatatruckRepository.buildSnapshotName({
107
170
  snapshotId: data.snapshot.id,
@@ -160,7 +223,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
160
223
  }
161
224
  normalizeCompressConfig(packageConfig) {
162
225
  let compress = packageConfig?.compress ?? this.config.compress;
163
- if (compress === true) {
226
+ if (compress === true || (compress && !Array.isArray(compress.packs))) {
164
227
  return {
165
228
  packs: [
166
229
  {
@@ -198,94 +261,124 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
198
261
  verbose: data.options.verbose,
199
262
  })
200
263
  : undefined;
201
- const stream = fast_glob_1.default.stream(include, {
202
- cwd: sourcePath,
203
- ignore: exclude,
204
- dot: true,
205
- onlyFiles: compress ? false : true,
206
- markDirectories: true,
207
- });
264
+ const packs = compress?.packs || [];
265
+ const tmpDir = await (0, fs_util_1.mkTmpDir)("path-lists");
266
+ const nonPackStream = (0, fs_1.createWriteStream)((0, path_1.join)(tmpDir, "nonpack.txt"));
267
+ const singlePackStream = (0, fs_1.createWriteStream)((0, path_1.join)(tmpDir, "single-pack.txt"));
268
+ const packStreams = Array.from({ length: packs.length }).map((v, i) => (0, fs_1.createWriteStream)((0, path_1.join)(tmpDir, `pack-${i}.txt`)));
269
+ const streams = [nonPackStream, singlePackStream, ...packStreams];
208
270
  if (data.options.verbose)
209
- (0, cli_util_1.logExec)(`Writing paths lists`);
210
- const pathLists = await (0, fs_util_1.writePathLists)({
211
- paths: stream,
212
- packs: compress?.packs,
271
+ (0, cli_util_1.logExec)(`Writing file lists in ${tmpDir}`);
272
+ const scanner = await this.createFileScanner({
273
+ glob: {
274
+ include,
275
+ cwd: sourcePath,
276
+ ignore: exclude,
277
+ onlyFiles: false,
278
+ },
279
+ onProgress: data.onProgress,
280
+ disableCounting: true,
213
281
  });
214
- if (data.options.verbose)
215
- (0, cli_util_1.logExec)(`Path lists: ${pathLists.path}`);
216
- let currentFiles = 0;
217
- if (compress?.packs) {
218
- let packIndex = 0;
219
- for (const packsPath of pathLists.includedPackPaths) {
220
- const pack = compress.packs[packIndex];
221
- if (pack.onePackByResult) {
222
- const reader = (0, readline_1.createInterface)({
223
- input: (0, fs_1.createReadStream)(packsPath),
224
- });
225
- let multipleIndex = 0;
226
- for await (let packPath of reader) {
227
- if (packPath.endsWith("/"))
228
- packPath = packPath.slice(0, -1);
229
- const target = (0, path_1.join)(outPath, `.${packIndex}-${multipleIndex++}-${encodeURIComponent(packPath.replace(/[\\/]/g, "-")).slice(0, 255)}.dd.zip`);
230
- const stats = await (0, zip_util_1.zip)({
231
- path: pkg.path,
232
- output: target,
233
- filter: [{ patterns: [packPath] }],
234
- excludeList: pathLists.excludedPackPaths[packIndex],
235
- verbose: data.options.verbose,
236
- onStream: async (stream) => await data.onProgress({
237
- total: pathLists.total.all,
238
- current: currentFiles + stream.data.files,
239
- percent: (0, math_util_1.progressPercent)(pathLists.total.all, currentFiles + stream.data.files),
240
- step: stream.type === "progress" ? stream.data.path : "",
241
- stepPercent: stream.type === "progress" ? stream.data.progress : null,
242
- }),
243
- });
244
- currentFiles += stats.files;
282
+ await Promise.all([
283
+ ...streams.map((p) => (0, fs_util_1.waitForClose)(p)),
284
+ (async () => {
285
+ await scanner.start(async (entry) => {
286
+ const pathSubject = entry.stats.isDirectory()
287
+ ? entry.path.slice(0, -1)
288
+ : entry.path;
289
+ let stream = nonPackStream;
290
+ let successPackIndex;
291
+ for (const [packIndex, pack] of packs.entries()) {
292
+ if ((0, string_util_1.checkPath)(pathSubject, pack.include, pack.exclude)) {
293
+ stream = pack.onePackByResult
294
+ ? singlePackStream
295
+ : packStreams[packIndex];
296
+ successPackIndex = packIndex;
297
+ break;
298
+ }
245
299
  }
300
+ const isNonPackStream = stream === nonPackStream;
301
+ const isPackStream = stream !== nonPackStream;
302
+ const isSinglePackStream = stream === singlePackStream;
303
+ const include = isPackStream
304
+ ? entry.stats.isDirectory()
305
+ ? await (0, fs_util_1.isEmptyDir)(entry.path)
306
+ : true
307
+ : true;
308
+ if (include) {
309
+ let value = entry.path;
310
+ if (isNonPackStream) {
311
+ value += `:${entry.stats.uid}:${entry.stats.gid}:${entry.stats.mode}`;
312
+ }
313
+ else if (isSinglePackStream) {
314
+ value += `:${successPackIndex}`;
315
+ }
316
+ if (!entry.stats.isDirectory())
317
+ scanner.total++;
318
+ stream.write(`${value}\n`);
319
+ }
320
+ });
321
+ for (const stream of streams) {
322
+ stream.end();
246
323
  }
247
- else {
248
- const target = (0, path_1.join)(outPath, `.${packIndex}.dd.zip`);
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;
263
- }
264
- packIndex++;
265
- }
266
- }
324
+ })(),
325
+ ]);
326
+ const dttFolder = `.dtt-${data.snapshot.id.slice(0, 8)}`;
327
+ const dttPath = (0, path_1.join)(outPath, dttFolder);
328
+ await (0, promises_1.mkdir)(dttPath);
329
+ await (0, promises_1.copyFile)(nonPackStream.path, (0, path_1.join)(dttPath, "permissions.txt"));
330
+ // Non pack
267
331
  if (data.options.verbose)
268
- (0, cli_util_1.logExec)(`Copying files to ${outPath}`);
332
+ (0, cli_util_1.logExec)(`Copying files from ${nonPackStream.path.toString()} to ${outPath}`);
269
333
  await (0, fs_util_1.cpy)({
270
334
  input: {
271
335
  type: "pathList",
272
- path: pathLists.path,
336
+ path: nonPackStream.path.toString(),
273
337
  basePath: sourcePath,
274
338
  },
275
339
  targetPath: outPath,
340
+ skipNotFoundError: true,
276
341
  concurrency: this.config.fileCopyConcurrency,
277
- async onPath({ isDir, entryPath }) {
278
- if (isDir)
279
- return;
280
- currentFiles++;
281
- await data.onProgress({
282
- total: pathLists.total.all,
283
- current: currentFiles,
284
- percent: (0, math_util_1.progressPercent)(pathLists.total.all, currentFiles),
285
- step: entryPath,
286
- });
287
- },
342
+ onProgress: async (progress) => await scanner.progress(progress.type === "end" ? "Files copied" : "Copying file", progress),
343
+ });
344
+ // Single pack
345
+ const singleReader = (0, readline_1.createInterface)({
346
+ input: (0, fs_1.createReadStream)(singlePackStream.path),
288
347
  });
348
+ for await (const line of singleReader) {
349
+ let [packPath, packIndex] = line.split(":");
350
+ const pack = packs[packIndex];
351
+ if (packPath.endsWith("/"))
352
+ packPath = packPath.slice(0, -1);
353
+ const outBasename = (`pack${pack.name ? `-${encodeURIComponent(pack.name)}` : ""}` +
354
+ `-${encodeURIComponent(packPath.replace(/[\\/]/g, "-"))}` +
355
+ `.zip`).slice(0, 255);
356
+ const target = (0, path_1.join)(dttPath, outBasename);
357
+ await (0, zip_util_1.zip)({
358
+ path: pkg.path,
359
+ output: target,
360
+ filter: [{ patterns: [packPath] }],
361
+ verbose: data.options.verbose,
362
+ onProgress: async (progress) => await scanner.progress(progress.type === "start"
363
+ ? "Starting compressing"
364
+ : "Compressing file", progress),
365
+ });
366
+ }
367
+ // Packs
368
+ for (const [packIndex, packStream] of packStreams.entries()) {
369
+ const pack = packs[packIndex];
370
+ const target = (0, path_1.join)(dttPath, `pack-${packIndex}${pack.name ? `-${pack.name}` : ""}.zip`);
371
+ await (0, zip_util_1.zip)({
372
+ path: sourcePath,
373
+ output: target,
374
+ includeList: packStream.path.toString(),
375
+ verbose: data.options.verbose,
376
+ onProgress: async (progress) => await scanner.progress(progress.type === "start"
377
+ ? "Starting compressing"
378
+ : "Compressing file", progress),
379
+ });
380
+ }
381
+ // Meta
289
382
  const metaPath = `${outPath}.json`;
290
383
  const nodePkg = (0, fs_util_1.parsePackageFile)();
291
384
  const meta = {
@@ -295,7 +388,8 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
295
388
  package: data.package.name,
296
389
  task: data.package.task?.name,
297
390
  version: nodePkg.version,
298
- size: await (0, fs_util_1.fastFolderSizeAsync)(outPath),
391
+ size: (await (0, fs_util_1.fastFolderSizeAsync)(outPath)) -
392
+ (await (0, fs_util_1.fastFolderSizeAsync)(dttPath)),
299
393
  };
300
394
  if (data.options.verbose)
301
395
  (0, cli_util_1.logExec)(`Writing metadata into ${metaPath}`);
@@ -312,14 +406,23 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
312
406
  const sourceMetaPath = `${sourcePath}.json`;
313
407
  const targetMetaPath = `${targetPath}.json`;
314
408
  if (data.options.verbose)
315
- (0, cli_util_1.logExec)(`Copying files to ${targetPath}`);
409
+ (0, cli_util_1.logExec)(`Copying backup files to ${targetPath}`);
316
410
  await (0, promises_1.mkdir)(targetPath);
411
+ const scanner = await this.createFileScanner({
412
+ glob: {
413
+ include: ["**/*"],
414
+ cwd: sourcePath,
415
+ },
416
+ onProgress: data.onProgress,
417
+ });
418
+ await scanner.start();
317
419
  await (0, fs_util_1.cpy)({
318
420
  input: {
319
421
  type: "glob",
320
422
  sourcePath,
321
423
  },
322
424
  targetPath,
425
+ onProgress: async (progress) => await scanner.progress(progress.type === "end" ? "Files copied" : "Copying file", progress),
323
426
  });
324
427
  await (0, promises_1.copyFile)(sourceMetaPath, targetMetaPath);
325
428
  }
@@ -340,50 +443,78 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
340
443
  packageName: data.package.name,
341
444
  });
342
445
  const sourcePath = (0, path_1.join)(this.config.outPath, snapshotName);
343
- let totalFiles = 0;
344
- let currentFiles = -1;
345
- await (0, fs_util_1.forEachFile)(sourcePath, () => {
346
- totalFiles++;
347
- }, true);
446
+ const dttFolder = `.dtt-${data.snapshot.id.slice(0, 8)}`;
447
+ const dttPath = (0, path_1.join)(sourcePath, dttFolder);
448
+ const scanner = await this.createFileScanner({
449
+ glob: {
450
+ include: ["**/*"],
451
+ cwd: sourcePath,
452
+ ignore: [dttFolder],
453
+ },
454
+ onProgress: data.onProgress,
455
+ });
456
+ await scanner.start();
457
+ const dttPathExists = await (0, fs_util_1.checkDir)(dttPath);
458
+ if (dttPathExists) {
459
+ const it = await (0, promises_1.opendir)(dttPath);
460
+ for await (const dirent of it) {
461
+ const path = (0, path_1.join)(dttPath, dirent.name);
462
+ if (dirent.name === "permissions.txt") {
463
+ scanner.total++;
464
+ }
465
+ else if (dirent.name.endsWith(".zip")) {
466
+ await (0, zip_util_1.listZip)({
467
+ path,
468
+ verbose: data.options.verbose,
469
+ onStream: async (item) => {
470
+ const isDir = item.Folder === "+";
471
+ if (!isDir)
472
+ scanner.total++;
473
+ },
474
+ });
475
+ }
476
+ }
477
+ }
348
478
  if (data.options.verbose)
349
479
  (0, cli_util_1.logExec)(`Copying files to ${restorePath}`);
350
480
  await (0, fs_util_1.cpy)({
351
481
  input: {
352
482
  type: "glob",
353
483
  sourcePath,
484
+ exclude: [dttFolder],
354
485
  },
355
486
  targetPath: restorePath,
356
487
  concurrency: this.config.fileCopyConcurrency,
357
- onPath: async ({ entryPath, entrySourcePath }) => {
358
- const isRootFile = (0, path_1.basename)(entryPath) === entryPath;
359
- const isZipFile = isRootFile &&
360
- entryPath.startsWith(".") &&
361
- entryPath.endsWith(".dd.zip");
362
- await data.onProgress({
363
- total: totalFiles,
364
- current: Math.max(currentFiles, 0),
365
- percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
366
- step: entryPath,
367
- });
368
- if (isZipFile) {
488
+ onProgress: async (progress) => await scanner.progress(progress.type === "end" ? "Files copied" : "Copying file", progress),
489
+ });
490
+ if (dttPathExists) {
491
+ const it = await (0, promises_1.opendir)(dttPath);
492
+ for await (const dirent of it) {
493
+ const path = (0, path_1.join)(dttPath, dirent.name);
494
+ if (dirent.name === "permissions.txt") {
495
+ if (data.options.verbose)
496
+ (0, cli_util_1.logExec)(`Applying permissions (${path})`);
497
+ await scanner.progress("Applying permissions", {
498
+ current: 0,
499
+ });
500
+ await (0, fs_util_1.applyPermissions)(restorePath, path);
501
+ await scanner.progress("Permissions applied", {
502
+ current: 1,
503
+ type: "end",
504
+ });
505
+ }
506
+ else if (dirent.name.endsWith(".zip")) {
369
507
  await (0, zip_util_1.unzip)({
370
- input: entrySourcePath,
508
+ input: path,
371
509
  output: restorePath,
372
510
  verbose: data.options.verbose,
373
- onStream: async (stream) => await data.onProgress({
374
- total: totalFiles,
375
- current: currentFiles + 1,
376
- percent: (0, math_util_1.progressPercent)(totalFiles, currentFiles + 1),
377
- step: stream.type === "progress"
378
- ? `Extracting ${stream.data.path}`
379
- : "",
380
- }),
511
+ onProgress: async (progress) => await scanner.progress(progress.type === "start"
512
+ ? "Starting extracting"
513
+ : "Extracting file", progress),
381
514
  });
382
515
  }
383
- currentFiles++;
384
- return isZipFile ? false : true;
385
- },
386
- });
516
+ }
517
+ }
387
518
  }
388
519
  }
389
520
  exports.DatatruckRepository = DatatruckRepository;
@@ -16,11 +16,16 @@ export declare type SnapshotResultType = SnapshotType & {
16
16
  size: number;
17
17
  };
18
18
  export declare type ProgressDataType = {
19
- total?: number;
20
- current?: number;
21
- percent?: number;
22
- step?: string;
23
- stepPercent?: number | null;
19
+ stats?: {
20
+ total?: number;
21
+ current?: number;
22
+ percent?: number;
23
+ };
24
+ step?: {
25
+ description?: string;
26
+ item?: string;
27
+ percent?: number | null;
28
+ };
24
29
  };
25
30
  export declare type InitDataType = {
26
31
  options: InitActionOptionsType;