@datatruck/cli 0.21.0 → 0.22.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.d.ts +2 -3
- package/Action/BackupAction.js +16 -20
- package/Action/RestoreAction.d.ts +3 -1
- package/Action/RestoreAction.js +5 -5
- package/Command/BackupCommand.d.ts +1 -1
- package/Command/BackupCommand.js +1 -1
- package/Command/RestoreCommand.d.ts +1 -1
- package/Command/RestoreCommand.js +1 -1
- package/Error/AppError.d.ts +1 -0
- package/Error/AppError.js +8 -0
- package/JsonSchema/JsonSchema.js +1 -1
- package/Repository/DatatruckRepository.d.ts +3 -0
- package/Repository/DatatruckRepository.js +30 -12
- package/Task/MysqlDumpTask.d.ts +13 -15
- package/Task/MysqlDumpTask.js +207 -149
- package/Task/PostgresqlDumpTask.js +1 -1
- package/Task/SqlDumpTaskAbstract.d.ts +5 -2
- package/Task/SqlDumpTaskAbstract.js +4 -2
- package/config.schema.json +78 -4
- package/package.json +1 -1
- package/utils/cli.js +3 -1
- package/utils/datatruck/config.d.ts +1 -1
- package/utils/fs.d.ts +4 -1
- package/utils/fs.js +21 -6
- package/utils/mysql.d.ts +39 -0
- package/utils/mysql.js +211 -0
- package/utils/string.d.ts +5 -1
- package/utils/string.js +28 -6
- package/utils/tar.js +38 -33
package/Action/BackupAction.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ConfigType } from "../Config/Config";
|
|
2
2
|
import { PackageConfigType } from "../Config/PackageConfig";
|
|
3
3
|
import { RepositoryConfigType } from "../Config/RepositoryConfig";
|
|
4
|
-
import { AppError } from "../Error/AppError";
|
|
5
4
|
import { SnapshotType } from "../Repository/RepositoryAbstract";
|
|
6
5
|
import { BackupSessionManager } from "../SessionManager/BackupSessionManager";
|
|
7
6
|
import { TaskAbstract } from "../Task/TaskAbstract";
|
|
@@ -35,7 +34,7 @@ export declare class BackupAction<TRequired extends boolean = true> {
|
|
|
35
34
|
error: boolean;
|
|
36
35
|
tmpDirs: string[];
|
|
37
36
|
}>;
|
|
38
|
-
protected getError(pkg: PackageConfigType):
|
|
37
|
+
protected getError(pkg: PackageConfigType): Error | undefined;
|
|
39
38
|
protected splitRepositories(repositoryNames: string[]): {
|
|
40
39
|
repoNames: string[];
|
|
41
40
|
mirrors: {
|
|
@@ -45,6 +44,6 @@ export declare class BackupAction<TRequired extends boolean = true> {
|
|
|
45
44
|
};
|
|
46
45
|
exec(session: BackupSessionManager): Promise<{
|
|
47
46
|
total: number;
|
|
48
|
-
errors:
|
|
47
|
+
errors: Error[];
|
|
49
48
|
}>;
|
|
50
49
|
}
|
package/Action/BackupAction.js
CHANGED
|
@@ -67,7 +67,7 @@ class BackupAction {
|
|
|
67
67
|
const key = `${pkg.name}`;
|
|
68
68
|
let error;
|
|
69
69
|
if (this.taskErrors[key]?.length) {
|
|
70
|
-
error =
|
|
70
|
+
error = AppError_1.AppError.create("Previous task failed", this.taskErrors[key]);
|
|
71
71
|
}
|
|
72
72
|
else {
|
|
73
73
|
try {
|
|
@@ -110,7 +110,7 @@ class BackupAction {
|
|
|
110
110
|
let error;
|
|
111
111
|
let repoInstance;
|
|
112
112
|
if (this.taskErrors[pkg.name]?.length) {
|
|
113
|
-
error =
|
|
113
|
+
error = AppError_1.AppError.create("Task failed", this.taskErrors[pkg.name]);
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
116
116
|
try {
|
|
@@ -156,7 +156,7 @@ class BackupAction {
|
|
|
156
156
|
let error;
|
|
157
157
|
let repoInstance;
|
|
158
158
|
if (this.taskErrors[pkg.name]?.length) {
|
|
159
|
-
error =
|
|
159
|
+
error = AppError_1.AppError.create("Task failed", this.taskErrors[pkg.name]);
|
|
160
160
|
}
|
|
161
161
|
else {
|
|
162
162
|
try {
|
|
@@ -190,20 +190,16 @@ class BackupAction {
|
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
192
|
getError(pkg) {
|
|
193
|
-
const taskErrors = this.taskErrors[pkg.name]
|
|
194
|
-
const repoErrors = this.repoErrors[pkg.name]
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
return null;
|
|
206
|
-
}
|
|
193
|
+
const taskErrors = this.taskErrors[pkg.name] || [];
|
|
194
|
+
const repoErrors = this.repoErrors[pkg.name] || [];
|
|
195
|
+
const errors = [...taskErrors, ...repoErrors];
|
|
196
|
+
if (!errors.length)
|
|
197
|
+
return;
|
|
198
|
+
return AppError_1.AppError.create(taskErrors.length && repoErrors.length
|
|
199
|
+
? "Task and repository failed"
|
|
200
|
+
: taskErrors.length && !repoErrors.length
|
|
201
|
+
? "Task failed"
|
|
202
|
+
: "Repository failed", errors);
|
|
207
203
|
}
|
|
208
204
|
splitRepositories(repositoryNames) {
|
|
209
205
|
const mirrorRepoMap = {};
|
|
@@ -230,7 +226,7 @@ class BackupAction {
|
|
|
230
226
|
}
|
|
231
227
|
async exec(session) {
|
|
232
228
|
const [snapshot, packages] = await this.init(session);
|
|
233
|
-
|
|
229
|
+
const errors = [];
|
|
234
230
|
for (const pkg of packages) {
|
|
235
231
|
const id = session.findId({
|
|
236
232
|
packageName: pkg.name,
|
|
@@ -272,7 +268,7 @@ class BackupAction {
|
|
|
272
268
|
}
|
|
273
269
|
const error = this.getError(pkg);
|
|
274
270
|
if (error)
|
|
275
|
-
errors
|
|
271
|
+
errors.push(error);
|
|
276
272
|
await session.end({
|
|
277
273
|
id: id,
|
|
278
274
|
error: error?.message,
|
|
@@ -283,7 +279,7 @@ class BackupAction {
|
|
|
283
279
|
});
|
|
284
280
|
return {
|
|
285
281
|
total: packages.length,
|
|
286
|
-
errors
|
|
282
|
+
errors,
|
|
287
283
|
};
|
|
288
284
|
}
|
|
289
285
|
}
|
|
@@ -39,6 +39,8 @@ export declare class RestoreAction<TRequired extends boolean = true> {
|
|
|
39
39
|
tmpDirs: string[];
|
|
40
40
|
}>;
|
|
41
41
|
protected getError(pkg: PackageConfigType): AppError | null;
|
|
42
|
-
exec(session: RestoreSessionManager): Promise<
|
|
42
|
+
exec(session: RestoreSessionManager): Promise<{
|
|
43
|
+
errors: Error[];
|
|
44
|
+
}>;
|
|
43
45
|
}
|
|
44
46
|
export {};
|
package/Action/RestoreAction.js
CHANGED
|
@@ -100,10 +100,10 @@ class RestoreAction {
|
|
|
100
100
|
});
|
|
101
101
|
let error;
|
|
102
102
|
if (this.repoErrors[pkg.name]?.length) {
|
|
103
|
-
error =
|
|
103
|
+
error = AppError_1.AppError.create("Repository failed", this.repoErrors[pkg.name]);
|
|
104
104
|
}
|
|
105
105
|
else if (this.taskErrors[pkg.name]?.length) {
|
|
106
|
-
error =
|
|
106
|
+
error = AppError_1.AppError.create("Previous task failed", this.taskErrors[pkg.name]);
|
|
107
107
|
}
|
|
108
108
|
else {
|
|
109
109
|
try {
|
|
@@ -222,7 +222,7 @@ class RestoreAction {
|
|
|
222
222
|
});
|
|
223
223
|
const snapshotAndConfigs = this.assocConfigs(packages, snapshots);
|
|
224
224
|
await this.init(session, this.options.snapshotId, snapshotAndConfigs);
|
|
225
|
-
|
|
225
|
+
const errors = [];
|
|
226
226
|
for (const [snapshot, pkg] of snapshotAndConfigs) {
|
|
227
227
|
(0, assert_1.ok)(pkg);
|
|
228
228
|
const repo = (0, config_1.findRepositoryOrFail)(this.config, snapshot.repositoryName);
|
|
@@ -257,10 +257,10 @@ class RestoreAction {
|
|
|
257
257
|
error: error?.message,
|
|
258
258
|
});
|
|
259
259
|
if (error)
|
|
260
|
-
|
|
260
|
+
errors.push(error);
|
|
261
261
|
}
|
|
262
262
|
await session.endDrivers();
|
|
263
|
-
return
|
|
263
|
+
return { errors };
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
exports.RestoreAction = RestoreAction;
|
|
@@ -12,5 +12,5 @@ export type BackupCommandOptionsType<TResolved = false> = {
|
|
|
12
12
|
};
|
|
13
13
|
export declare class BackupCommand extends CommandAbstract<BackupCommandOptionsType<false>, BackupCommandOptionsType<true>> {
|
|
14
14
|
onOptions(): import("../utils/cli").OptionsType<BackupCommandOptionsType<false>, BackupCommandOptionsType<true>>;
|
|
15
|
-
onExec(): Promise<
|
|
15
|
+
onExec(): Promise<1 | 0>;
|
|
16
16
|
}
|
package/Command/BackupCommand.js
CHANGED
|
@@ -74,7 +74,7 @@ class BackupCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
74
74
|
progressInterval: this.globalOptions.progressInterval,
|
|
75
75
|
});
|
|
76
76
|
const result = await backup.exec(sessionManager);
|
|
77
|
-
if (result.errors) {
|
|
77
|
+
if (result.errors.length) {
|
|
78
78
|
return 1;
|
|
79
79
|
}
|
|
80
80
|
else if (!result.total) {
|
|
@@ -12,5 +12,5 @@ export type RestoreCommandOptionsType<TResolved = false> = {
|
|
|
12
12
|
};
|
|
13
13
|
export declare class RestoreCommand extends CommandAbstract<RestoreCommandOptionsType<false>, RestoreCommandOptionsType<true>> {
|
|
14
14
|
onOptions(): import("../utils/cli").OptionsType<RestoreCommandOptionsType<false>, RestoreCommandOptionsType<true>>;
|
|
15
|
-
onExec(): Promise<
|
|
15
|
+
onExec(): Promise<1 | 0>;
|
|
16
16
|
}
|
|
@@ -74,7 +74,7 @@ class RestoreCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
74
74
|
progressInterval: this.globalOptions.progressInterval,
|
|
75
75
|
});
|
|
76
76
|
const result = await restore.exec(sessionManager);
|
|
77
|
-
return result ?
|
|
77
|
+
return result.errors.length ? 1 : 0;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
exports.RestoreCommand = RestoreCommand;
|
package/Error/AppError.d.ts
CHANGED
package/Error/AppError.js
CHANGED
|
@@ -6,5 +6,13 @@ class AppError extends Error {
|
|
|
6
6
|
super(message);
|
|
7
7
|
this.name = AppError.name;
|
|
8
8
|
}
|
|
9
|
+
static create(message, errors) {
|
|
10
|
+
if (errors.length === 1) {
|
|
11
|
+
return errors[0];
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return new AggregateError(errors, message);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
9
17
|
}
|
|
10
18
|
exports.AppError = AppError;
|
package/JsonSchema/JsonSchema.js
CHANGED
|
@@ -38,7 +38,7 @@ exports.definitions = {
|
|
|
38
38
|
[DefinitionEnum_1.DefinitionEnum.resticPackageRepository]: ResticRepository_1.resticPackageRepositoryDefinition,
|
|
39
39
|
[DefinitionEnum_1.DefinitionEnum.gitTask]: GitTask_1.gitTaskDefinition,
|
|
40
40
|
[DefinitionEnum_1.DefinitionEnum.scriptTask]: ScriptTask_1.scriptTaskDefinition,
|
|
41
|
-
[DefinitionEnum_1.DefinitionEnum.sqlDumpTask]: SqlDumpTaskAbstract_1.sqlDumpTaskDefinition,
|
|
41
|
+
[DefinitionEnum_1.DefinitionEnum.sqlDumpTask]: (0, SqlDumpTaskAbstract_1.sqlDumpTaskDefinition)(),
|
|
42
42
|
[DefinitionEnum_1.DefinitionEnum.mariadbTask]: MariadbTask_1.mariadbTaskDefinition,
|
|
43
43
|
[DefinitionEnum_1.DefinitionEnum.mssqlTask]: MssqlTask_1.mssqlTaskDefinition,
|
|
44
44
|
[DefinitionEnum_1.DefinitionEnum.mysqlDumpTask]: MysqlDumpTask_1.mysqlDumpTaskDefinition,
|
|
@@ -196,7 +196,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
196
196
|
if (entry.dirent.isDirectory() &&
|
|
197
197
|
!(await (0, fs_1.isEmptyDir)((0, path_1.join)(sourcePath, entry.path))))
|
|
198
198
|
return false;
|
|
199
|
-
let packIndex = configPacks.findIndex((pack) => (0, string_1.
|
|
199
|
+
let packIndex = configPacks.findIndex((pack) => (0, string_1.match)(entry.path, pack.include, pack.exclude));
|
|
200
200
|
if (packIndex === -1)
|
|
201
201
|
packIndex = defaultsPackIndex;
|
|
202
202
|
const pack = packs[packIndex];
|
|
@@ -213,22 +213,26 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
213
213
|
});
|
|
214
214
|
await stream.end();
|
|
215
215
|
let packIndex = 0;
|
|
216
|
+
const tarStats = {};
|
|
216
217
|
for (const pack of packs) {
|
|
217
218
|
const packBasename = [`pack`, packIndex.toString(), pack.name]
|
|
218
219
|
.filter((v) => typeof v === "string")
|
|
219
220
|
.map((v) => encodeURIComponent(v.toString().replace(/[\\/]/g, "-")))
|
|
220
|
-
.join("-");
|
|
221
|
-
const ext = pack.compress ? `.tar.gz` : `.tar`;
|
|
221
|
+
.join("-") + (pack.compress ? `.tar.gz` : `.tar`);
|
|
222
222
|
const includeList = stream.path(packIndex);
|
|
223
|
-
if (includeList)
|
|
223
|
+
if (includeList) {
|
|
224
|
+
tarStats[packBasename] = {
|
|
225
|
+
files: stream.lines(packIndex),
|
|
226
|
+
};
|
|
224
227
|
await (0, tar_1.createTar)({
|
|
225
228
|
compress: pack.compress,
|
|
226
229
|
verbose: data.options.verbose,
|
|
227
230
|
includeList,
|
|
228
231
|
path: sourcePath,
|
|
229
|
-
output: (0, path_1.join)(outPath, packBasename)
|
|
232
|
+
output: (0, path_1.join)(outPath, packBasename),
|
|
230
233
|
onEntry: async (data) => await scanner.progress(pack.compress ? "Compressing" : "Packing", data.path),
|
|
231
234
|
});
|
|
235
|
+
}
|
|
232
236
|
packIndex++;
|
|
233
237
|
}
|
|
234
238
|
await scanner.end();
|
|
@@ -243,6 +247,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
243
247
|
task: data.package.task?.name,
|
|
244
248
|
version: nodePkg.version,
|
|
245
249
|
size: await (0, fs_1.fastFolderSizeAsync)(outPath),
|
|
250
|
+
tarStats,
|
|
246
251
|
};
|
|
247
252
|
if (data.options.verbose)
|
|
248
253
|
(0, cli_1.logExec)(`Writing metadata into ${metaPath}`);
|
|
@@ -298,6 +303,8 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
298
303
|
packageName: data.package.name,
|
|
299
304
|
});
|
|
300
305
|
const sourcePath = (0, path_1.join)(this.config.outPath, snapshotName);
|
|
306
|
+
const metaPath = (0, path_1.join)(sourcePath, "meta.json");
|
|
307
|
+
const meta = await DatatruckRepository.parseMetaData(metaPath);
|
|
301
308
|
const scanner = await (0, fs_1.createFileScanner)({
|
|
302
309
|
onProgress: data.onProgress,
|
|
303
310
|
glob: {
|
|
@@ -306,26 +313,37 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
306
313
|
},
|
|
307
314
|
});
|
|
308
315
|
const tarFiles = [];
|
|
316
|
+
const tarStats = meta?.tarStats || {};
|
|
309
317
|
await scanner.start(async (entry) => {
|
|
310
318
|
const path = (0, path_1.join)(sourcePath, entry.name);
|
|
311
319
|
const isTar = entry.name.endsWith(".tar");
|
|
312
320
|
const isTarGz = entry.name.endsWith(".tar.gz");
|
|
313
321
|
if (isTar || isTarGz) {
|
|
314
322
|
tarFiles.push(path);
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
|
|
323
|
+
if (typeof tarStats[entry.name]?.files === "number") {
|
|
324
|
+
scanner.total += tarStats[entry.name].files;
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
scanner.progress("Scanning", entry.name, false);
|
|
328
|
+
const selfTarStats = (tarStats[entry.name] = { files: 0 });
|
|
329
|
+
await (0, tar_1.listTar)({
|
|
330
|
+
input: path,
|
|
331
|
+
verbose: data.options.verbose,
|
|
332
|
+
onEntry: () => {
|
|
333
|
+
scanner.total++;
|
|
334
|
+
selfTarStats.files++;
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
}
|
|
322
338
|
}
|
|
323
339
|
return false;
|
|
324
340
|
});
|
|
325
341
|
if (data.options.verbose)
|
|
326
342
|
(0, cli_1.logExec)(`Unpacking files to ${restorePath}`);
|
|
327
343
|
for (const tarFile of tarFiles) {
|
|
344
|
+
const entryName = (0, path_1.basename)(tarFile);
|
|
328
345
|
await (0, tar_1.extractTar)({
|
|
346
|
+
total: tarStats[entryName].files,
|
|
329
347
|
input: tarFile,
|
|
330
348
|
output: restorePath,
|
|
331
349
|
decompress: tarFile.endsWith(".tar.gz"),
|
package/Task/MysqlDumpTask.d.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { SqlDumpTaskConfigType } from "./SqlDumpTaskAbstract";
|
|
2
|
+
import { BackupDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
|
|
3
3
|
export declare const mysqlDumpTaskName = "mysql-dump";
|
|
4
|
-
export type MysqlDumpTaskConfigType = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
onExportStoredPrograms(output: string): Promise<void>;
|
|
16
|
-
onImport(path: string, database: string): Promise<void>;
|
|
4
|
+
export type MysqlDumpTaskConfigType = {
|
|
5
|
+
/**
|
|
6
|
+
* @default "sql"
|
|
7
|
+
*/
|
|
8
|
+
dataFormat?: "csv" | "sql";
|
|
9
|
+
csvSharedPath?: string;
|
|
10
|
+
} & SqlDumpTaskConfigType;
|
|
11
|
+
export declare const mysqlDumpTaskDefinition: import("json-schema").JSONSchema7;
|
|
12
|
+
export declare class MysqlDumpTask extends TaskAbstract<MysqlDumpTaskConfigType> {
|
|
13
|
+
onBackup(data: BackupDataType): Promise<void>;
|
|
14
|
+
onRestore(data: RestoreDataType): Promise<void>;
|
|
17
15
|
}
|