@datatruck/cli 0.14.0 → 0.16.1
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.d.ts +10 -3
- package/Action/BackupAction.js +41 -49
- package/Action/RestoreAction.d.ts +2 -2
- package/Action/RestoreAction.js +8 -16
- 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 +1 -0
- package/Repository/DatatruckRepository.js +162 -158
- 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/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 +10 -1
- package/util/fs-util.js +10 -1
- package/util/process-util.d.ts +3 -0
- package/util/process-util.js +11 -0
- package/util/progress.d.ts +12 -0
- package/util/progress.js +2 -0
- package/util/zip-util.d.ts +23 -5
- package/util/zip-util.js +82 -25
|
@@ -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
|
}
|
package/Task/MysqlDumpTask.js
CHANGED
|
@@ -70,7 +70,7 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
70
70
|
table_name
|
|
71
71
|
`);
|
|
72
72
|
}
|
|
73
|
-
async onExportTables(tableNames, output) {
|
|
73
|
+
async onExportTables(tableNames, output, onProgress) {
|
|
74
74
|
const stream = (0, fs_1.createWriteStream)(output);
|
|
75
75
|
await Promise.all([
|
|
76
76
|
new Promise((resolve, reject) => {
|
|
@@ -83,7 +83,10 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
83
83
|
"--skip-add-drop-table=false",
|
|
84
84
|
...tableNames,
|
|
85
85
|
], null, {
|
|
86
|
-
pipe: {
|
|
86
|
+
pipe: {
|
|
87
|
+
stream,
|
|
88
|
+
onWriteProgress: onProgress,
|
|
89
|
+
},
|
|
87
90
|
log: {
|
|
88
91
|
exec: this.verbose,
|
|
89
92
|
stderr: this.verbose,
|
|
@@ -9,7 +9,9 @@ export declare class PostgresqlDumpTask extends SqlDumpTaskAbstract<PostgresqlDu
|
|
|
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(): Promise<void>;
|
|
14
16
|
onImport(path: string, database: string): Promise<void>;
|
|
15
17
|
}
|
|
@@ -73,7 +73,7 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
73
73
|
CONCAT(table_schema, '.', table_name)
|
|
74
74
|
`);
|
|
75
75
|
}
|
|
76
|
-
async onExportTables(tableNames, output) {
|
|
76
|
+
async onExportTables(tableNames, output, onProgress) {
|
|
77
77
|
const stream = (0, fs_1.createWriteStream)(output);
|
|
78
78
|
await Promise.all([
|
|
79
79
|
new Promise((resolve, reject) => {
|
|
@@ -84,7 +84,7 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
84
84
|
...(await this.buildConnectionArgs()),
|
|
85
85
|
...(tableNames?.flatMap((v) => ["-t", v]) ?? []),
|
|
86
86
|
], null, {
|
|
87
|
-
pipe: { stream:
|
|
87
|
+
pipe: { stream, onWriteProgress: onProgress },
|
|
88
88
|
stderr: {
|
|
89
89
|
toExitCode: true,
|
|
90
90
|
},
|
|
@@ -29,7 +29,9 @@ export declare abstract class SqlDumpTaskAbstract<TConfig extends SqlDumpTaskCon
|
|
|
29
29
|
abstract onDatabaseIsEmpty(databaseName: string): Promise<boolean>;
|
|
30
30
|
abstract onFetchTableNames(database: string): Promise<string[]>;
|
|
31
31
|
abstract onExecQuery(query: string): ReturnType<typeof exec>;
|
|
32
|
-
abstract onExportTables(tableNames: string[], output: string
|
|
32
|
+
abstract onExportTables(tableNames: string[], output: string, onProgress: (data: {
|
|
33
|
+
totalBytes: number;
|
|
34
|
+
}) => void): Promise<void>;
|
|
33
35
|
abstract onExportStoredPrograms(output: string): Promise<void>;
|
|
34
36
|
abstract onImport(path: string, database: string): Promise<void>;
|
|
35
37
|
onBackup(data: BackupDataType): Promise<void>;
|
|
@@ -118,24 +118,61 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
|
118
118
|
await (0, promises_1.mkdir)(outputPath, { recursive: true });
|
|
119
119
|
if (!this.config.oneFileByTable) {
|
|
120
120
|
const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ database: this.config.database }));
|
|
121
|
-
|
|
121
|
+
data.onProgress({
|
|
122
|
+
relative: {
|
|
123
|
+
description: "Exporting",
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
await this.onExportTables(tableNames, outPath, async (progress) => {
|
|
127
|
+
await data.onProgress({
|
|
128
|
+
absolute: {
|
|
129
|
+
description: "Exporting in single file",
|
|
130
|
+
current: progress.totalBytes,
|
|
131
|
+
format: "size",
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
});
|
|
122
135
|
}
|
|
123
136
|
else {
|
|
124
137
|
let current = 0;
|
|
125
138
|
for (const tableName of tableNames) {
|
|
126
|
-
data.onProgress({
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
await data.onProgress({
|
|
140
|
+
relative: {
|
|
141
|
+
description: "Exporting",
|
|
142
|
+
payload: tableName,
|
|
143
|
+
},
|
|
144
|
+
absolute: {
|
|
145
|
+
total: tableNames.length,
|
|
146
|
+
current: current,
|
|
147
|
+
percent: (0, math_util_1.progressPercent)(tableNames.length, current),
|
|
148
|
+
},
|
|
131
149
|
});
|
|
132
|
-
current++;
|
|
133
150
|
const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ table: tableName }));
|
|
134
|
-
await this.onExportTables([tableName], outPath)
|
|
151
|
+
await this.onExportTables([tableName], outPath, async (progress) => {
|
|
152
|
+
await data.onProgress({
|
|
153
|
+
relative: {
|
|
154
|
+
description: "Exporting",
|
|
155
|
+
payload: tableName,
|
|
156
|
+
current: progress.totalBytes,
|
|
157
|
+
format: "size",
|
|
158
|
+
},
|
|
159
|
+
absolute: {
|
|
160
|
+
total: tableNames.length,
|
|
161
|
+
current: current,
|
|
162
|
+
percent: (0, math_util_1.progressPercent)(tableNames.length, current),
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
current++;
|
|
135
167
|
}
|
|
136
168
|
}
|
|
137
169
|
if (this.config.storedPrograms) {
|
|
138
170
|
const outPath = (0, path_1.join)(outputPath, "stored-programs.sql");
|
|
171
|
+
data.onProgress({
|
|
172
|
+
relative: {
|
|
173
|
+
description: "Exporting storaged programs",
|
|
174
|
+
},
|
|
175
|
+
});
|
|
139
176
|
await this.onExportStoredPrograms(outPath);
|
|
140
177
|
}
|
|
141
178
|
}
|
|
@@ -184,13 +221,18 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
|
184
221
|
for (const item of items) {
|
|
185
222
|
const path = (0, path_1.join)(restorePath, item.fileName);
|
|
186
223
|
data.onProgress({
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
224
|
+
relative: {
|
|
225
|
+
description: "Importing",
|
|
226
|
+
payload: item.fileName,
|
|
227
|
+
},
|
|
228
|
+
absolute: {
|
|
229
|
+
total: items.length,
|
|
230
|
+
current: current,
|
|
231
|
+
percent: (0, math_util_1.progressPercent)(items.length, current),
|
|
232
|
+
},
|
|
191
233
|
});
|
|
192
|
-
current++;
|
|
193
234
|
await this.onImport(path, database.name);
|
|
235
|
+
current++;
|
|
194
236
|
}
|
|
195
237
|
}
|
|
196
238
|
}
|
package/Task/TaskAbstract.d.ts
CHANGED
|
@@ -2,22 +2,16 @@ import { BackupActionOptionsType } from "../Action/BackupAction";
|
|
|
2
2
|
import { RestoreActionOptionsType } from "../Action/RestoreAction";
|
|
3
3
|
import { PackageConfigType } from "../Config/PackageConfig";
|
|
4
4
|
import { SnapshotType } from "../Repository/RepositoryAbstract";
|
|
5
|
-
|
|
6
|
-
total?: number;
|
|
7
|
-
current?: number;
|
|
8
|
-
percent?: number;
|
|
9
|
-
step?: string;
|
|
10
|
-
stepPercent?: number;
|
|
11
|
-
};
|
|
5
|
+
import { Progress } from "../util/progress";
|
|
12
6
|
export declare type BackupDataType = {
|
|
13
|
-
onProgress: (data:
|
|
7
|
+
onProgress: (data: Progress) => Promise<void>;
|
|
14
8
|
options: BackupActionOptionsType;
|
|
15
9
|
package: PackageConfigType;
|
|
16
10
|
targetPath: string | undefined;
|
|
17
11
|
snapshot: SnapshotType;
|
|
18
12
|
};
|
|
19
13
|
export declare type RestoreDataType = {
|
|
20
|
-
onProgress: (data:
|
|
14
|
+
onProgress: (data: Progress) => Promise<void>;
|
|
21
15
|
options: RestoreActionOptionsType;
|
|
22
16
|
package: PackageConfigType;
|
|
23
17
|
targetPath: string | undefined;
|