@datatruck/cli 0.13.1 → 0.16.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 +7 -19
- package/Action/RestoreAction.js +4 -12
- 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 -5
- package/Error/AppError.d.ts +1 -0
- package/Error/AppError.js +4 -0
- package/Repository/DatatruckRepository.d.ts +2 -0
- package/Repository/DatatruckRepository.js +234 -123
- package/Repository/RepositoryAbstract.d.ts +4 -10
- package/Repository/ResticRepository.js +34 -17
- package/SessionDriver/ConsoleSessionDriver.d.ts +2 -7
- package/SessionDriver/ConsoleSessionDriver.js +51 -24
- package/SessionDriver/SqliteSessionDriver.js +5 -0
- package/SessionManager/BackupSessionManager.d.ts +12 -11
- package/SessionManager/BackupSessionManager.js +20 -5
- package/SessionManager/RestoreSessionManager.d.ts +14 -11
- package/SessionManager/RestoreSessionManager.js +20 -5
- package/SessionManager/SessionManagerAbstract.d.ts +18 -0
- package/SessionManager/SessionManagerAbstract.js +32 -0
- package/Task/GitTask.js +22 -14
- package/Task/MariadbTask.js +9 -4
- package/Task/MysqlDumpTask.d.ts +3 -1
- package/Task/MysqlDumpTask.js +5 -2
- package/Task/PostgresqlDumpTask.d.ts +3 -1
- package/Task/PostgresqlDumpTask.js +2 -2
- package/Task/SqlDumpTaskAbstract.d.ts +3 -1
- package/Task/SqlDumpTaskAbstract.js +55 -13
- package/Task/TaskAbstract.d.ts +3 -9
- package/cli.js +1 -1
- package/config.schema.json +3 -0
- package/migrations/001-initial.sql +6 -30
- package/package.json +1 -1
- package/util/cli-util.d.ts +1 -1
- package/util/cli-util.js +17 -2
- package/util/fs-util.d.ts +25 -21
- package/util/fs-util.js +60 -93
- package/util/math-util.js +2 -0
- package/util/process-util.d.ts +4 -0
- package/util/process-util.js +31 -4
- package/util/progress.d.ts +12 -0
- package/util/progress.js +2 -0
- package/util/string-util.d.ts +1 -0
- package/util/string-util.js +8 -1
- package/util/zip-util.d.ts +64 -20
- package/util/zip-util.js +153 -59
|
@@ -4,6 +4,7 @@ import type { RestoreActionOptionsType } from "../Action/RestoreAction";
|
|
|
4
4
|
import type { SnapshotExtendedType, SnapshotsActionOptionsType } from "../Action/SnapshotsAction";
|
|
5
5
|
import type { PackageConfigType } from "../Config/PackageConfig";
|
|
6
6
|
import type { RepositoryConfigType } from "../Config/RepositoryConfig";
|
|
7
|
+
import { Progress } from "../util/progress";
|
|
7
8
|
export declare type SnapshotType = {
|
|
8
9
|
id: string;
|
|
9
10
|
date: string;
|
|
@@ -15,13 +16,6 @@ export declare type SnapshotResultType = SnapshotType & {
|
|
|
15
16
|
tags: string[];
|
|
16
17
|
size: number;
|
|
17
18
|
};
|
|
18
|
-
export declare type ProgressDataType = {
|
|
19
|
-
total?: number;
|
|
20
|
-
current?: number;
|
|
21
|
-
percent?: number;
|
|
22
|
-
step?: string;
|
|
23
|
-
stepPercent?: number | null;
|
|
24
|
-
};
|
|
25
19
|
export declare type InitDataType = {
|
|
26
20
|
options: InitActionOptionsType;
|
|
27
21
|
};
|
|
@@ -33,7 +27,7 @@ export declare type CopyBackupType<TRepositoryConfig> = {
|
|
|
33
27
|
snapshot: SnapshotType;
|
|
34
28
|
package: PackageConfigType;
|
|
35
29
|
mirrorRepositoryConfig: TRepositoryConfig;
|
|
36
|
-
onProgress: (data:
|
|
30
|
+
onProgress: (data: Progress) => Promise<void>;
|
|
37
31
|
};
|
|
38
32
|
export declare type BackupDataType<TPackageConfig> = {
|
|
39
33
|
options: BackupActionOptionsType;
|
|
@@ -41,7 +35,7 @@ export declare type BackupDataType<TPackageConfig> = {
|
|
|
41
35
|
package: PackageConfigType;
|
|
42
36
|
targetPath: string | undefined;
|
|
43
37
|
packageConfig: TPackageConfig | undefined;
|
|
44
|
-
onProgress: (data:
|
|
38
|
+
onProgress: (data: Progress) => Promise<void>;
|
|
45
39
|
};
|
|
46
40
|
export declare type RestoreDataType<TPackageConfig> = {
|
|
47
41
|
options: RestoreActionOptionsType;
|
|
@@ -49,7 +43,7 @@ export declare type RestoreDataType<TPackageConfig> = {
|
|
|
49
43
|
package: PackageConfigType;
|
|
50
44
|
targetPath: string | undefined;
|
|
51
45
|
packageConfig: TPackageConfig;
|
|
52
|
-
onProgress: (data:
|
|
46
|
+
onProgress: (data: Progress) => Promise<void>;
|
|
53
47
|
};
|
|
54
48
|
export declare type PruneDataType = {
|
|
55
49
|
snapshot: SnapshotExtendedType;
|
|
@@ -195,7 +195,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
195
195
|
verbose: data.options.verbose,
|
|
196
196
|
});
|
|
197
197
|
await data.onProgress({
|
|
198
|
-
|
|
198
|
+
relative: {
|
|
199
|
+
description: "Writing excluded paths list",
|
|
200
|
+
},
|
|
199
201
|
});
|
|
200
202
|
const tmpDir = await (0, fs_util_1.mkTmpDir)("restic-exclude");
|
|
201
203
|
const ignoredContents = (0, fs_util_1.fastglobToGitIgnore)(exclude, sourcePath).join("\n");
|
|
@@ -223,7 +225,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
223
225
|
if (data.options.verbose)
|
|
224
226
|
(0, cli_util_1.logExec)(`Writing paths lists`);
|
|
225
227
|
await data.onProgress({
|
|
226
|
-
|
|
228
|
+
relative: {
|
|
229
|
+
description: "Writing excluded paths list",
|
|
230
|
+
},
|
|
227
231
|
});
|
|
228
232
|
gitignorePath = await (0, fs_util_1.writeGitIgnoreList)({
|
|
229
233
|
paths: stream,
|
|
@@ -233,7 +237,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
233
237
|
throw new AppError_1.AppError(`Tag prefix is not allowed`);
|
|
234
238
|
const packageTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.PACKAGE, data.package.name);
|
|
235
239
|
await data.onProgress({
|
|
236
|
-
|
|
240
|
+
relative: {
|
|
241
|
+
description: "Fetching last snapshot",
|
|
242
|
+
},
|
|
237
243
|
});
|
|
238
244
|
const [lastSnapshot] = await restic.snapshots({
|
|
239
245
|
json: true,
|
|
@@ -245,7 +251,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
245
251
|
let totalFilesChanges = 0;
|
|
246
252
|
const totalFilesChangesLimit = 10;
|
|
247
253
|
await data.onProgress({
|
|
248
|
-
|
|
254
|
+
relative: {
|
|
255
|
+
description: "Executing backup action",
|
|
256
|
+
},
|
|
249
257
|
});
|
|
250
258
|
let resticSnapshotId;
|
|
251
259
|
let resticTotalBytes;
|
|
@@ -278,19 +286,24 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
278
286
|
if (totalFilesChanges > totalFilesChangesLimit) {
|
|
279
287
|
showProgressBar = true;
|
|
280
288
|
}
|
|
281
|
-
else if (lastProgress?.total !== streamData.total_files) {
|
|
289
|
+
else if (lastProgress?.absolute?.total !== streamData.total_files) {
|
|
282
290
|
totalFilesChanges = 0;
|
|
283
291
|
}
|
|
284
292
|
else {
|
|
285
293
|
totalFilesChanges++;
|
|
286
294
|
}
|
|
287
295
|
await data.onProgress((lastProgress = {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
296
|
+
relative: {
|
|
297
|
+
description: "Copying file",
|
|
298
|
+
payload: streamData.current_files?.join(", ") ?? "-",
|
|
299
|
+
},
|
|
300
|
+
absolute: {
|
|
301
|
+
total: Math.max(lastProgress?.absolute?.total || 0, streamData.total_files || 0),
|
|
302
|
+
current: Math.max(lastProgress?.absolute?.current || 0, streamData.files_done ?? 0),
|
|
303
|
+
percent: showProgressBar
|
|
304
|
+
? Number((streamData.percent_done * 100).toFixed(2))
|
|
305
|
+
: 0,
|
|
306
|
+
},
|
|
294
307
|
}));
|
|
295
308
|
}
|
|
296
309
|
else if (streamData.message_type === "summary") {
|
|
@@ -306,9 +319,11 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
306
319
|
const sizeTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.SIZE, resticTotalBytes.toString());
|
|
307
320
|
await restic.exec(["tag", "--add", sizeTag, resticSnapshotId]);
|
|
308
321
|
await data.onProgress({
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
322
|
+
absolute: {
|
|
323
|
+
total: lastProgress?.absolute?.total || 0,
|
|
324
|
+
current: lastProgress?.absolute?.total || 0,
|
|
325
|
+
percent: 100,
|
|
326
|
+
},
|
|
312
327
|
});
|
|
313
328
|
}
|
|
314
329
|
async onCopyBackup(data) {
|
|
@@ -357,9 +372,11 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
357
372
|
if (streamData.message_type === "restore-status") {
|
|
358
373
|
const current = Math.min(streamData.total_bytes, snapshot.size);
|
|
359
374
|
await data.onProgress({
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
375
|
+
absolute: {
|
|
376
|
+
total: snapshot.size,
|
|
377
|
+
current,
|
|
378
|
+
percent: (0, math_util_1.progressPercent)(snapshot.size, current),
|
|
379
|
+
},
|
|
363
380
|
});
|
|
364
381
|
}
|
|
365
382
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import { Progress } from "../util/progress";
|
|
2
3
|
import { WriteDataType, ReadResultType, SessionDriverAbstract, SessionDriverOptions } from "./SessionDriverAbstract";
|
|
3
4
|
declare type BadgeType = {
|
|
4
5
|
name: string;
|
|
@@ -12,20 +13,14 @@ declare type MessageType = {
|
|
|
12
13
|
text?: string;
|
|
13
14
|
badges: BadgeType[];
|
|
14
15
|
errorBadge?: BadgeType;
|
|
15
|
-
|
|
16
|
-
progressTotal?: number | null;
|
|
17
|
-
progressPercent?: number | null;
|
|
18
|
-
progressStep?: string | null;
|
|
19
|
-
progressStepPercent?: number | null;
|
|
16
|
+
progress?: Progress;
|
|
20
17
|
};
|
|
21
18
|
declare type ConsoleSessionDriverOptions = SessionDriverOptions & {
|
|
22
19
|
progress?: "auto" | "tty" | "plain";
|
|
23
|
-
progressInterval?: number;
|
|
24
20
|
};
|
|
25
21
|
export declare class ConsoleSessionDriver extends SessionDriverAbstract<ConsoleSessionDriverOptions> {
|
|
26
22
|
protected lastMessage: MessageType | undefined;
|
|
27
23
|
protected lastMessageText: string | undefined;
|
|
28
|
-
protected lastProgressDate: number | undefined;
|
|
29
24
|
protected prints: number;
|
|
30
25
|
protected renderInterval: NodeJS.Timeout;
|
|
31
26
|
protected rendering?: boolean;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.ConsoleSessionDriver = void 0;
|
|
4
7
|
const AppError_1 = require("../Error/AppError");
|
|
@@ -6,6 +9,7 @@ const cli_util_1 = require("../util/cli-util");
|
|
|
6
9
|
const date_util_1 = require("../util/date-util");
|
|
7
10
|
const SessionDriverAbstract_1 = require("./SessionDriverAbstract");
|
|
8
11
|
const chalk_1 = require("chalk");
|
|
12
|
+
const pretty_bytes_1 = __importDefault(require("pretty-bytes"));
|
|
9
13
|
const sep = (0, chalk_1.grey)(`|`);
|
|
10
14
|
const renderBadge = (badge) => `${badge.color(badge.name)}${(0, chalk_1.grey)(`:`)} ${(0, chalk_1.white)(badge.value)}`;
|
|
11
15
|
const renderBadges = (badges) => badges.map(renderBadge).join(` ${sep} `);
|
|
@@ -72,34 +76,59 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
72
76
|
]);
|
|
73
77
|
const padding = " ".repeat(message.level ?? 0);
|
|
74
78
|
const sessionId = message.sessionId.toString().padStart(2, "0");
|
|
75
|
-
|
|
79
|
+
let parts = [
|
|
76
80
|
`${padding}${message.textPrefix} [${(0, chalk_1.grey)(sessionId)}] ${message.text}`,
|
|
77
81
|
badges,
|
|
78
82
|
];
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
const progress = message.progress;
|
|
84
|
+
const absolute = progress?.absolute || {};
|
|
85
|
+
const relative = progress?.relative || {};
|
|
86
|
+
if (typeof absolute.percent === "number" ||
|
|
87
|
+
typeof relative.percent === "number") {
|
|
88
|
+
parts.push((0, cli_util_1.renderProgressBar)(absolute.percent ?? 0, 10, relative.percent ?? undefined));
|
|
81
89
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
const createProgressParts = (p) => {
|
|
91
|
+
const result = [];
|
|
92
|
+
if (typeof p.percent === "number")
|
|
93
|
+
result.push(`${p.percent.toFixed(2)}%`);
|
|
94
|
+
if (typeof p.current === "number" || typeof p.total === "number") {
|
|
95
|
+
const format = (value) => p.format === "size" ? (0, pretty_bytes_1.default)(value) : value;
|
|
96
|
+
if (typeof p.current === "number" && typeof p.total === "number") {
|
|
97
|
+
result.push(`${format(p.current)}/${format(p.total)}`);
|
|
98
|
+
}
|
|
99
|
+
else if (typeof p.current === "number") {
|
|
100
|
+
result.push(`${format(p.current)}`);
|
|
101
|
+
}
|
|
102
|
+
else if (typeof p.total === "number") {
|
|
103
|
+
result.push(`?/${format(p.total)}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (p.description && p.payload) {
|
|
107
|
+
result.push(`${p.description}: ${p.payload}`);
|
|
108
|
+
}
|
|
109
|
+
else if (p.description) {
|
|
110
|
+
result.push(p.description);
|
|
111
|
+
}
|
|
112
|
+
else if (p.payload) {
|
|
113
|
+
result.push(p.payload);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
};
|
|
117
|
+
if (progress?.absolute)
|
|
118
|
+
parts.push(...createProgressParts(progress?.absolute));
|
|
119
|
+
if (progress?.relative) {
|
|
120
|
+
const relativeParts = createProgressParts(progress?.relative);
|
|
121
|
+
if (relativeParts.length) {
|
|
122
|
+
return (parts.join(` ${sep} `) +
|
|
123
|
+
` ${(0, chalk_1.cyan)("▷")} ` +
|
|
124
|
+
relativeParts.join(` ${sep} `));
|
|
125
|
+
}
|
|
90
126
|
}
|
|
91
127
|
return parts.join(` ${sep} `);
|
|
92
128
|
}
|
|
93
129
|
async onWrite(data) {
|
|
94
130
|
if (data.action === SessionDriverAbstract_1.ActionEnum.Init)
|
|
95
131
|
return;
|
|
96
|
-
if (data.action === SessionDriverAbstract_1.ActionEnum.Progress && this.options.progressInterval) {
|
|
97
|
-
const skip = this.lastProgressDate &&
|
|
98
|
-
Date.now() - this.lastProgressDate < this.options.progressInterval;
|
|
99
|
-
if (skip)
|
|
100
|
-
return;
|
|
101
|
-
this.lastProgressDate = Date.now();
|
|
102
|
-
}
|
|
103
132
|
const message = {
|
|
104
133
|
sessionId: "sessionId" in data.data ? data.data.sessionId : data.data.id,
|
|
105
134
|
badges: [],
|
|
@@ -124,7 +153,9 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
124
153
|
if (data.data.error)
|
|
125
154
|
message.errorBadge = {
|
|
126
155
|
name: "error",
|
|
127
|
-
value: this.tty
|
|
156
|
+
value: this.tty && data.data.error.startsWith(`${AppError_1.AppError.name} :`)
|
|
157
|
+
? data.data.error.split("\n")[0]
|
|
158
|
+
: data.data.error,
|
|
128
159
|
color: chalk_1.red,
|
|
129
160
|
};
|
|
130
161
|
}
|
|
@@ -132,11 +163,7 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
132
163
|
message.textPrefix = "{spinner}";
|
|
133
164
|
}
|
|
134
165
|
if (hasProgress) {
|
|
135
|
-
message.
|
|
136
|
-
message.progressCurrent = data.data.progressCurrent;
|
|
137
|
-
message.progressTotal = data.data.progressTotal;
|
|
138
|
-
message.progressStep = data.data.progressStep;
|
|
139
|
-
message.progressStepPercent = data.data.progressStepPercent;
|
|
166
|
+
message.progress = data.data.progress;
|
|
140
167
|
}
|
|
141
168
|
if (data.entity === SessionDriverAbstract_1.EntityEnum.BackupSession ||
|
|
142
169
|
data.entity === SessionDriverAbstract_1.EntityEnum.RestoreSession) {
|
|
@@ -134,6 +134,11 @@ class SqliteSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
134
134
|
let stm;
|
|
135
135
|
let object = data.data;
|
|
136
136
|
const id = object.id;
|
|
137
|
+
object = {
|
|
138
|
+
...object,
|
|
139
|
+
// @ts-expect-error
|
|
140
|
+
progress: data.data.progress ? JSON.stringify(data.data.progress) : null,
|
|
141
|
+
};
|
|
137
142
|
if (data.action === SessionDriverAbstract_1.ActionEnum.Init) {
|
|
138
143
|
// @ts-expect-error
|
|
139
144
|
object = { ...object, id: null };
|
|
@@ -2,19 +2,14 @@ import { BackupSessionsActionOptionsType } from "../Action/BackupSessionsAction"
|
|
|
2
2
|
import { BackupSessionEntity } from "../Entity/BackupSessionEntity";
|
|
3
3
|
import { BackupSessionRepositoryEntity } from "../Entity/BackupSessionRepositoryEntity";
|
|
4
4
|
import { BackupSessionTaskEntity } from "../Entity/BackupSessionTaskEntity";
|
|
5
|
-
import { WriteDataType
|
|
5
|
+
import { WriteDataType } from "../SessionDriver/SessionDriverAbstract";
|
|
6
6
|
import { ObjectVault } from "../util/ObjectVault";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
verbose?: boolean;
|
|
11
|
-
};
|
|
12
|
-
export declare class BackupSessionManager {
|
|
13
|
-
readonly options: OptionsType;
|
|
7
|
+
import { Progress } from "../util/progress";
|
|
8
|
+
import SessionManagerAbstract from "./SessionManagerAbstract";
|
|
9
|
+
export declare class BackupSessionManager extends SessionManagerAbstract {
|
|
14
10
|
sessionVault: ObjectVault<BackupSessionEntity>;
|
|
15
11
|
taskVault: ObjectVault<BackupSessionTaskEntity>;
|
|
16
12
|
repositoryVault: ObjectVault<BackupSessionRepositoryEntity>;
|
|
17
|
-
constructor(options: OptionsType);
|
|
18
13
|
findId(data: {
|
|
19
14
|
packageName: string;
|
|
20
15
|
}): number;
|
|
@@ -36,9 +31,15 @@ export declare class BackupSessionManager {
|
|
|
36
31
|
start(input: Pick<BackupSessionEntity, "id">): Promise<number>;
|
|
37
32
|
end(input: Pick<BackupSessionEntity, "id" | "error">): Promise<number>;
|
|
38
33
|
startTask(input: Pick<BackupSessionTaskEntity, "id">): Promise<number>;
|
|
39
|
-
progressTask(input:
|
|
34
|
+
progressTask(input: {
|
|
35
|
+
id: number;
|
|
36
|
+
progress: Progress;
|
|
37
|
+
}): Promise<number>;
|
|
40
38
|
endTask(input: Pick<BackupSessionTaskEntity, "id" | "error">): Promise<number>;
|
|
41
39
|
startRepository(input: Pick<BackupSessionRepositoryEntity, "id">): Promise<number>;
|
|
42
|
-
progressRepository(input:
|
|
40
|
+
progressRepository(input: {
|
|
41
|
+
id: number;
|
|
42
|
+
progress: Progress;
|
|
43
|
+
}): Promise<number>;
|
|
43
44
|
endRepository(input: Pick<BackupSessionRepositoryEntity, "id" | "error">): Promise<number>;
|
|
44
45
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.BackupSessionManager = void 0;
|
|
4
7
|
const SessionDriverAbstract_1 = require("../SessionDriver/SessionDriverAbstract");
|
|
5
8
|
const ObjectVault_1 = require("../util/ObjectVault");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
const SessionManagerAbstract_1 = __importDefault(require("./SessionManagerAbstract"));
|
|
10
|
+
class BackupSessionManager extends SessionManagerAbstract_1.default {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
9
13
|
this.sessionVault = new ObjectVault_1.ObjectVault();
|
|
10
14
|
this.taskVault = new ObjectVault_1.ObjectVault();
|
|
11
15
|
this.repositoryVault = new ObjectVault_1.ObjectVault();
|
|
@@ -29,14 +33,25 @@ class BackupSessionManager {
|
|
|
29
33
|
}
|
|
30
34
|
async endDrivers(data) {
|
|
31
35
|
const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
|
|
36
|
+
this.stopDelayedProgress();
|
|
32
37
|
for (const driver of drivers) {
|
|
33
38
|
await driver.onEnd(data);
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
async alter(data) {
|
|
37
42
|
const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
const write = async () => {
|
|
44
|
+
for (const driver of drivers) {
|
|
45
|
+
await driver.onWrite(data);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
if (data.action === SessionDriverAbstract_1.ActionEnum.Progress &&
|
|
49
|
+
!this.checkProgress(data.data.progress?.relative?.description)) {
|
|
50
|
+
this.delayProgress(write);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.stopDelayedProgress();
|
|
54
|
+
await write();
|
|
40
55
|
}
|
|
41
56
|
return data.data.id;
|
|
42
57
|
}
|
|
@@ -2,19 +2,16 @@ import { BackupSessionsActionOptionsType } from "../Action/BackupSessionsAction"
|
|
|
2
2
|
import { RestoreSessionEntity } from "../Entity/RestoreSessionEntity";
|
|
3
3
|
import { RestoreSessionRepositoryEntity } from "../Entity/RestoreSessionRepositoryEntity";
|
|
4
4
|
import { RestoreSessionTaskEntity } from "../Entity/RestoreSessionTaskEntity";
|
|
5
|
-
import { WriteDataType
|
|
5
|
+
import { WriteDataType } from "../SessionDriver/SessionDriverAbstract";
|
|
6
6
|
import { ObjectVault } from "../util/ObjectVault";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
verbose?: boolean;
|
|
11
|
-
};
|
|
12
|
-
export declare class RestoreSessionManager {
|
|
13
|
-
readonly options: OptionsType;
|
|
7
|
+
import { Progress } from "../util/progress";
|
|
8
|
+
import SessionManagerAbstract from "./SessionManagerAbstract";
|
|
9
|
+
export declare class RestoreSessionManager extends SessionManagerAbstract {
|
|
14
10
|
sessionVault: ObjectVault<RestoreSessionEntity>;
|
|
15
11
|
repositoryVault: ObjectVault<RestoreSessionRepositoryEntity>;
|
|
16
12
|
taskVault: ObjectVault<RestoreSessionTaskEntity>;
|
|
17
|
-
|
|
13
|
+
protected lastProgressDate: number | undefined;
|
|
14
|
+
protected lastRelativeProgressDescription: string | null | undefined;
|
|
18
15
|
findId(data: {
|
|
19
16
|
packageName: string;
|
|
20
17
|
}): number;
|
|
@@ -37,8 +34,14 @@ export declare class RestoreSessionManager {
|
|
|
37
34
|
end(input: Pick<RestoreSessionEntity, "id" | "error">): Promise<number>;
|
|
38
35
|
startTask(input: Pick<RestoreSessionTaskEntity, "id">): Promise<number>;
|
|
39
36
|
startRepository(input: Pick<RestoreSessionRepositoryEntity, "id">): Promise<number>;
|
|
40
|
-
progressTask(input:
|
|
37
|
+
progressTask(input: {
|
|
38
|
+
id: number;
|
|
39
|
+
progress: Progress;
|
|
40
|
+
}): Promise<number>;
|
|
41
41
|
endTask(input: Pick<RestoreSessionTaskEntity, "id" | "error">): Promise<number>;
|
|
42
|
-
progressRepository(input:
|
|
42
|
+
progressRepository(input: {
|
|
43
|
+
id: number;
|
|
44
|
+
progress: Progress;
|
|
45
|
+
}): Promise<number>;
|
|
43
46
|
endRepository(input: Pick<RestoreSessionRepositoryEntity, "id" | "error">): Promise<number>;
|
|
44
47
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.RestoreSessionManager = void 0;
|
|
4
7
|
const SessionDriverAbstract_1 = require("../SessionDriver/SessionDriverAbstract");
|
|
5
8
|
const ObjectVault_1 = require("../util/ObjectVault");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
const SessionManagerAbstract_1 = __importDefault(require("./SessionManagerAbstract"));
|
|
10
|
+
class RestoreSessionManager extends SessionManagerAbstract_1.default {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
9
13
|
this.sessionVault = new ObjectVault_1.ObjectVault();
|
|
10
14
|
this.repositoryVault = new ObjectVault_1.ObjectVault();
|
|
11
15
|
this.taskVault = new ObjectVault_1.ObjectVault();
|
|
@@ -29,14 +33,25 @@ class RestoreSessionManager {
|
|
|
29
33
|
}
|
|
30
34
|
async endDrivers() {
|
|
31
35
|
const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
|
|
36
|
+
this.stopDelayedProgress();
|
|
32
37
|
for (const driver of drivers) {
|
|
33
38
|
await driver.onEnd();
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
async alter(data) {
|
|
37
42
|
const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
const write = async () => {
|
|
44
|
+
for (const driver of drivers) {
|
|
45
|
+
await driver.onWrite(data);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
if (data.action === SessionDriverAbstract_1.ActionEnum.Progress &&
|
|
49
|
+
!this.checkProgress(data.data.progress?.relative?.description)) {
|
|
50
|
+
this.delayProgress(write);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.stopDelayedProgress();
|
|
54
|
+
await write();
|
|
40
55
|
}
|
|
41
56
|
return data.data.id;
|
|
42
57
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { SessionDriverAbstract } from "../SessionDriver/SessionDriverAbstract";
|
|
3
|
+
export declare type OptionsType = {
|
|
4
|
+
driver: SessionDriverAbstract;
|
|
5
|
+
altDrivers?: SessionDriverAbstract[];
|
|
6
|
+
progressInterval?: number;
|
|
7
|
+
verbose?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export default abstract class SessionManagerAbstract {
|
|
10
|
+
readonly options: OptionsType;
|
|
11
|
+
protected lastProgressDate: number | undefined;
|
|
12
|
+
protected lastRelativeProgressDescription: string | null | undefined;
|
|
13
|
+
protected progressTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
14
|
+
constructor(options: OptionsType);
|
|
15
|
+
protected stopDelayedProgress(): void;
|
|
16
|
+
protected delayProgress(cb: () => Promise<any>): void;
|
|
17
|
+
protected checkProgress(description: string | null | undefined): boolean;
|
|
18
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class SessionManagerAbstract {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
stopDelayedProgress() {
|
|
8
|
+
clearTimeout(this.progressTimeout);
|
|
9
|
+
this.progressTimeout = undefined;
|
|
10
|
+
}
|
|
11
|
+
delayProgress(cb) {
|
|
12
|
+
clearTimeout(this.progressTimeout);
|
|
13
|
+
this.progressTimeout = setTimeout(async () => {
|
|
14
|
+
this.progressTimeout = undefined;
|
|
15
|
+
await cb();
|
|
16
|
+
}, 1500);
|
|
17
|
+
}
|
|
18
|
+
checkProgress(description) {
|
|
19
|
+
const progressInterval = this.options.progressInterval;
|
|
20
|
+
if (progressInterval) {
|
|
21
|
+
const skip = this.lastProgressDate &&
|
|
22
|
+
description === this.lastRelativeProgressDescription &&
|
|
23
|
+
Date.now() - this.lastProgressDate < progressInterval;
|
|
24
|
+
if (skip)
|
|
25
|
+
return false;
|
|
26
|
+
this.lastProgressDate = Date.now();
|
|
27
|
+
this.lastRelativeProgressDescription = description;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.default = SessionManagerAbstract;
|
package/Task/GitTask.js
CHANGED
|
@@ -73,7 +73,9 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
|
|
|
73
73
|
// Bundle
|
|
74
74
|
const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
|
|
75
75
|
await data.onProgress({
|
|
76
|
-
|
|
76
|
+
relative: {
|
|
77
|
+
description: "Creating bundle",
|
|
78
|
+
},
|
|
77
79
|
});
|
|
78
80
|
await (0, process_util_1.exec)(this.command, ["bundle", "create", bundlePath, "--all"], {
|
|
79
81
|
cwd: path,
|
|
@@ -174,10 +176,15 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
|
|
|
174
176
|
onPath: async ({ entryPath }) => {
|
|
175
177
|
currentFiles++;
|
|
176
178
|
await data.onProgress({
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
relative: {
|
|
180
|
+
description: "Copying file",
|
|
181
|
+
payload: entryPath,
|
|
182
|
+
},
|
|
183
|
+
absolute: {
|
|
184
|
+
total,
|
|
185
|
+
current: currentFiles,
|
|
186
|
+
percent: (0, math_util_1.progressPercent)(total, currentFiles),
|
|
187
|
+
},
|
|
181
188
|
});
|
|
182
189
|
},
|
|
183
190
|
});
|
|
@@ -201,14 +208,17 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
|
|
|
201
208
|
let totalFiles = 0;
|
|
202
209
|
let currentFiles = 0;
|
|
203
210
|
await (0, fs_util_1.forEachFile)(targetPath, () => totalFiles++, true);
|
|
204
|
-
const incrementProgress = async (
|
|
211
|
+
const incrementProgress = async (description, item, count = true) => {
|
|
205
212
|
await data.onProgress({
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
absolute: {
|
|
214
|
+
total: totalFiles,
|
|
215
|
+
current: Math.max(currentFiles, 0),
|
|
216
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
|
|
217
|
+
},
|
|
218
|
+
relative: { description, payload: item },
|
|
210
219
|
});
|
|
211
|
-
|
|
220
|
+
if (count)
|
|
221
|
+
currentFiles++;
|
|
212
222
|
};
|
|
213
223
|
// Bundle
|
|
214
224
|
const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
|
|
@@ -237,9 +247,7 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
|
|
|
237
247
|
},
|
|
238
248
|
targetPath: restorePath,
|
|
239
249
|
concurrency: this.config.fileCopyConcurrency,
|
|
240
|
-
|
|
241
|
-
await incrementProgress(entryPath);
|
|
242
|
-
},
|
|
250
|
+
onProgress: async (progress) => await incrementProgress(progress.type === "end" ? "Files copied" : "Copying file", progress.path, !progress.type),
|
|
243
251
|
});
|
|
244
252
|
}
|
|
245
253
|
}
|
package/Task/MariadbTask.js
CHANGED
|
@@ -108,10 +108,15 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
|
|
|
108
108
|
else if (paths.length) {
|
|
109
109
|
const path = (0, posix_1.normalize)(paths[0]);
|
|
110
110
|
await data.onProgress({
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
relative: {
|
|
112
|
+
description: "Copying file",
|
|
113
|
+
payload: path,
|
|
114
|
+
},
|
|
115
|
+
absolute: {
|
|
116
|
+
current,
|
|
117
|
+
percent: (0, math_util_1.progressPercent)(total, current),
|
|
118
|
+
total,
|
|
119
|
+
},
|
|
115
120
|
});
|
|
116
121
|
}
|
|
117
122
|
};
|
package/Task/MysqlDumpTask.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export declare class MysqlDumpTask extends SqlDumpTaskAbstract<MysqlDumpTaskConf
|
|
|
9
9
|
onCreateDatabase(database: TargetDatabaseType): Promise<void>;
|
|
10
10
|
onExecQuery(query: string): Promise<import("../util/process-util").ExecResultType>;
|
|
11
11
|
onFetchTableNames(database: string): Promise<string[]>;
|
|
12
|
-
onExportTables(tableNames: string[], output: string
|
|
12
|
+
onExportTables(tableNames: string[], output: string, onProgress: (progress: {
|
|
13
|
+
totalBytes: number;
|
|
14
|
+
}) => void): Promise<void>;
|
|
13
15
|
onExportStoredPrograms(output: string): Promise<void>;
|
|
14
16
|
onImport(path: string, database: string): Promise<void>;
|
|
15
17
|
}
|