@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.
- package/Action/BackupAction.js +3 -15
- package/Action/RestoreAction.js +2 -10
- package/Command/BackupCommand.js +2 -1
- package/Command/BackupSessionsCommand.js +1 -0
- package/Command/RestoreCommand.js +1 -1
- package/Command/RestoreSessionsCommand.js +1 -0
- package/Entity/StateEntityAbstract.d.ts +2 -1
- package/Repository/DatatruckRepository.d.ts +2 -0
- package/Repository/DatatruckRepository.js +239 -108
- package/Repository/RepositoryAbstract.d.ts +10 -5
- package/Repository/ResticRepository.js +34 -17
- package/SessionDriver/ConsoleSessionDriver.d.ts +2 -3
- package/SessionDriver/ConsoleSessionDriver.js +11 -10
- package/SessionManager/BackupSessionManager.d.ts +10 -11
- package/SessionManager/BackupSessionManager.js +24 -5
- package/SessionManager/RestoreSessionManager.d.ts +12 -11
- package/SessionManager/RestoreSessionManager.js +24 -5
- package/SessionManager/SessionManagerAbstract.d.ts +14 -0
- package/SessionManager/SessionManagerAbstract.js +21 -0
- package/Task/GitTask.js +23 -14
- package/Task/MariadbTask.js +9 -4
- package/Task/SqlDumpTaskAbstract.js +31 -10
- package/Task/TaskAbstract.d.ts +10 -5
- package/cli.js +1 -1
- package/config.schema.json +4 -0
- package/migrations/001-initial.sql +12 -6
- package/package.json +1 -1
- package/util/fs-util.d.ts +27 -21
- package/util/fs-util.js +89 -101
- 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 +64 -19
- package/util/zip-util.js +156 -59
package/Action/BackupAction.js
CHANGED
|
@@ -77,11 +77,7 @@ class BackupAction {
|
|
|
77
77
|
onProgress: async (data) => {
|
|
78
78
|
await session.progressTask({
|
|
79
79
|
id: taskId,
|
|
80
|
-
|
|
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
|
-
|
|
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
|
-
|
|
171
|
-
progressPercent: data.percent,
|
|
172
|
-
progressStep: data.step,
|
|
173
|
-
progressStepPercent: data.stepPercent,
|
|
174
|
-
progressTotal: data.total,
|
|
162
|
+
...data,
|
|
175
163
|
});
|
|
176
164
|
},
|
|
177
165
|
});
|
package/Action/RestoreAction.js
CHANGED
|
@@ -114,11 +114,7 @@ class RestoreAction {
|
|
|
114
114
|
onProgress: async (data) => {
|
|
115
115
|
await session.progressTask({
|
|
116
116
|
id: taskId,
|
|
117
|
-
|
|
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
|
-
|
|
167
|
-
progressPercent: data.percent,
|
|
168
|
-
progressStep: data.step,
|
|
169
|
-
progressStepPercent: data.stepPercent,
|
|
170
|
-
progressTotal: data.total,
|
|
162
|
+
...data,
|
|
171
163
|
});
|
|
172
164
|
},
|
|
173
165
|
});
|
package/Command/BackupCommand.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
215
|
-
(0,
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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:
|
|
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
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
344
|
-
|
|
345
|
-
await
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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:
|
|
508
|
+
input: path,
|
|
371
509
|
output: restorePath,
|
|
372
510
|
verbose: data.options.verbose,
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
|
|
384
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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;
|