@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
|
@@ -195,7 +195,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
195
195
|
verbose: data.options.verbose,
|
|
196
196
|
});
|
|
197
197
|
await data.onProgress({
|
|
198
|
-
step:
|
|
198
|
+
step: {
|
|
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
|
-
step:
|
|
228
|
+
step: {
|
|
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
|
-
step:
|
|
240
|
+
step: {
|
|
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
|
-
step:
|
|
254
|
+
step: {
|
|
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?.stats?.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
|
+
step: {
|
|
297
|
+
description: "Copying file",
|
|
298
|
+
item: streamData.current_files?.join(", ") ?? "-",
|
|
299
|
+
},
|
|
300
|
+
stats: {
|
|
301
|
+
total: Math.max(lastProgress?.stats?.total || 0, streamData.total_files || 0),
|
|
302
|
+
current: Math.max(lastProgress?.stats?.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
|
+
stats: {
|
|
323
|
+
total: lastProgress?.stats?.total || 0,
|
|
324
|
+
current: lastProgress?.stats?.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
|
+
stats: {
|
|
376
|
+
total: snapshot.size,
|
|
377
|
+
current,
|
|
378
|
+
percent: (0, math_util_1.progressPercent)(snapshot.size, current),
|
|
379
|
+
},
|
|
363
380
|
});
|
|
364
381
|
}
|
|
365
382
|
},
|
|
@@ -15,17 +15,16 @@ declare type MessageType = {
|
|
|
15
15
|
progressCurrent?: number | null;
|
|
16
16
|
progressTotal?: number | null;
|
|
17
17
|
progressPercent?: number | null;
|
|
18
|
-
|
|
18
|
+
progressStepDescription?: string | null;
|
|
19
|
+
progressStepItem?: string | null;
|
|
19
20
|
progressStepPercent?: number | null;
|
|
20
21
|
};
|
|
21
22
|
declare type ConsoleSessionDriverOptions = SessionDriverOptions & {
|
|
22
23
|
progress?: "auto" | "tty" | "plain";
|
|
23
|
-
progressInterval?: number;
|
|
24
24
|
};
|
|
25
25
|
export declare class ConsoleSessionDriver extends SessionDriverAbstract<ConsoleSessionDriverOptions> {
|
|
26
26
|
protected lastMessage: MessageType | undefined;
|
|
27
27
|
protected lastMessageText: string | undefined;
|
|
28
|
-
protected lastProgressDate: number | undefined;
|
|
29
28
|
protected prints: number;
|
|
30
29
|
protected renderInterval: NodeJS.Timeout;
|
|
31
30
|
protected rendering?: boolean;
|
|
@@ -83,8 +83,15 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
83
83
|
typeof message.progressTotal === "number") {
|
|
84
84
|
parts.push(`${message.progressCurrent ?? "?"}/${message.progressTotal ?? "?"}`);
|
|
85
85
|
}
|
|
86
|
-
if (
|
|
87
|
-
parts.push(message.
|
|
86
|
+
if (message.progressStepDescription && message.progressStepItem) {
|
|
87
|
+
parts.push(`${message.progressStepDescription}: ${message.progressStepItem}`);
|
|
88
|
+
}
|
|
89
|
+
else if (message.progressStepDescription) {
|
|
90
|
+
parts.push(message.progressStepDescription);
|
|
91
|
+
}
|
|
92
|
+
else if (message.progressStepItem) {
|
|
93
|
+
parts.push(message.progressStepItem);
|
|
94
|
+
}
|
|
88
95
|
if (typeof message.progressStepPercent === "number") {
|
|
89
96
|
parts.push((0, chalk_1.cyan)((0, cli_util_1.renderProgressBar)(message.progressStepPercent ?? 0, 10)));
|
|
90
97
|
}
|
|
@@ -93,13 +100,6 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
93
100
|
async onWrite(data) {
|
|
94
101
|
if (data.action === SessionDriverAbstract_1.ActionEnum.Init)
|
|
95
102
|
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
103
|
const message = {
|
|
104
104
|
sessionId: "sessionId" in data.data ? data.data.sessionId : data.data.id,
|
|
105
105
|
badges: [],
|
|
@@ -135,7 +135,8 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
135
135
|
message.progressPercent = data.data.progressPercent;
|
|
136
136
|
message.progressCurrent = data.data.progressCurrent;
|
|
137
137
|
message.progressTotal = data.data.progressTotal;
|
|
138
|
-
message.
|
|
138
|
+
message.progressStepDescription = data.data.progressStepDescription;
|
|
139
|
+
message.progressStepItem = data.data.progressStepItem;
|
|
139
140
|
message.progressStepPercent = data.data.progressStepPercent;
|
|
140
141
|
}
|
|
141
142
|
if (data.entity === SessionDriverAbstract_1.EntityEnum.BackupSession ||
|
|
@@ -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 {
|
|
5
|
+
import { ProgressDataType } from "../Repository/RepositoryAbstract";
|
|
6
|
+
import { WriteDataType } from "../SessionDriver/SessionDriverAbstract";
|
|
6
7
|
import { ObjectVault } from "../util/ObjectVault";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
altDrivers?: SessionDriverAbstract[];
|
|
10
|
-
verbose?: boolean;
|
|
11
|
-
};
|
|
12
|
-
export declare class BackupSessionManager {
|
|
13
|
-
readonly options: OptionsType;
|
|
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,13 @@ 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
|
+
} & ProgressDataType): Promise<number>;
|
|
40
37
|
endTask(input: Pick<BackupSessionTaskEntity, "id" | "error">): Promise<number>;
|
|
41
38
|
startRepository(input: Pick<BackupSessionRepositoryEntity, "id">): Promise<number>;
|
|
42
|
-
progressRepository(input:
|
|
39
|
+
progressRepository(input: {
|
|
40
|
+
id: number;
|
|
41
|
+
} & ProgressDataType): Promise<number>;
|
|
43
42
|
endRepository(input: Pick<BackupSessionRepositoryEntity, "id" | "error">): Promise<number>;
|
|
44
43
|
}
|
|
@@ -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();
|
|
@@ -35,6 +39,9 @@ class BackupSessionManager {
|
|
|
35
39
|
}
|
|
36
40
|
async alter(data) {
|
|
37
41
|
const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
|
|
42
|
+
if (data.action === SessionDriverAbstract_1.ActionEnum.Progress &&
|
|
43
|
+
!this.checkProgress(data.data.progressStepDescription))
|
|
44
|
+
return data.data.id;
|
|
38
45
|
for (const driver of drivers) {
|
|
39
46
|
await driver.onWrite(data);
|
|
40
47
|
}
|
|
@@ -139,7 +146,13 @@ class BackupSessionManager {
|
|
|
139
146
|
sessionData: this.sessionVault.get(object.sessionId),
|
|
140
147
|
data: {
|
|
141
148
|
...object,
|
|
142
|
-
|
|
149
|
+
id: input.id,
|
|
150
|
+
progressCurrent: input.stats?.current,
|
|
151
|
+
progressTotal: input.stats?.total,
|
|
152
|
+
progressPercent: input.stats?.percent,
|
|
153
|
+
progressStepDescription: input.step?.description,
|
|
154
|
+
progressStepItem: input.step?.item,
|
|
155
|
+
progressStepPercent: input.step?.percent,
|
|
143
156
|
updatingDate: new Date().toISOString(),
|
|
144
157
|
},
|
|
145
158
|
});
|
|
@@ -182,7 +195,13 @@ class BackupSessionManager {
|
|
|
182
195
|
sessionData: this.sessionVault.get(object.sessionId),
|
|
183
196
|
data: {
|
|
184
197
|
...object,
|
|
185
|
-
|
|
198
|
+
id: input.id,
|
|
199
|
+
progressCurrent: input.stats?.current,
|
|
200
|
+
progressTotal: input.stats?.total,
|
|
201
|
+
progressPercent: input.stats?.percent,
|
|
202
|
+
progressStepDescription: input.step?.description,
|
|
203
|
+
progressStepItem: input.step?.item,
|
|
204
|
+
progressStepPercent: input.step?.percent,
|
|
186
205
|
updatingDate: new Date().toISOString(),
|
|
187
206
|
},
|
|
188
207
|
});
|
|
@@ -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 {
|
|
5
|
+
import { ProgressDataType } from "../Repository/RepositoryAbstract";
|
|
6
|
+
import { WriteDataType } from "../SessionDriver/SessionDriverAbstract";
|
|
6
7
|
import { ObjectVault } from "../util/ObjectVault";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
altDrivers?: SessionDriverAbstract[];
|
|
10
|
-
verbose?: boolean;
|
|
11
|
-
};
|
|
12
|
-
export declare class RestoreSessionManager {
|
|
13
|
-
readonly options: OptionsType;
|
|
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 lastProgressStepDescription: string | null | undefined;
|
|
18
15
|
findId(data: {
|
|
19
16
|
packageName: string;
|
|
20
17
|
}): number;
|
|
@@ -37,8 +34,12 @@ 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
|
+
} & ProgressDataType): Promise<number>;
|
|
41
40
|
endTask(input: Pick<RestoreSessionTaskEntity, "id" | "error">): Promise<number>;
|
|
42
|
-
progressRepository(input:
|
|
41
|
+
progressRepository(input: {
|
|
42
|
+
id: number;
|
|
43
|
+
} & ProgressDataType): Promise<number>;
|
|
43
44
|
endRepository(input: Pick<RestoreSessionRepositoryEntity, "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.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();
|
|
@@ -35,6 +39,9 @@ class RestoreSessionManager {
|
|
|
35
39
|
}
|
|
36
40
|
async alter(data) {
|
|
37
41
|
const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
|
|
42
|
+
if (data.action === SessionDriverAbstract_1.ActionEnum.Progress &&
|
|
43
|
+
!this.checkProgress(data.data.progressStepDescription))
|
|
44
|
+
return data.data.id;
|
|
38
45
|
for (const driver of drivers) {
|
|
39
46
|
await driver.onWrite(data);
|
|
40
47
|
}
|
|
@@ -154,7 +161,13 @@ class RestoreSessionManager {
|
|
|
154
161
|
sessionData: this.sessionVault.get(object.sessionId),
|
|
155
162
|
data: {
|
|
156
163
|
...object,
|
|
157
|
-
|
|
164
|
+
id: input.id,
|
|
165
|
+
progressCurrent: input.stats?.current,
|
|
166
|
+
progressTotal: input.stats?.total,
|
|
167
|
+
progressPercent: input.stats?.percent,
|
|
168
|
+
progressStepDescription: input.step?.description,
|
|
169
|
+
progressStepItem: input.step?.item,
|
|
170
|
+
progressStepPercent: input.step?.percent,
|
|
158
171
|
updatingDate: new Date().toISOString(),
|
|
159
172
|
},
|
|
160
173
|
});
|
|
@@ -182,7 +195,13 @@ class RestoreSessionManager {
|
|
|
182
195
|
sessionData: this.sessionVault.get(object.sessionId),
|
|
183
196
|
data: {
|
|
184
197
|
...object,
|
|
185
|
-
|
|
198
|
+
id: input.id,
|
|
199
|
+
progressCurrent: input.stats?.current,
|
|
200
|
+
progressTotal: input.stats?.total,
|
|
201
|
+
progressPercent: input.stats?.percent,
|
|
202
|
+
progressStepDescription: input.step?.description,
|
|
203
|
+
progressStepItem: input.step?.item,
|
|
204
|
+
progressStepPercent: input.step?.percent,
|
|
186
205
|
updatingDate: new Date().toISOString(),
|
|
187
206
|
},
|
|
188
207
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SessionDriverAbstract } from "../SessionDriver/SessionDriverAbstract";
|
|
2
|
+
export declare type OptionsType = {
|
|
3
|
+
driver: SessionDriverAbstract;
|
|
4
|
+
altDrivers?: SessionDriverAbstract[];
|
|
5
|
+
progressInterval?: number;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export default abstract class SessionManagerAbstract {
|
|
9
|
+
readonly options: OptionsType;
|
|
10
|
+
protected lastProgressDate: number | undefined;
|
|
11
|
+
protected lastProgressStepDescription: string | null | undefined;
|
|
12
|
+
constructor(options: OptionsType);
|
|
13
|
+
protected checkProgress(description: string | null | undefined): boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class SessionManagerAbstract {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
checkProgress(description) {
|
|
8
|
+
const progressInterval = this.options.progressInterval;
|
|
9
|
+
if (progressInterval) {
|
|
10
|
+
const skip = this.lastProgressDate &&
|
|
11
|
+
description === this.lastProgressStepDescription &&
|
|
12
|
+
Date.now() - this.lastProgressDate < progressInterval;
|
|
13
|
+
if (skip)
|
|
14
|
+
return false;
|
|
15
|
+
this.lastProgressDate = Date.now();
|
|
16
|
+
this.lastProgressStepDescription = description;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
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
|
-
step:
|
|
76
|
+
step: {
|
|
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,
|
|
@@ -169,14 +171,20 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
|
|
|
169
171
|
basePath: path,
|
|
170
172
|
},
|
|
171
173
|
targetPath: outPath,
|
|
174
|
+
skipNotFoundError: true,
|
|
172
175
|
concurrency: this.config.fileCopyConcurrency,
|
|
173
176
|
onPath: async ({ entryPath }) => {
|
|
174
177
|
currentFiles++;
|
|
175
178
|
await data.onProgress({
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
step: {
|
|
180
|
+
description: "Copying file",
|
|
181
|
+
item: entryPath,
|
|
182
|
+
},
|
|
183
|
+
stats: {
|
|
184
|
+
total,
|
|
185
|
+
current: currentFiles,
|
|
186
|
+
percent: (0, math_util_1.progressPercent)(total, currentFiles),
|
|
187
|
+
},
|
|
180
188
|
});
|
|
181
189
|
},
|
|
182
190
|
});
|
|
@@ -200,14 +208,17 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
|
|
|
200
208
|
let totalFiles = 0;
|
|
201
209
|
let currentFiles = 0;
|
|
202
210
|
await (0, fs_util_1.forEachFile)(targetPath, () => totalFiles++, true);
|
|
203
|
-
const incrementProgress = async (
|
|
211
|
+
const incrementProgress = async (description, item, count = true) => {
|
|
204
212
|
await data.onProgress({
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
213
|
+
stats: {
|
|
214
|
+
total: totalFiles,
|
|
215
|
+
current: Math.max(currentFiles, 0),
|
|
216
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
|
|
217
|
+
},
|
|
218
|
+
step: { description, item },
|
|
209
219
|
});
|
|
210
|
-
|
|
220
|
+
if (count)
|
|
221
|
+
currentFiles++;
|
|
211
222
|
};
|
|
212
223
|
// Bundle
|
|
213
224
|
const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
|
|
@@ -236,9 +247,7 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
|
|
|
236
247
|
},
|
|
237
248
|
targetPath: restorePath,
|
|
238
249
|
concurrency: this.config.fileCopyConcurrency,
|
|
239
|
-
|
|
240
|
-
await incrementProgress(entryPath);
|
|
241
|
-
},
|
|
250
|
+
onProgress: async (progress) => await incrementProgress(progress.type === "end" ? "Files copied" : "Copying file", progress.path, !progress.type),
|
|
242
251
|
});
|
|
243
252
|
}
|
|
244
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
|
+
step: {
|
|
112
|
+
description: "Copying file",
|
|
113
|
+
item: path,
|
|
114
|
+
},
|
|
115
|
+
stats: {
|
|
116
|
+
current,
|
|
117
|
+
percent: (0, math_util_1.progressPercent)(total, current),
|
|
118
|
+
total,
|
|
119
|
+
},
|
|
115
120
|
});
|
|
116
121
|
}
|
|
117
122
|
};
|
|
@@ -15,6 +15,7 @@ const path_1 = require("path");
|
|
|
15
15
|
exports.sqlDumpTaskDefinition = {
|
|
16
16
|
type: "object",
|
|
17
17
|
required: ["password", "hostname", "username", "database"],
|
|
18
|
+
additionalProperties: false,
|
|
18
19
|
properties: {
|
|
19
20
|
password: {
|
|
20
21
|
anyOf: [
|
|
@@ -117,24 +118,39 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
|
117
118
|
await (0, promises_1.mkdir)(outputPath, { recursive: true });
|
|
118
119
|
if (!this.config.oneFileByTable) {
|
|
119
120
|
const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ database: this.config.database }));
|
|
121
|
+
data.onProgress({
|
|
122
|
+
step: {
|
|
123
|
+
description: "Exporting",
|
|
124
|
+
},
|
|
125
|
+
});
|
|
120
126
|
await this.onExportTables(tableNames, outPath);
|
|
121
127
|
}
|
|
122
128
|
else {
|
|
123
129
|
let current = 0;
|
|
124
130
|
for (const tableName of tableNames) {
|
|
125
131
|
data.onProgress({
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
step: {
|
|
133
|
+
description: "Exporting",
|
|
134
|
+
item: tableName,
|
|
135
|
+
},
|
|
136
|
+
stats: {
|
|
137
|
+
total: tableNames.length,
|
|
138
|
+
current: current,
|
|
139
|
+
percent: (0, math_util_1.progressPercent)(tableNames.length, current),
|
|
140
|
+
},
|
|
130
141
|
});
|
|
131
|
-
current++;
|
|
132
142
|
const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ table: tableName }));
|
|
133
143
|
await this.onExportTables([tableName], outPath);
|
|
144
|
+
current++;
|
|
134
145
|
}
|
|
135
146
|
}
|
|
136
147
|
if (this.config.storedPrograms) {
|
|
137
148
|
const outPath = (0, path_1.join)(outputPath, "stored-programs.sql");
|
|
149
|
+
data.onProgress({
|
|
150
|
+
step: {
|
|
151
|
+
description: "Exporting storaged programs",
|
|
152
|
+
},
|
|
153
|
+
});
|
|
138
154
|
await this.onExportStoredPrograms(outPath);
|
|
139
155
|
}
|
|
140
156
|
}
|
|
@@ -183,13 +199,18 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
|
183
199
|
for (const item of items) {
|
|
184
200
|
const path = (0, path_1.join)(restorePath, item.fileName);
|
|
185
201
|
data.onProgress({
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
202
|
+
step: {
|
|
203
|
+
description: "Importing",
|
|
204
|
+
item: item.fileName,
|
|
205
|
+
},
|
|
206
|
+
stats: {
|
|
207
|
+
total: items.length,
|
|
208
|
+
current: current,
|
|
209
|
+
percent: (0, math_util_1.progressPercent)(items.length, current),
|
|
210
|
+
},
|
|
190
211
|
});
|
|
191
|
-
current++;
|
|
192
212
|
await this.onImport(path, database.name);
|
|
213
|
+
current++;
|
|
193
214
|
}
|
|
194
215
|
}
|
|
195
216
|
}
|
package/Task/TaskAbstract.d.ts
CHANGED
|
@@ -3,11 +3,16 @@ import { RestoreActionOptionsType } from "../Action/RestoreAction";
|
|
|
3
3
|
import { PackageConfigType } from "../Config/PackageConfig";
|
|
4
4
|
import { SnapshotType } from "../Repository/RepositoryAbstract";
|
|
5
5
|
export declare type ProgressDataType = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
stats?: {
|
|
7
|
+
total?: number;
|
|
8
|
+
current?: number;
|
|
9
|
+
percent?: number;
|
|
10
|
+
};
|
|
11
|
+
step?: {
|
|
12
|
+
description?: string;
|
|
13
|
+
item?: string;
|
|
14
|
+
percent?: number;
|
|
15
|
+
};
|
|
11
16
|
};
|
|
12
17
|
export declare type BackupDataType = {
|
|
13
18
|
onProgress: (data: ProgressDataType) => Promise<void>;
|
package/cli.js
CHANGED
|
@@ -81,7 +81,7 @@ program.usage("dtt");
|
|
|
81
81
|
program.option("-v,--verbose", "Verbose", (_, previous) => previous + 1, 0);
|
|
82
82
|
program.option("-c,--config <path>", "Config path", process.env["DATATRUCK_CONFIG"] ?? (cwd.endsWith(path_1.sep) ? cwd : `${cwd}${path_1.sep}`));
|
|
83
83
|
program.option("--progress <value>", "Progress type (auto, plain, tty)", "auto");
|
|
84
|
-
program.option("--progress-interval <ms>", "Progress interval");
|
|
84
|
+
program.option("--progress-interval <ms>", "Progress interval", Number, 1000);
|
|
85
85
|
program.option("-o,--output-format <format>", "Output format (json, pjson, yaml, table, custom=$, tpl=name)", "table");
|
|
86
86
|
makeCommand(CommandFactory_1.CommandEnum.config).alias("c");
|
|
87
87
|
makeCommand(CommandFactory_1.CommandEnum.init).alias("i");
|
package/config.schema.json
CHANGED
|
@@ -475,6 +475,9 @@
|
|
|
475
475
|
"include"
|
|
476
476
|
],
|
|
477
477
|
"properties": {
|
|
478
|
+
"name": {
|
|
479
|
+
"type": "string"
|
|
480
|
+
},
|
|
478
481
|
"include": {
|
|
479
482
|
"$ref": "#/definitions/stringlist-util"
|
|
480
483
|
},
|
|
@@ -683,6 +686,7 @@
|
|
|
683
686
|
"username",
|
|
684
687
|
"database"
|
|
685
688
|
],
|
|
689
|
+
"additionalProperties": false,
|
|
686
690
|
"properties": {
|
|
687
691
|
"password": {
|
|
688
692
|
"anyOf": [
|