@datatruck/cli 0.34.4 → 0.34.5
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/lib/actions/BackupAction.js +123 -38
- package/lib/actions/CopyAction.js +40 -18
- package/lib/actions/InitAction.js +1 -1
- package/lib/actions/RestoreAction.d.ts +0 -2
- package/lib/actions/RestoreAction.js +128 -60
- package/lib/repositories/DatatruckRepository.d.ts +1 -1
- package/lib/repositories/DatatruckRepository.js +25 -15
- package/lib/repositories/GitRepository.js +11 -3
- package/lib/repositories/RepositoryAbstract.d.ts +2 -1
- package/lib/repositories/RepositoryAbstract.js +3 -1
- package/lib/utils/datatruck/client.d.ts +7 -3
- package/lib/utils/datatruck/client.js +9 -2
- package/lib/utils/datatruck/config.js +2 -2
- package/lib/utils/datatruck/repository.d.ts +3 -3
- package/lib/utils/datatruck/repository.js +3 -3
- package/lib/utils/fs.d.ts +2 -1
- package/lib/utils/fs.js +18 -0
- package/lib/utils/git.d.ts +5 -0
- package/lib/utils/git.js +10 -0
- package/lib/utils/list.d.ts +3 -1
- package/lib/utils/list.js +2 -3
- package/lib/utils/progress.d.ts +8 -1
- package/lib/utils/progress.js +38 -5
- package/lib/utils/temp.d.ts +13 -10
- package/lib/utils/temp.js +47 -40
- package/package.json +1 -1
|
@@ -1,4 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
3
|
+
if (value !== null && value !== void 0) {
|
|
4
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
5
|
+
var dispose;
|
|
6
|
+
if (async) {
|
|
7
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
8
|
+
dispose = value[Symbol.asyncDispose];
|
|
9
|
+
}
|
|
10
|
+
if (dispose === void 0) {
|
|
11
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
12
|
+
dispose = value[Symbol.dispose];
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
16
|
+
}
|
|
17
|
+
else if (async) {
|
|
18
|
+
env.stack.push({ async: true });
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
};
|
|
22
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
23
|
+
return function (env) {
|
|
24
|
+
function fail(e) {
|
|
25
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
26
|
+
env.hasError = true;
|
|
27
|
+
}
|
|
28
|
+
function next() {
|
|
29
|
+
while (env.stack.length) {
|
|
30
|
+
var rec = env.stack.pop();
|
|
31
|
+
try {
|
|
32
|
+
var result = rec.dispose && rec.dispose.call(rec.value);
|
|
33
|
+
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
fail(e);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (env.hasError) throw env.error;
|
|
40
|
+
}
|
|
41
|
+
return next();
|
|
42
|
+
};
|
|
43
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
44
|
+
var e = new Error(message);
|
|
45
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
46
|
+
});
|
|
2
47
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
48
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
49
|
};
|
|
@@ -166,6 +211,7 @@ class BackupAction {
|
|
|
166
211
|
}
|
|
167
212
|
async exec() {
|
|
168
213
|
const { options } = this;
|
|
214
|
+
const gc = new temp_1.GargabeCollector();
|
|
169
215
|
const pm = new progress_1.ProgressManager({
|
|
170
216
|
verbose: options.verbose,
|
|
171
217
|
tty: options.tty,
|
|
@@ -174,6 +220,7 @@ class BackupAction {
|
|
|
174
220
|
const l = new list_1.Listr3({
|
|
175
221
|
streams: this.options.streams,
|
|
176
222
|
progressManager: pm,
|
|
223
|
+
gargabeCollector: gc,
|
|
177
224
|
});
|
|
178
225
|
return l
|
|
179
226
|
.add([
|
|
@@ -197,11 +244,11 @@ class BackupAction {
|
|
|
197
244
|
return [
|
|
198
245
|
...packages.flatMap((pkg) => {
|
|
199
246
|
let taskResult = {};
|
|
200
|
-
const gc = new temp_1.GargabeCollector();
|
|
201
247
|
const repositories = this.getRepositoryNames(pkg.repositoryNames ?? []);
|
|
202
248
|
const mirrorRepositories = repositories
|
|
203
249
|
.filter((r) => r.mirrors.length)
|
|
204
250
|
.flatMap(({ name, mirrors }) => mirrors.map((mirror) => ({ name, mirror })));
|
|
251
|
+
const taskGc = gc.create();
|
|
205
252
|
return l.$tasks(!!pkg.task &&
|
|
206
253
|
l.$task({
|
|
207
254
|
key: "task",
|
|
@@ -214,13 +261,25 @@ class BackupAction {
|
|
|
214
261
|
completed: `Task executed: ${pkg.name} (${pkg.task.name})`,
|
|
215
262
|
},
|
|
216
263
|
exitOnError: false,
|
|
217
|
-
runWrapper: gc.cleanupIfFail.bind(gc),
|
|
218
264
|
run: async (task) => {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
265
|
+
await taskGc.disposeIfFail(async () => {
|
|
266
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
267
|
+
try {
|
|
268
|
+
const progress = __addDisposableResource(env_1, pm.create(task), false);
|
|
269
|
+
taskResult = await (0, task_1.createTask)(pkg.task).backup({
|
|
270
|
+
options,
|
|
271
|
+
package: pkg,
|
|
272
|
+
snapshot,
|
|
273
|
+
onProgress: progress.update,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
catch (e_1) {
|
|
277
|
+
env_1.error = e_1;
|
|
278
|
+
env_1.hasError = true;
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
__disposeResources(env_1);
|
|
282
|
+
}
|
|
224
283
|
});
|
|
225
284
|
},
|
|
226
285
|
}), ...repositories.map(({ name: repositoryName }) => l.$task({
|
|
@@ -238,21 +297,34 @@ class BackupAction {
|
|
|
238
297
|
failed: `Backup create failed: ${pkg.name} (${repositoryName})`,
|
|
239
298
|
},
|
|
240
299
|
exitOnError: false,
|
|
241
|
-
runWrapper: gc.cleanupOnFinish.bind(gc),
|
|
242
300
|
run: async (task, data) => {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
301
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
302
|
+
try {
|
|
303
|
+
const _ = __addDisposableResource(env_2, gc.create().disposeOnFinish(), true);
|
|
304
|
+
const taskSummary = pkg.task
|
|
305
|
+
? l.result("task", pkg.name)
|
|
306
|
+
: undefined;
|
|
307
|
+
if (taskSummary?.error)
|
|
308
|
+
throw new error_1.AppError(`Task failed`);
|
|
309
|
+
const progress = __addDisposableResource(env_2, pm.create(task), false);
|
|
310
|
+
const backup = await this.backup({
|
|
311
|
+
pkg,
|
|
312
|
+
repositoryName,
|
|
313
|
+
snapshot,
|
|
314
|
+
snapshotPath: taskResult?.snapshotPath,
|
|
315
|
+
onProgress: progress.update,
|
|
316
|
+
});
|
|
317
|
+
data.bytes = backup.bytes;
|
|
318
|
+
}
|
|
319
|
+
catch (e_2) {
|
|
320
|
+
env_2.error = e_2;
|
|
321
|
+
env_2.hasError = true;
|
|
322
|
+
}
|
|
323
|
+
finally {
|
|
324
|
+
const result_1 = __disposeResources(env_2);
|
|
325
|
+
if (result_1)
|
|
326
|
+
await result_1;
|
|
327
|
+
}
|
|
256
328
|
},
|
|
257
329
|
})), l.$task({
|
|
258
330
|
key: "cleanup",
|
|
@@ -265,8 +337,8 @@ class BackupAction {
|
|
|
265
337
|
failed: "Task files clean failed",
|
|
266
338
|
},
|
|
267
339
|
exitOnError: false,
|
|
268
|
-
enabled:
|
|
269
|
-
run: () =>
|
|
340
|
+
enabled: taskGc.pending(),
|
|
341
|
+
run: () => taskGc.dispose(),
|
|
270
342
|
}), ...mirrorRepositories.map(({ name, mirror }) => l.$task({
|
|
271
343
|
key: "copy",
|
|
272
344
|
keyIndex: [pkg.name, mirror],
|
|
@@ -283,22 +355,35 @@ class BackupAction {
|
|
|
283
355
|
failed: `Snapshot copy failed: ${pkg.name} (${mirror})`,
|
|
284
356
|
},
|
|
285
357
|
exitOnError: false,
|
|
286
|
-
runWrapper: gc.cleanup.bind(gc),
|
|
287
358
|
run: async (task, data) => {
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
359
|
+
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
360
|
+
try {
|
|
361
|
+
const _ = __addDisposableResource(env_3, gc.create().disposeOnFinish(), true);
|
|
362
|
+
const backupSummary = l.result("backup", [
|
|
363
|
+
pkg.name,
|
|
364
|
+
name,
|
|
365
|
+
]);
|
|
366
|
+
if (backupSummary.error)
|
|
367
|
+
throw new error_1.AppError(`Backup failed`);
|
|
368
|
+
const progress = __addDisposableResource(env_3, pm.create(task), false);
|
|
369
|
+
const copy = await this.copy({
|
|
370
|
+
repositoryName: name,
|
|
371
|
+
mirrorRepositoryName: mirror,
|
|
372
|
+
pkg,
|
|
373
|
+
snapshot,
|
|
374
|
+
onProgress: progress.update,
|
|
375
|
+
});
|
|
376
|
+
data.bytes = copy.bytes;
|
|
377
|
+
}
|
|
378
|
+
catch (e_3) {
|
|
379
|
+
env_3.error = e_3;
|
|
380
|
+
env_3.hasError = true;
|
|
381
|
+
}
|
|
382
|
+
finally {
|
|
383
|
+
const result_2 = __disposeResources(env_3);
|
|
384
|
+
if (result_2)
|
|
385
|
+
await result_2;
|
|
386
|
+
}
|
|
302
387
|
},
|
|
303
388
|
})), !!this.options.prune &&
|
|
304
389
|
l.$task({
|
|
@@ -269,26 +269,48 @@ class CopyAction {
|
|
|
269
269
|
? sourceRepo.get()
|
|
270
270
|
: undefined;
|
|
271
271
|
if ($sourceRepo) {
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
272
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
273
|
+
try {
|
|
274
|
+
const progress = __addDisposableResource(env_2, pm.create(task), false);
|
|
275
|
+
const copy = await $sourceRepo.copy({
|
|
276
|
+
mirrorRepositoryConfig: mirrorConfig.config,
|
|
277
|
+
options: { verbose: this.options.verbose },
|
|
278
|
+
package: { name: snapshot.packageName },
|
|
279
|
+
snapshot,
|
|
280
|
+
onProgress: progress.update,
|
|
281
|
+
});
|
|
282
|
+
data.bytes = copy.bytes;
|
|
283
|
+
}
|
|
284
|
+
catch (e_2) {
|
|
285
|
+
env_2.error = e_2;
|
|
286
|
+
env_2.hasError = true;
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
__disposeResources(env_2);
|
|
290
|
+
}
|
|
280
291
|
}
|
|
281
292
|
else {
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
293
|
+
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
294
|
+
try {
|
|
295
|
+
const progress = __addDisposableResource(env_3, pm.create(task), false);
|
|
296
|
+
const copy = await this.copyCrossRepository({
|
|
297
|
+
mirrorConfig,
|
|
298
|
+
mirrorRepo,
|
|
299
|
+
repo,
|
|
300
|
+
repoConfig,
|
|
301
|
+
snapshot,
|
|
302
|
+
onProgress: progress.update,
|
|
303
|
+
});
|
|
304
|
+
data.bytes = copy.bytes;
|
|
305
|
+
sourceRepo.set(mirrorRepo);
|
|
306
|
+
}
|
|
307
|
+
catch (e_3) {
|
|
308
|
+
env_3.error = e_3;
|
|
309
|
+
env_3.hasError = true;
|
|
310
|
+
}
|
|
311
|
+
finally {
|
|
312
|
+
__disposeResources(env_3);
|
|
313
|
+
}
|
|
292
314
|
}
|
|
293
315
|
},
|
|
294
316
|
});
|
|
@@ -21,7 +21,7 @@ class InitAction {
|
|
|
21
21
|
if (this.options.repositoryTypes &&
|
|
22
22
|
!this.options.repositoryTypes.includes(repoConfig.type))
|
|
23
23
|
continue;
|
|
24
|
-
const repo = (0, repository_1.createRepo)(repoConfig);
|
|
24
|
+
const repo = (0, repository_1.createRepo)(repoConfig, this.options.verbose);
|
|
25
25
|
let initError = null;
|
|
26
26
|
try {
|
|
27
27
|
await repo.init({
|
|
@@ -5,7 +5,6 @@ import type { Config, PackageConfig } from "../utils/datatruck/config-type";
|
|
|
5
5
|
import { Listr3TaskResultEnd } from "../utils/list";
|
|
6
6
|
import { Progress, ProgressMode } from "../utils/progress";
|
|
7
7
|
import { StdStreams } from "../utils/stream";
|
|
8
|
-
import { GargabeCollector } from "../utils/temp";
|
|
9
8
|
import { IfRequireKeys } from "../utils/ts";
|
|
10
9
|
export type RestoreActionOptions = {
|
|
11
10
|
snapshotId: string;
|
|
@@ -47,7 +46,6 @@ export declare class RestoreAction<TRequired extends boolean = true> {
|
|
|
47
46
|
pkg: PackageConfig;
|
|
48
47
|
task: TaskAbstract | undefined;
|
|
49
48
|
snapshot: RestoreSnapshot;
|
|
50
|
-
gc: GargabeCollector;
|
|
51
49
|
onProgress: (progress: Progress) => void;
|
|
52
50
|
}): Promise<{
|
|
53
51
|
snapshotPath: string | undefined;
|
|
@@ -1,4 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
3
|
+
if (value !== null && value !== void 0) {
|
|
4
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
5
|
+
var dispose;
|
|
6
|
+
if (async) {
|
|
7
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
8
|
+
dispose = value[Symbol.asyncDispose];
|
|
9
|
+
}
|
|
10
|
+
if (dispose === void 0) {
|
|
11
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
12
|
+
dispose = value[Symbol.dispose];
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
16
|
+
}
|
|
17
|
+
else if (async) {
|
|
18
|
+
env.stack.push({ async: true });
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
};
|
|
22
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
23
|
+
return function (env) {
|
|
24
|
+
function fail(e) {
|
|
25
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
26
|
+
env.hasError = true;
|
|
27
|
+
}
|
|
28
|
+
function next() {
|
|
29
|
+
while (env.stack.length) {
|
|
30
|
+
var rec = env.stack.pop();
|
|
31
|
+
try {
|
|
32
|
+
var result = rec.dispose && rec.dispose.call(rec.value);
|
|
33
|
+
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
fail(e);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (env.hasError) throw env.error;
|
|
40
|
+
}
|
|
41
|
+
return next();
|
|
42
|
+
};
|
|
43
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
44
|
+
var e = new Error(message);
|
|
45
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
46
|
+
});
|
|
2
47
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
48
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
49
|
};
|
|
@@ -71,27 +116,25 @@ class RestoreAction {
|
|
|
71
116
|
const repoConfig = (0, config_1.findRepositoryOrFail)(this.config, snapshot.repositoryName);
|
|
72
117
|
const repo = await (0, repository_1.createAndInitRepo)(repoConfig, this.options.verbose);
|
|
73
118
|
let snapshotPath = pkg.restorePath ?? pkg.path;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const taskResult = await task.prepareRestore({
|
|
77
|
-
options: this.options,
|
|
78
|
-
package: pkg,
|
|
79
|
-
snapshot,
|
|
80
|
-
});
|
|
81
|
-
snapshotPath = taskResult?.snapshotPath;
|
|
82
|
-
}
|
|
83
|
-
await (0, fs_1.initEmptyDir)(snapshotPath);
|
|
84
|
-
if (this.config.minFreeDiskSpace)
|
|
85
|
-
await (0, fs_1.ensureFreeDiskSpace)([snapshotPath], this.config.minFreeDiskSpace);
|
|
86
|
-
await repo.restore({
|
|
119
|
+
if (task) {
|
|
120
|
+
const taskResult = await task.prepareRestore({
|
|
87
121
|
options: this.options,
|
|
88
|
-
snapshot: data.snapshot,
|
|
89
122
|
package: pkg,
|
|
90
|
-
|
|
91
|
-
packageConfig: pkg.repositoryConfigs?.find((config) => config.type === repoConfig.type &&
|
|
92
|
-
(!config.names || config.names.includes(repoConfig.name)))?.config,
|
|
93
|
-
onProgress: data.onProgress,
|
|
123
|
+
snapshot,
|
|
94
124
|
});
|
|
125
|
+
snapshotPath = taskResult?.snapshotPath;
|
|
126
|
+
}
|
|
127
|
+
await (0, fs_1.initEmptyDir)(snapshotPath);
|
|
128
|
+
if (this.config.minFreeDiskSpace)
|
|
129
|
+
await (0, fs_1.ensureFreeDiskSpace)([snapshotPath], this.config.minFreeDiskSpace);
|
|
130
|
+
await repo.restore({
|
|
131
|
+
options: this.options,
|
|
132
|
+
snapshot: data.snapshot,
|
|
133
|
+
package: pkg,
|
|
134
|
+
snapshotPath: snapshotPath,
|
|
135
|
+
packageConfig: pkg.repositoryConfigs?.find((config) => config.type === repoConfig.type &&
|
|
136
|
+
(!config.names || config.names.includes(repoConfig.name)))?.config,
|
|
137
|
+
onProgress: data.onProgress,
|
|
95
138
|
});
|
|
96
139
|
return { snapshotPath };
|
|
97
140
|
}
|
|
@@ -139,6 +182,7 @@ class RestoreAction {
|
|
|
139
182
|
}
|
|
140
183
|
async exec() {
|
|
141
184
|
const { options } = this;
|
|
185
|
+
const gc = new temp_1.GargabeCollector();
|
|
142
186
|
const pm = new progress_1.ProgressManager({
|
|
143
187
|
verbose: options.verbose,
|
|
144
188
|
tty: options.tty,
|
|
@@ -147,6 +191,7 @@ class RestoreAction {
|
|
|
147
191
|
const l = new list_1.Listr3({
|
|
148
192
|
streams: options.streams,
|
|
149
193
|
progressManager: pm,
|
|
194
|
+
gargabeCollector: gc,
|
|
150
195
|
});
|
|
151
196
|
return l
|
|
152
197
|
.add(l.$task({
|
|
@@ -184,48 +229,71 @@ class RestoreAction {
|
|
|
184
229
|
},
|
|
185
230
|
exitOnError: false,
|
|
186
231
|
run: async (listTask) => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
232
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
233
|
+
try {
|
|
234
|
+
let pkg = (0, config_1.resolvePackage)((0, config_1.findPackageOrFail)(this.config, snapshot.packageName), {
|
|
235
|
+
snapshotId: options.snapshotId,
|
|
236
|
+
snapshotDate: snapshot.date,
|
|
237
|
+
action: "restore",
|
|
238
|
+
});
|
|
239
|
+
if (this.options.initial)
|
|
240
|
+
pkg = { ...pkg, restorePath: pkg.path };
|
|
241
|
+
const task = pkg.task ? (0, task_1.createTask)(pkg.task) : undefined;
|
|
242
|
+
const progress = __addDisposableResource(env_1, pm.create(listTask), false);
|
|
243
|
+
const restoreGc = gc.create();
|
|
244
|
+
const restore = await restoreGc.disposeIfFail(() => this.restore({
|
|
245
|
+
pkg,
|
|
246
|
+
task,
|
|
247
|
+
snapshot: snapshot,
|
|
248
|
+
onProgress: progress.update,
|
|
249
|
+
}));
|
|
250
|
+
if (!task)
|
|
251
|
+
return await restoreGc.dispose();
|
|
252
|
+
return l.$tasks({
|
|
253
|
+
key: "task",
|
|
254
|
+
keyIndex: pkg.name,
|
|
255
|
+
data: { taskName: pkg.task.name, packageName: pkg.name },
|
|
256
|
+
title: {
|
|
257
|
+
initial: `Execute task: ${pkg.name} (${pkg.task.name})`,
|
|
258
|
+
started: `Executing task: ${pkg.name} (${pkg.task.name})`,
|
|
259
|
+
completed: `Task executed: ${pkg.name} (${pkg.task.name})`,
|
|
260
|
+
failed: `Task execute failed: ${pkg.name} (${pkg.task.name})`,
|
|
261
|
+
},
|
|
262
|
+
exitOnError: false,
|
|
263
|
+
run: async (listTask) => {
|
|
264
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
265
|
+
try {
|
|
266
|
+
const _ = __addDisposableResource(env_2, restoreGc.disposeOnFinish(), true);
|
|
267
|
+
const { snapshotPath } = restore;
|
|
268
|
+
(0, assert_1.ok)(snapshotPath);
|
|
269
|
+
const progress = __addDisposableResource(env_2, pm.create(listTask), false);
|
|
270
|
+
await task.restore({
|
|
271
|
+
package: pkg,
|
|
272
|
+
options,
|
|
273
|
+
snapshot,
|
|
274
|
+
snapshotPath,
|
|
275
|
+
onProgress: progress.update,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
catch (e_2) {
|
|
279
|
+
env_2.error = e_2;
|
|
280
|
+
env_2.hasError = true;
|
|
281
|
+
}
|
|
282
|
+
finally {
|
|
283
|
+
const result_1 = __disposeResources(env_2);
|
|
284
|
+
if (result_1)
|
|
285
|
+
await result_1;
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
catch (e_1) {
|
|
291
|
+
env_1.error = e_1;
|
|
292
|
+
env_1.hasError = true;
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
__disposeResources(env_1);
|
|
296
|
+
}
|
|
229
297
|
},
|
|
230
298
|
}));
|
|
231
299
|
},
|
|
@@ -45,15 +45,15 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
45
45
|
return this.config.backend;
|
|
46
46
|
}
|
|
47
47
|
fetchDiskStats(config) {
|
|
48
|
-
const fs = (0, client_1.createFs)(config.backend);
|
|
48
|
+
const fs = (0, client_1.createFs)(config.backend, this.verbose);
|
|
49
49
|
return fs.fetchDiskStats(".");
|
|
50
50
|
}
|
|
51
51
|
async init(data) {
|
|
52
|
-
const fs = (0, client_1.createFs)(this.config.backend);
|
|
52
|
+
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
53
53
|
await fs.mkdir(".");
|
|
54
54
|
}
|
|
55
55
|
async prune(data) {
|
|
56
|
-
const fs = (0, client_1.createFs)(this.config.backend);
|
|
56
|
+
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
57
57
|
const snapshotName = DatatruckRepository.buildSnapshotName(data.snapshot, {
|
|
58
58
|
name: data.snapshot.packageName,
|
|
59
59
|
});
|
|
@@ -63,7 +63,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
63
63
|
await fs.rmAll(snapshotName);
|
|
64
64
|
}
|
|
65
65
|
async fetchSnapshots(data) {
|
|
66
|
-
const fs = (0, client_1.createFs)(this.config.backend);
|
|
66
|
+
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
67
67
|
if (!(await fs.existsDir(".")))
|
|
68
68
|
throw new error_1.AppError(`Repository (${this.repository.name}) out path does not exist: ${fs.resolvePath(".")}`);
|
|
69
69
|
const snapshots = [];
|
|
@@ -105,7 +105,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
105
105
|
return snapshots;
|
|
106
106
|
}
|
|
107
107
|
async backup(data) {
|
|
108
|
-
const fs = (0, client_1.createFs)(this.config.backend);
|
|
108
|
+
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
109
109
|
const snapshotName = DatatruckRepository.buildSnapshotName(data.snapshot, data.package);
|
|
110
110
|
const outPath = fs.isLocal()
|
|
111
111
|
? fs.resolvePath(snapshotName)
|
|
@@ -177,11 +177,11 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
177
177
|
.join("-") + (pack.compress ? `.tar.gz` : `.tar`);
|
|
178
178
|
const includeList = stream.path(packIndex);
|
|
179
179
|
if (includeList) {
|
|
180
|
-
tarStats[packBasename] = {
|
|
180
|
+
const stats = (tarStats[packBasename] = {
|
|
181
181
|
files: stream.lines(packIndex),
|
|
182
182
|
size: 0,
|
|
183
183
|
checksum: "",
|
|
184
|
-
};
|
|
184
|
+
});
|
|
185
185
|
const tarPath = (0, path_1.join)(outPath, packBasename);
|
|
186
186
|
await (0, tar_1.createTar)({
|
|
187
187
|
compress: pack.compress,
|
|
@@ -192,8 +192,8 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
192
192
|
onEntry: async (data) => scanner.progress(pack.compress ? "Compressing" : "Packing", data.path),
|
|
193
193
|
});
|
|
194
194
|
scanner.progress("Fetching tar stats", (0, path_1.basename)(tarPath), false);
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
stats.checksum = await (0, crypto_1.calcFileHash)(tarPath, "sha1");
|
|
196
|
+
stats.size = (await (0, promises_1.stat)(tarPath)).size;
|
|
197
197
|
if (!fs.isLocal()) {
|
|
198
198
|
scanner.progress("Uploading tar", (0, path_1.basename)(tarPath), false);
|
|
199
199
|
await fs.upload(tarPath, `${snapshotName}/${packBasename}`);
|
|
@@ -204,7 +204,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
204
204
|
}
|
|
205
205
|
scanner.end();
|
|
206
206
|
// Meta
|
|
207
|
-
const size = Object.values(tarStats).reduce((total,
|
|
207
|
+
const size = Object.values(tarStats).reduce((total, stat) => total + stat.size, 0);
|
|
208
208
|
const metaPath = `${snapshotName}/meta.json`;
|
|
209
209
|
const nodePkg = (0, fs_1.parsePackageFile)();
|
|
210
210
|
const meta = {
|
|
@@ -225,8 +225,8 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
225
225
|
};
|
|
226
226
|
}
|
|
227
227
|
async copy(data) {
|
|
228
|
-
const sourceFs = (0, client_1.createFs)(this.config.backend);
|
|
229
|
-
const targetFs = (0, client_1.createFs)(data.mirrorRepositoryConfig.backend);
|
|
228
|
+
const sourceFs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
229
|
+
const targetFs = (0, client_1.createFs)(data.mirrorRepositoryConfig.backend, this.verbose);
|
|
230
230
|
const snapshotName = DatatruckRepository.buildSnapshotName(data.snapshot, data.package);
|
|
231
231
|
if (data.options.verbose)
|
|
232
232
|
(0, cli_1.logExec)(`Copying backup files to ${data.mirrorRepositoryConfig.backend}`);
|
|
@@ -296,7 +296,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
296
296
|
return { bytes };
|
|
297
297
|
}
|
|
298
298
|
async restore(data) {
|
|
299
|
-
const fs = (0, client_1.createFs)(this.config.backend);
|
|
299
|
+
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
300
300
|
const relRestorePath = data.snapshotPath;
|
|
301
301
|
(0, assert_1.ok)(relRestorePath);
|
|
302
302
|
const restorePath = (0, path_1.resolve)(relRestorePath);
|
|
@@ -325,10 +325,20 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
325
325
|
if (!fs.isLocal()) {
|
|
326
326
|
const tempDir = await (0, temp_1.mkTmpDir)(exports.datatruckRepositoryName, "repo", "restore", "remote-fs", entry);
|
|
327
327
|
tempEntry = `${tempDir}/${entry}`;
|
|
328
|
-
await fs.download(sourceEntry, tempEntry
|
|
328
|
+
await fs.download(sourceEntry, tempEntry, {
|
|
329
|
+
onProgress: (stats) => {
|
|
330
|
+
progress.updateRelative("Downloading", entry, {
|
|
331
|
+
...stats,
|
|
332
|
+
format: "size",
|
|
333
|
+
});
|
|
334
|
+
},
|
|
335
|
+
});
|
|
329
336
|
}
|
|
337
|
+
const stats = tarStats[entry];
|
|
338
|
+
if (data.options.verbose)
|
|
339
|
+
(0, cli_1.logExec)(`Stats of '${entry}' is not available`);
|
|
330
340
|
await (0, tar_1.extractTar)({
|
|
331
|
-
total:
|
|
341
|
+
total: stats?.files,
|
|
332
342
|
input: tempEntry ?? fs.resolvePath(sourceEntry),
|
|
333
343
|
output: restorePath,
|
|
334
344
|
decompress: entry.endsWith(".tar.gz"),
|
|
@@ -68,7 +68,11 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
68
68
|
branchName,
|
|
69
69
|
orphan: true,
|
|
70
70
|
});
|
|
71
|
-
await git.
|
|
71
|
+
await git.commit("Initial commit", {
|
|
72
|
+
allowEmpty: true,
|
|
73
|
+
userName: "datatruck",
|
|
74
|
+
userEmail: "datatruck@localhost",
|
|
75
|
+
});
|
|
72
76
|
await git.push({ branchName });
|
|
73
77
|
}
|
|
74
78
|
}
|
|
@@ -184,8 +188,12 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
184
188
|
if (data.options.verbose)
|
|
185
189
|
console.info(`Copied ${files} files`);
|
|
186
190
|
await git.exec(["add", "--verbose", "."]);
|
|
187
|
-
if (await git.haveChanges())
|
|
188
|
-
await git.
|
|
191
|
+
if (await git.haveChanges()) {
|
|
192
|
+
await git.commit(data.snapshot.id, {
|
|
193
|
+
userName: "datatruck",
|
|
194
|
+
userEmail: "datatruck@localhost",
|
|
195
|
+
});
|
|
196
|
+
}
|
|
189
197
|
const nodePkg = (0, fs_1.parsePackageFile)();
|
|
190
198
|
const size = (await (0, fs_1.fastFolderSizeAsync)(tmpPath)) -
|
|
191
199
|
(await (0, fs_1.fastFolderSizeAsync)((0, path_1.join)(tmpPath, ".git")));
|
|
@@ -75,8 +75,9 @@ export type SnapshotTagObject = {
|
|
|
75
75
|
};
|
|
76
76
|
export declare abstract class RepositoryAbstract<TConfig> {
|
|
77
77
|
readonly repository: RepositoryConfig;
|
|
78
|
+
readonly verbose: boolean;
|
|
78
79
|
readonly config: TConfig;
|
|
79
|
-
constructor(repository: RepositoryConfig);
|
|
80
|
+
constructor(repository: RepositoryConfig, verbose: boolean);
|
|
80
81
|
abstract getSource(): string;
|
|
81
82
|
abstract fetchDiskStats(config: TConfig): Promise<DiskStats | undefined>;
|
|
82
83
|
ensureFreeDiskSpace(config: TConfig, minFreeDiskSpace: number | string): Promise<void>;
|
|
@@ -15,9 +15,11 @@ var SnapshotTagEnum;
|
|
|
15
15
|
})(SnapshotTagEnum || (exports.SnapshotTagEnum = SnapshotTagEnum = {}));
|
|
16
16
|
class RepositoryAbstract {
|
|
17
17
|
repository;
|
|
18
|
+
verbose;
|
|
18
19
|
config;
|
|
19
|
-
constructor(repository) {
|
|
20
|
+
constructor(repository, verbose) {
|
|
20
21
|
this.repository = repository;
|
|
22
|
+
this.verbose = verbose;
|
|
21
23
|
this.config = repository.config;
|
|
22
24
|
}
|
|
23
25
|
async ensureFreeDiskSpace(config, minFreeDiskSpace) {
|
|
@@ -2,10 +2,14 @@ import { DiskStats } from "../fs";
|
|
|
2
2
|
import { BasicProgress } from "../progress";
|
|
3
3
|
import { AbstractFs, FsOptions } from "../virtual-fs";
|
|
4
4
|
export declare class RemoteFs extends AbstractFs {
|
|
5
|
-
readonly options: FsOptions
|
|
5
|
+
readonly options: FsOptions & {
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
};
|
|
6
8
|
protected url: string;
|
|
7
9
|
protected headers: Record<string, string>;
|
|
8
|
-
constructor(options: FsOptions
|
|
10
|
+
constructor(options: FsOptions & {
|
|
11
|
+
verbose?: boolean;
|
|
12
|
+
});
|
|
9
13
|
isLocal(): boolean;
|
|
10
14
|
protected fetchJson(name: string, params: any[]): Promise<any>;
|
|
11
15
|
protected post(name: string, params: any[], data: string): Promise<void>;
|
|
@@ -28,4 +32,4 @@ export declare class RemoteFs extends AbstractFs {
|
|
|
28
32
|
}>;
|
|
29
33
|
}
|
|
30
34
|
export declare function isRemoteBackend(backend: string): boolean;
|
|
31
|
-
export declare function createFs(backend: string): AbstractFs;
|
|
35
|
+
export declare function createFs(backend: string, verbose: boolean | undefined): AbstractFs;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createFs = exports.isRemoteBackend = exports.RemoteFs = void 0;
|
|
4
|
+
const cli_1 = require("../cli");
|
|
4
5
|
const http_1 = require("../http");
|
|
5
6
|
const virtual_fs_1 = require("../virtual-fs");
|
|
6
7
|
const repository_server_1 = require("./repository-server");
|
|
@@ -69,9 +70,13 @@ class RemoteFs extends virtual_fs_1.AbstractFs {
|
|
|
69
70
|
await this.fetchJson("rmAll", [path]);
|
|
70
71
|
}
|
|
71
72
|
async fetchDiskStats(path) {
|
|
73
|
+
if (this.options.verbose)
|
|
74
|
+
(0, cli_1.logExec)("fs.fetchDiskStats", [path]);
|
|
72
75
|
return await this.fetchJson("fetchDiskStats", [path]);
|
|
73
76
|
}
|
|
74
77
|
async upload(source, target) {
|
|
78
|
+
if (this.options.verbose)
|
|
79
|
+
(0, cli_1.logExec)("fs.upload", [source, target]);
|
|
75
80
|
await (0, http_1.uploadFile)(`${this.url}/upload`, source, {
|
|
76
81
|
headers: this.headers,
|
|
77
82
|
query: {
|
|
@@ -80,6 +85,8 @@ class RemoteFs extends virtual_fs_1.AbstractFs {
|
|
|
80
85
|
});
|
|
81
86
|
}
|
|
82
87
|
async download(source, target, options = {}) {
|
|
88
|
+
if (this.options.verbose)
|
|
89
|
+
(0, cli_1.logExec)("fs.download", [source, target]);
|
|
83
90
|
return await (0, http_1.downloadFile)(`${this.url}/download`, target, {
|
|
84
91
|
...options,
|
|
85
92
|
headers: this.headers,
|
|
@@ -92,9 +99,9 @@ function isRemoteBackend(backend) {
|
|
|
92
99
|
return backend.startsWith("http:") || backend.startsWith("https:");
|
|
93
100
|
}
|
|
94
101
|
exports.isRemoteBackend = isRemoteBackend;
|
|
95
|
-
function createFs(backend) {
|
|
102
|
+
function createFs(backend, verbose) {
|
|
96
103
|
return isRemoteBackend(backend)
|
|
97
|
-
? new RemoteFs({ backend })
|
|
104
|
+
? new RemoteFs({ backend, verbose })
|
|
98
105
|
: new virtual_fs_1.LocalFs({ backend });
|
|
99
106
|
}
|
|
100
107
|
exports.createFs = createFs;
|
|
@@ -8,14 +8,14 @@ const micromatch_1 = require("micromatch");
|
|
|
8
8
|
function findRepositoryOrFail(config, repositoryName) {
|
|
9
9
|
const repo = config.repositories.find((v) => v.name === repositoryName);
|
|
10
10
|
if (!repo)
|
|
11
|
-
throw new error_1.AppError(`Repository '${repositoryName}' not found`);
|
|
11
|
+
throw new error_1.AppError(`Repository '${repositoryName}' not found in the config`);
|
|
12
12
|
return repo;
|
|
13
13
|
}
|
|
14
14
|
exports.findRepositoryOrFail = findRepositoryOrFail;
|
|
15
15
|
function findPackageOrFail(config, packageName) {
|
|
16
16
|
const pkg = config.packages.find((v) => v.name === packageName);
|
|
17
17
|
if (!pkg)
|
|
18
|
-
throw new error_1.AppError(`Package '${packageName}' not found`);
|
|
18
|
+
throw new error_1.AppError(`Package '${packageName}' not found in the config`);
|
|
19
19
|
return pkg;
|
|
20
20
|
}
|
|
21
21
|
exports.findPackageOrFail = findPackageOrFail;
|
|
@@ -9,8 +9,8 @@ declare const repoMap: {
|
|
|
9
9
|
datatruck: typeof DatatruckRepository;
|
|
10
10
|
};
|
|
11
11
|
export declare function getRepoConstructor(type: keyof typeof repoMap): {
|
|
12
|
-
new (config: RepositoryConfig): RepositoryAbstract<any>;
|
|
12
|
+
new (config: RepositoryConfig, verbose?: boolean): RepositoryAbstract<any>;
|
|
13
13
|
};
|
|
14
|
-
export declare function createRepo(repository: RepositoryConfig): RepositoryAbstract<any>;
|
|
15
|
-
export declare function createAndInitRepo(repository: RepositoryConfig, verbose
|
|
14
|
+
export declare function createRepo(repository: RepositoryConfig, verbose: boolean | undefined): RepositoryAbstract<any>;
|
|
15
|
+
export declare function createAndInitRepo(repository: RepositoryConfig, verbose: boolean | undefined): Promise<RepositoryAbstract<any>>;
|
|
16
16
|
export {};
|
|
@@ -17,13 +17,13 @@ function getRepoConstructor(type) {
|
|
|
17
17
|
return Constructor;
|
|
18
18
|
}
|
|
19
19
|
exports.getRepoConstructor = getRepoConstructor;
|
|
20
|
-
function createRepo(repository) {
|
|
20
|
+
function createRepo(repository, verbose) {
|
|
21
21
|
const Constructor = getRepoConstructor(repository.type);
|
|
22
|
-
return new Constructor(repository);
|
|
22
|
+
return new Constructor(repository, verbose);
|
|
23
23
|
}
|
|
24
24
|
exports.createRepo = createRepo;
|
|
25
25
|
async function createAndInitRepo(repository, verbose) {
|
|
26
|
-
const repo = createRepo(repository);
|
|
26
|
+
const repo = createRepo(repository, verbose);
|
|
27
27
|
await repo.init({ options: { verbose } });
|
|
28
28
|
return repo;
|
|
29
29
|
}
|
package/lib/utils/fs.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
/// <reference types="node" />
|
|
4
|
-
import { Progress } from "./progress";
|
|
4
|
+
import { Progress, ProgressStats } from "./progress";
|
|
5
5
|
import { Entry, Options } from "fast-glob";
|
|
6
6
|
import { Stats } from "fs";
|
|
7
7
|
import { WriteStream } from "fs";
|
|
@@ -90,6 +90,7 @@ type ProgressObject = {
|
|
|
90
90
|
total: number;
|
|
91
91
|
current: number;
|
|
92
92
|
update: (description: string, path?: string, increment?: boolean) => void;
|
|
93
|
+
updateRelative: (description: string, path: string, stats: ProgressStats) => void;
|
|
93
94
|
};
|
|
94
95
|
export declare function createProgress(options: {
|
|
95
96
|
onProgress: (data: Progress) => void;
|
package/lib/utils/fs.js
CHANGED
|
@@ -400,11 +400,29 @@ function createProgress(options) {
|
|
|
400
400
|
disposed: false,
|
|
401
401
|
total: 0,
|
|
402
402
|
current: 0,
|
|
403
|
+
updateRelative(description, path, stats) {
|
|
404
|
+
if (progress.disposed)
|
|
405
|
+
return;
|
|
406
|
+
options.onProgress({
|
|
407
|
+
relative: {
|
|
408
|
+
...stats,
|
|
409
|
+
description,
|
|
410
|
+
payload: path,
|
|
411
|
+
},
|
|
412
|
+
absolute: {
|
|
413
|
+
total: progress.total,
|
|
414
|
+
current: progress.current,
|
|
415
|
+
percent: (0, math_1.progressPercent)(progress.total, progress.current),
|
|
416
|
+
},
|
|
417
|
+
});
|
|
418
|
+
},
|
|
403
419
|
update: (description, path, increment = true) => {
|
|
404
420
|
if (progress.disposed)
|
|
405
421
|
return;
|
|
406
422
|
if (path && increment)
|
|
407
423
|
progress.current++;
|
|
424
|
+
if (path === "." || path === "./")
|
|
425
|
+
return;
|
|
408
426
|
options.onProgress({
|
|
409
427
|
relative: {
|
|
410
428
|
description,
|
package/lib/utils/git.d.ts
CHANGED
|
@@ -28,6 +28,11 @@ export declare class Git {
|
|
|
28
28
|
removeAll(): Promise<void>;
|
|
29
29
|
haveChanges(): Promise<boolean>;
|
|
30
30
|
fetchCommitId(tag: string): Promise<string>;
|
|
31
|
+
commit(description: string, options?: {
|
|
32
|
+
allowEmpty?: boolean;
|
|
33
|
+
userName?: string;
|
|
34
|
+
userEmail?: string;
|
|
35
|
+
}): Promise<void>;
|
|
31
36
|
getTags(names?: string[]): Promise<{
|
|
32
37
|
name: string;
|
|
33
38
|
message?: string | undefined;
|
package/lib/utils/git.js
CHANGED
|
@@ -70,6 +70,16 @@ class Git {
|
|
|
70
70
|
async fetchCommitId(tag) {
|
|
71
71
|
return (await this.stdout(["rev-list", "-n", "1", tag])).trim();
|
|
72
72
|
}
|
|
73
|
+
async commit(description, options = {}) {
|
|
74
|
+
await this.exec([
|
|
75
|
+
...(options.userName ? ["-c", `user.name='${options.userName}'`] : []),
|
|
76
|
+
...(options.userEmail ? ["-c", `user.email='${options.userEmail}'`] : []),
|
|
77
|
+
"commit",
|
|
78
|
+
"-m",
|
|
79
|
+
description,
|
|
80
|
+
...(options.allowEmpty ? ["--allow-empty"] : []),
|
|
81
|
+
]);
|
|
82
|
+
}
|
|
73
83
|
async getTags(names) {
|
|
74
84
|
const stdout = await this.stdout(["tag", "-n", ...(names ?? [])]);
|
|
75
85
|
return stdout.split(/\r?\n/).reduce((result, value) => {
|
package/lib/utils/list.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Timer } from "./date";
|
|
2
2
|
import { ProgressManager } from "./progress";
|
|
3
3
|
import { StdStreams } from "./stream";
|
|
4
|
+
import { GargabeCollector } from "./temp";
|
|
4
5
|
import { Listr, ListrGetRendererClassFromValue, ListrLogger, ListrTask, ListrTaskWrapper } from "listr2";
|
|
5
6
|
export declare class List3Logger<Levels extends string = string> extends ListrLogger<Levels> {
|
|
6
7
|
constructor(options?: {
|
|
@@ -19,7 +20,6 @@ type Listr3Task<T extends Listr3Context, K extends keyof T> = {
|
|
|
19
20
|
failed?: string;
|
|
20
21
|
completed?: string;
|
|
21
22
|
};
|
|
22
|
-
runWrapper?: (cb: () => any) => any;
|
|
23
23
|
run: (task: ListrTaskWrapper<any, any, any>, data: T[K]) => Promise<void | ListrTask[] | Listr | undefined> | void | undefined | ListrTask[] | Listr;
|
|
24
24
|
exitOnError?: boolean;
|
|
25
25
|
enabled?: boolean;
|
|
@@ -43,6 +43,7 @@ export declare class Listr3<T extends Listr3Context> extends Listr<void, "defaul
|
|
|
43
43
|
readonly $options: {
|
|
44
44
|
streams?: StdStreams;
|
|
45
45
|
progressManager?: ProgressManager;
|
|
46
|
+
gargabeCollector?: GargabeCollector;
|
|
46
47
|
};
|
|
47
48
|
readonly resultMap: Record<string, Listr3TaskResult<T>>;
|
|
48
49
|
readonly resultList: Listr3TaskResult<T>[];
|
|
@@ -51,6 +52,7 @@ export declare class Listr3<T extends Listr3Context> extends Listr<void, "defaul
|
|
|
51
52
|
constructor($options: {
|
|
52
53
|
streams?: StdStreams;
|
|
53
54
|
progressManager?: ProgressManager;
|
|
55
|
+
gargabeCollector?: GargabeCollector;
|
|
54
56
|
});
|
|
55
57
|
private serializeKeyIndex;
|
|
56
58
|
private createResultIndex;
|
package/lib/utils/list.js
CHANGED
|
@@ -89,9 +89,7 @@ class Listr3 extends listr2_1.Listr {
|
|
|
89
89
|
const timer = (0, date_1.createTimer)();
|
|
90
90
|
if (title)
|
|
91
91
|
try {
|
|
92
|
-
const runResult = item.
|
|
93
|
-
? await item.runWrapper(async () => await item.run(task, result.data))
|
|
94
|
-
: await item.run(task, result.data);
|
|
92
|
+
const runResult = await item.run(task, result.data);
|
|
95
93
|
if (title.completed)
|
|
96
94
|
task.title = title.completed;
|
|
97
95
|
return Array.isArray(runResult)
|
|
@@ -153,6 +151,7 @@ class Listr3 extends listr2_1.Listr {
|
|
|
153
151
|
throw error;
|
|
154
152
|
}
|
|
155
153
|
finally {
|
|
154
|
+
await this.$options.gargabeCollector?.dispose();
|
|
156
155
|
dispose();
|
|
157
156
|
}
|
|
158
157
|
}
|
package/lib/utils/progress.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
2
3
|
import { Timer } from "./date";
|
|
3
4
|
export type BasicProgress = {
|
|
4
5
|
percent: number;
|
|
@@ -35,6 +36,7 @@ export declare class ProgressManager {
|
|
|
35
36
|
protected interval: Timer | undefined;
|
|
36
37
|
protected intervalMs: number;
|
|
37
38
|
protected keydownListener: ((data: Buffer | undefined) => void) | undefined;
|
|
39
|
+
protected pendingProgress: Progress | undefined;
|
|
38
40
|
readonly tty: Exclude<ProgressTty, "auto">;
|
|
39
41
|
readonly mode: Exclude<ProgressMode, "auto" | `interval:${number}`>;
|
|
40
42
|
constructor(options: {
|
|
@@ -51,7 +53,12 @@ export declare class ProgressManager {
|
|
|
51
53
|
elapsed(): number;
|
|
52
54
|
start(): void;
|
|
53
55
|
dispose(): void;
|
|
54
|
-
|
|
56
|
+
create(input: ((text: string) => void) | {
|
|
57
|
+
output: string;
|
|
58
|
+
}, delay?: number): Disposable & {
|
|
59
|
+
update: (progress: Progress) => void;
|
|
60
|
+
};
|
|
61
|
+
renderProgress(progress: Progress, force?: boolean): string | undefined;
|
|
55
62
|
}
|
|
56
63
|
export declare function renderProgress(progress: Progress, bar?: boolean): string[];
|
|
57
64
|
export declare function renderProgressStats(stats: ProgressStats, progressBar?: boolean): string;
|
package/lib/utils/progress.js
CHANGED
|
@@ -13,6 +13,7 @@ class ProgressManager {
|
|
|
13
13
|
interval = (0, date_1.createTimer)();
|
|
14
14
|
intervalMs;
|
|
15
15
|
keydownListener;
|
|
16
|
+
pendingProgress;
|
|
16
17
|
tty;
|
|
17
18
|
mode;
|
|
18
19
|
constructor(options) {
|
|
@@ -66,19 +67,51 @@ class ProgressManager {
|
|
|
66
67
|
this.keydownListener = undefined;
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
create(input, delay = 1000) {
|
|
71
|
+
const update = (progress, force) => {
|
|
72
|
+
const text = this.renderProgress(progress, force);
|
|
73
|
+
if (typeof text === "string") {
|
|
74
|
+
if (typeof input === "function") {
|
|
75
|
+
input(text);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
input.output = text;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const updatePending = () => {
|
|
83
|
+
const pendingProgress = this.pendingProgress;
|
|
84
|
+
if (pendingProgress) {
|
|
85
|
+
this.pendingProgress = undefined;
|
|
86
|
+
update(pendingProgress, true);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const interval = setInterval(updatePending, delay);
|
|
90
|
+
return {
|
|
91
|
+
update,
|
|
92
|
+
[Symbol.dispose]: () => {
|
|
93
|
+
clearInterval(interval);
|
|
94
|
+
updatePending();
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
renderProgress(progress, force = false) {
|
|
99
|
+
if (!this.mode) {
|
|
71
100
|
return;
|
|
72
|
-
|
|
101
|
+
}
|
|
102
|
+
else if (this.mode === "interval") {
|
|
73
103
|
if (this.interval) {
|
|
74
|
-
if (!this.interval.reset(this.intervalMs))
|
|
104
|
+
if (!this.interval.reset(this.intervalMs) && !force) {
|
|
105
|
+
this.pendingProgress = progress;
|
|
75
106
|
return;
|
|
107
|
+
}
|
|
76
108
|
}
|
|
77
109
|
else {
|
|
78
110
|
this.interval = (0, date_1.createTimer)();
|
|
79
111
|
}
|
|
80
112
|
}
|
|
81
|
-
|
|
113
|
+
this.pendingProgress = undefined;
|
|
114
|
+
return renderProgress(progress, this.tty).join("\n");
|
|
82
115
|
}
|
|
83
116
|
}
|
|
84
117
|
exports.ProgressManager = ProgressManager;
|
package/lib/utils/temp.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export declare function ensureFreeDiskTempSpace(size: number | string): Promise<
|
|
|
5
5
|
export declare function isTmpDir(path: string): boolean;
|
|
6
6
|
export declare function rmTmpDir(input: string | string[]): Promise<void>;
|
|
7
7
|
export declare function tmpDir(...keys: [string, ...string[]]): string;
|
|
8
|
+
export declare const collectors: Set<GargabeCollector>;
|
|
8
9
|
export declare function mkTmpDir(...keys: [string, ...string[]]): Promise<string>;
|
|
9
10
|
export declare function useTempDir(...keys: [string, ...string[]]): Promise<AsyncDisposable & {
|
|
10
11
|
path: string;
|
|
@@ -12,15 +13,17 @@ export declare function useTempDir(...keys: [string, ...string[]]): Promise<Asyn
|
|
|
12
13
|
export declare function useTempFile(path: string): AsyncDisposable & {
|
|
13
14
|
path: string;
|
|
14
15
|
};
|
|
15
|
-
export declare class CleanupListener {
|
|
16
|
-
readonly paths: string[];
|
|
17
|
-
stop(): void;
|
|
18
|
-
dispose(): Promise<void>;
|
|
19
|
-
}
|
|
20
16
|
export declare class GargabeCollector {
|
|
21
|
-
protected
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
protected parent?: GargabeCollector | undefined;
|
|
18
|
+
readonly paths: Set<string>;
|
|
19
|
+
readonly children: Set<GargabeCollector>;
|
|
20
|
+
constructor(parent?: GargabeCollector | undefined);
|
|
21
|
+
pending(): boolean;
|
|
22
|
+
cleanup(): Promise<void>;
|
|
23
|
+
dispose(): Promise<void>;
|
|
24
|
+
disposeIfFail<T>(cb: () => Promise<T>): Promise<T>;
|
|
25
|
+
disposeOnFinish(): {
|
|
26
|
+
[Symbol.asyncDispose]: () => Promise<void>;
|
|
27
|
+
};
|
|
28
|
+
create(): GargabeCollector;
|
|
26
29
|
}
|
package/lib/utils/temp.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.GargabeCollector = exports.
|
|
6
|
+
exports.GargabeCollector = exports.useTempFile = exports.useTempDir = exports.mkTmpDir = exports.collectors = exports.tmpDir = exports.rmTmpDir = exports.isTmpDir = exports.ensureFreeDiskTempSpace = exports.sessionTmpDir = exports.parentTmpDir = void 0;
|
|
7
7
|
const globalData_1 = __importDefault(require("../globalData"));
|
|
8
8
|
const fs_1 = require("./fs");
|
|
9
9
|
const crypto_1 = require("crypto");
|
|
@@ -44,12 +44,15 @@ exports.rmTmpDir = rmTmpDir;
|
|
|
44
44
|
function tmpDir(...keys) {
|
|
45
45
|
const id = (0, crypto_1.randomUUID)().slice(0, 8);
|
|
46
46
|
const path = (0, path_1.join)(sessionTmpDir(), [...keys, id].map(encodeURIComponent).join("-"));
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
if (exports.collectors.size) {
|
|
48
|
+
const lastListener = [...exports.collectors.values()].at(exports.collectors.size - 1);
|
|
49
|
+
if (lastListener)
|
|
50
|
+
lastListener.paths.add(path);
|
|
51
|
+
}
|
|
49
52
|
return path;
|
|
50
53
|
}
|
|
51
54
|
exports.tmpDir = tmpDir;
|
|
52
|
-
|
|
55
|
+
exports.collectors = new Set();
|
|
53
56
|
async function mkTmpDir(...keys) {
|
|
54
57
|
const path = tmpDir(...keys);
|
|
55
58
|
await (0, promises_1.mkdir)(path, { recursive: true });
|
|
@@ -81,53 +84,57 @@ function useTempFile(path) {
|
|
|
81
84
|
};
|
|
82
85
|
}
|
|
83
86
|
exports.useTempFile = useTempFile;
|
|
84
|
-
class CleanupListener {
|
|
85
|
-
paths = [];
|
|
86
|
-
stop() {
|
|
87
|
-
listeners.delete(this);
|
|
88
|
-
}
|
|
89
|
-
async dispose() {
|
|
90
|
-
this.stop();
|
|
91
|
-
await rmTmpDir(this.paths);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
exports.CleanupListener = CleanupListener;
|
|
95
87
|
class GargabeCollector {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
88
|
+
parent;
|
|
89
|
+
paths = new Set();
|
|
90
|
+
children = new Set();
|
|
91
|
+
constructor(parent) {
|
|
92
|
+
this.parent = parent;
|
|
93
|
+
exports.collectors.add(this);
|
|
99
94
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
95
|
+
pending() {
|
|
96
|
+
if (this.paths.size)
|
|
97
|
+
return true;
|
|
98
|
+
for (const child of this.children)
|
|
99
|
+
if (child.pending())
|
|
100
|
+
return true;
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
async cleanup() {
|
|
104
|
+
for (const path of this.paths) {
|
|
105
|
+
try {
|
|
106
|
+
await rmTmpDir(path);
|
|
107
|
+
this.paths.delete(path);
|
|
108
108
|
}
|
|
109
|
+
catch (_) { }
|
|
109
110
|
}
|
|
111
|
+
for (const child of this.children)
|
|
112
|
+
await child.cleanup();
|
|
110
113
|
}
|
|
111
|
-
async
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
await cb();
|
|
115
|
-
}
|
|
116
|
-
finally {
|
|
117
|
-
cleanup.dispose();
|
|
118
|
-
}
|
|
114
|
+
async dispose() {
|
|
115
|
+
await this.cleanup();
|
|
116
|
+
exports.collectors.delete(this);
|
|
119
117
|
}
|
|
120
|
-
async
|
|
121
|
-
const cleanup = new CleanupListener();
|
|
118
|
+
async disposeIfFail(cb) {
|
|
122
119
|
try {
|
|
123
|
-
await cb();
|
|
120
|
+
return await cb();
|
|
124
121
|
}
|
|
125
122
|
catch (error) {
|
|
126
|
-
await
|
|
123
|
+
await this.dispose();
|
|
127
124
|
throw error;
|
|
128
125
|
}
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
}
|
|
127
|
+
disposeOnFinish() {
|
|
128
|
+
return {
|
|
129
|
+
[Symbol.asyncDispose]: async () => {
|
|
130
|
+
return this.dispose();
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
create() {
|
|
135
|
+
const gc = new GargabeCollector();
|
|
136
|
+
this.children.add(gc);
|
|
137
|
+
return gc;
|
|
131
138
|
}
|
|
132
139
|
}
|
|
133
140
|
exports.GargabeCollector = GargabeCollector;
|