@datatruck/cli 0.34.5 → 0.35.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/config.schema.json +57 -0
- package/lib/actions/InitAction.js +5 -4
- package/lib/actions/RestoreAction.js +5 -4
- package/lib/actions/SnapshotsAction.js +5 -4
- package/lib/repositories/DatatruckRepository.js +22 -18
- package/lib/repositories/GitRepository.js +5 -6
- package/lib/repositories/ResticRepository.js +5 -5
- package/lib/tasks/MongoDumpTask.d.ts +21 -0
- package/lib/tasks/MongoDumpTask.js +48 -0
- package/lib/tasks/MssqlTask.js +5 -5
- package/lib/tasks/PostgresqlDumpTask.js +14 -2
- package/lib/tasks/SqlDumpTaskAbstract.js +5 -8
- package/lib/utils/async.d.ts +1 -1
- package/lib/utils/async.js +2 -2
- package/lib/utils/datatruck/config-task-type.d.ts +6 -1
- package/lib/utils/datatruck/config.d.ts +3 -0
- package/lib/utils/datatruck/config.js +29 -13
- package/lib/utils/datatruck/task.js +4 -0
- package/lib/utils/mysql.js +4 -3
- package/lib/utils/string.d.ts +10 -3
- package/lib/utils/string.js +26 -18
- package/package.json +1 -1
package/config.schema.json
CHANGED
|
@@ -399,6 +399,63 @@
|
|
|
399
399
|
"name"
|
|
400
400
|
]
|
|
401
401
|
},
|
|
402
|
+
{
|
|
403
|
+
"type": "object",
|
|
404
|
+
"properties": {
|
|
405
|
+
"name": {
|
|
406
|
+
"type": "string",
|
|
407
|
+
"const": "mongo-dump"
|
|
408
|
+
},
|
|
409
|
+
"config": {
|
|
410
|
+
"type": "object",
|
|
411
|
+
"properties": {
|
|
412
|
+
"command": {
|
|
413
|
+
"type": "string"
|
|
414
|
+
},
|
|
415
|
+
"hostname": {
|
|
416
|
+
"type": "string"
|
|
417
|
+
},
|
|
418
|
+
"port": {
|
|
419
|
+
"type": "number"
|
|
420
|
+
},
|
|
421
|
+
"username": {
|
|
422
|
+
"type": "string"
|
|
423
|
+
},
|
|
424
|
+
"password": {
|
|
425
|
+
"anyOf": [
|
|
426
|
+
{
|
|
427
|
+
"type": "object",
|
|
428
|
+
"properties": {
|
|
429
|
+
"path": {
|
|
430
|
+
"type": "string"
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
"additionalProperties": false,
|
|
434
|
+
"required": [
|
|
435
|
+
"path"
|
|
436
|
+
]
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
"type": "string"
|
|
440
|
+
}
|
|
441
|
+
]
|
|
442
|
+
},
|
|
443
|
+
"compress": {
|
|
444
|
+
"type": "boolean"
|
|
445
|
+
},
|
|
446
|
+
"concurrency": {
|
|
447
|
+
"type": "number"
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
"additionalProperties": false
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
"additionalProperties": false,
|
|
454
|
+
"required": [
|
|
455
|
+
"config",
|
|
456
|
+
"name"
|
|
457
|
+
]
|
|
458
|
+
},
|
|
402
459
|
{
|
|
403
460
|
"type": "object",
|
|
404
461
|
"properties": {
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.InitAction = void 0;
|
|
4
4
|
const config_1 = require("../utils/datatruck/config");
|
|
5
5
|
const repository_1 = require("../utils/datatruck/repository");
|
|
6
|
+
const string_1 = require("../utils/string");
|
|
6
7
|
class InitAction {
|
|
7
8
|
config;
|
|
8
9
|
options;
|
|
@@ -12,14 +13,14 @@ class InitAction {
|
|
|
12
13
|
}
|
|
13
14
|
async exec() {
|
|
14
15
|
const result = [];
|
|
16
|
+
const filterRepo = (0, string_1.createPatternFilter)(this.options.repositoryNames);
|
|
17
|
+
const filterRepoType = (0, string_1.createPatternFilter)(this.options.repositoryTypes);
|
|
15
18
|
for (const repoConfig of this.config.repositories) {
|
|
16
19
|
if (!(0, config_1.filterRepositoryByEnabled)(repoConfig, "init"))
|
|
17
20
|
continue;
|
|
18
|
-
if (
|
|
19
|
-
!this.options.repositoryNames.includes(repoConfig.name))
|
|
21
|
+
if (!filterRepo(repoConfig.name))
|
|
20
22
|
continue;
|
|
21
|
-
if (
|
|
22
|
-
!this.options.repositoryTypes.includes(repoConfig.type))
|
|
23
|
+
if (!filterRepoType(repoConfig.type))
|
|
23
24
|
continue;
|
|
24
25
|
const repo = (0, repository_1.createRepo)(repoConfig, this.options.verbose);
|
|
25
26
|
let initError = null;
|
|
@@ -59,6 +59,7 @@ const error_1 = require("../utils/error");
|
|
|
59
59
|
const fs_1 = require("../utils/fs");
|
|
60
60
|
const list_1 = require("../utils/list");
|
|
61
61
|
const progress_1 = require("../utils/progress");
|
|
62
|
+
const string_1 = require("../utils/string");
|
|
62
63
|
const temp_1 = require("../utils/temp");
|
|
63
64
|
const SnapshotsAction_1 = require("./SnapshotsAction");
|
|
64
65
|
const assert_1 = require("assert");
|
|
@@ -74,12 +75,12 @@ class RestoreAction {
|
|
|
74
75
|
}
|
|
75
76
|
async findSnapshots() {
|
|
76
77
|
const result = [];
|
|
78
|
+
const filterRepo = (0, string_1.createPatternFilter)(this.options.repositoryNames);
|
|
79
|
+
const filterRepoType = (0, string_1.createPatternFilter)(this.options.repositoryTypes);
|
|
77
80
|
for (const repository of this.config.repositories) {
|
|
78
|
-
if (
|
|
79
|
-
!this.options.repositoryNames.includes(repository.name))
|
|
81
|
+
if (!filterRepo(repository.name))
|
|
80
82
|
continue;
|
|
81
|
-
if (
|
|
82
|
-
!this.options.repositoryTypes.includes(repository.type))
|
|
83
|
+
if (!filterRepoType(repository.type))
|
|
83
84
|
continue;
|
|
84
85
|
const snapshotsAction = new SnapshotsAction_1.SnapshotsAction(this.config, {
|
|
85
86
|
repositoryNames: [repository.name],
|
|
@@ -4,6 +4,7 @@ exports.SnapshotsAction = void 0;
|
|
|
4
4
|
const config_1 = require("../utils/datatruck/config");
|
|
5
5
|
const repository_1 = require("../utils/datatruck/repository");
|
|
6
6
|
const snapshot_1 = require("../utils/datatruck/snapshot");
|
|
7
|
+
const string_1 = require("../utils/string");
|
|
7
8
|
class SnapshotsAction {
|
|
8
9
|
config;
|
|
9
10
|
options;
|
|
@@ -15,14 +16,14 @@ class SnapshotsAction {
|
|
|
15
16
|
if (!sourceAction)
|
|
16
17
|
sourceAction = "snapshots";
|
|
17
18
|
let result = [];
|
|
19
|
+
const filterRepo = (0, string_1.createPatternFilter)(this.options.repositoryNames);
|
|
20
|
+
const filterRepoType = (0, string_1.createPatternFilter)(this.options.repositoryTypes);
|
|
18
21
|
for (const repoConfig of this.config.repositories) {
|
|
19
22
|
if (!(0, config_1.filterRepositoryByEnabled)(repoConfig, sourceAction))
|
|
20
23
|
continue;
|
|
21
|
-
if (
|
|
22
|
-
!this.options.repositoryNames.includes(repoConfig.name))
|
|
24
|
+
if (!filterRepo(repoConfig.name))
|
|
23
25
|
continue;
|
|
24
|
-
if (
|
|
25
|
-
!this.options.repositoryTypes.includes(repoConfig.type))
|
|
26
|
+
if (!filterRepoType(repoConfig.type))
|
|
26
27
|
continue;
|
|
27
28
|
const repo = await (0, repository_1.createAndInitRepo)(repoConfig, this.options.verbose);
|
|
28
29
|
const configPackageNames = this.config.packages.map((pkg) => pkg.name);
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DatatruckRepository = exports.datatruckRepositoryName = void 0;
|
|
4
|
+
const async_1 = require("../utils/async");
|
|
4
5
|
const cli_1 = require("../utils/cli");
|
|
5
6
|
const crypto_1 = require("../utils/crypto");
|
|
6
7
|
const client_1 = require("../utils/datatruck/client");
|
|
8
|
+
const config_1 = require("../utils/datatruck/config");
|
|
7
9
|
const paths_1 = require("../utils/datatruck/paths");
|
|
8
10
|
const error_1 = require("../utils/error");
|
|
9
11
|
const fs_1 = require("../utils/fs");
|
|
@@ -14,7 +16,6 @@ const temp_1 = require("../utils/temp");
|
|
|
14
16
|
const RepositoryAbstract_1 = require("./RepositoryAbstract");
|
|
15
17
|
const assert_1 = require("assert");
|
|
16
18
|
const promises_1 = require("fs/promises");
|
|
17
|
-
const micromatch_1 = require("micromatch");
|
|
18
19
|
const path_1 = require("path");
|
|
19
20
|
exports.datatruckRepositoryName = "datatruck";
|
|
20
21
|
class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
@@ -68,23 +69,26 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
68
69
|
throw new error_1.AppError(`Repository (${this.repository.name}) out path does not exist: ${fs.resolvePath(".")}`);
|
|
69
70
|
const snapshots = [];
|
|
70
71
|
const snapshotNames = await fs.readdir(".");
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
const filterPkg = (0, config_1.createPkgFilter)(data.options.packageNames);
|
|
73
|
+
const filterTask = (0, config_1.createTaskFilter)(data.options.packageTaskNames);
|
|
74
|
+
const filterId = (shortId) => !data.options.ids ||
|
|
75
|
+
data.options.ids.some((id) => shortId.startsWith(id.slice(0, 8)));
|
|
76
|
+
const preSnapshots = snapshotNames
|
|
77
|
+
.filter((snapshotName) => {
|
|
78
|
+
const data = DatatruckRepository.parseSnapshotName(snapshotName);
|
|
79
|
+
return (data && filterPkg(data.packageName) && filterId(data.snapshotShortId));
|
|
80
|
+
})
|
|
81
|
+
.map((name) => ({ name }));
|
|
82
|
+
await (0, async_1.runParallel)({
|
|
83
|
+
items: preSnapshots,
|
|
84
|
+
concurrency: 5,
|
|
85
|
+
async onItem({ item }) {
|
|
86
|
+
item.metaData = await fs.readFileIfExists(`${item.name}/meta.json`);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
for (const { name, metaData } of preSnapshots) {
|
|
84
90
|
const meta = !!metaData && (await DatatruckRepository.parseMetaData(metaData));
|
|
85
|
-
if (!meta)
|
|
86
|
-
continue;
|
|
87
|
-
if (taskPatterns && !(0, string_1.checkMatch)(meta.task, taskPatterns))
|
|
91
|
+
if (!meta || !filterTask(meta.task))
|
|
88
92
|
continue;
|
|
89
93
|
if (data.options.ids &&
|
|
90
94
|
!data.options.ids.some((id) => meta.id.startsWith(id)))
|
|
@@ -93,7 +97,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
93
97
|
!data.options.tags.some((value) => data.options.tags?.includes(value)))
|
|
94
98
|
continue;
|
|
95
99
|
snapshots.push({
|
|
96
|
-
originalId:
|
|
100
|
+
originalId: name,
|
|
97
101
|
id: meta.id,
|
|
98
102
|
date: meta.date,
|
|
99
103
|
packageName: meta.package,
|
|
@@ -5,15 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.GitRepository = exports.gitRepositoryName = void 0;
|
|
7
7
|
const cli_1 = require("../utils/cli");
|
|
8
|
+
const config_1 = require("../utils/datatruck/config");
|
|
8
9
|
const paths_1 = require("../utils/datatruck/paths");
|
|
9
10
|
const fs_1 = require("../utils/fs");
|
|
10
11
|
const git_1 = require("../utils/git");
|
|
11
|
-
const string_1 = require("../utils/string");
|
|
12
12
|
const temp_1 = require("../utils/temp");
|
|
13
13
|
const RepositoryAbstract_1 = require("./RepositoryAbstract");
|
|
14
14
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
15
15
|
const promises_1 = require("fs/promises");
|
|
16
|
-
const micromatch_1 = require("micromatch");
|
|
17
16
|
const path_1 = require("path");
|
|
18
17
|
exports.gitRepositoryName = "git";
|
|
19
18
|
class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
@@ -104,11 +103,11 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
104
103
|
dir: await (0, temp_1.mkTmpDir)(exports.gitRepositoryName, "repo", "snapshots"),
|
|
105
104
|
log: data.options.verbose,
|
|
106
105
|
});
|
|
107
|
-
const pkgPatterns = (0, string_1.makePathPatterns)(data.options.packageNames);
|
|
108
|
-
const pkgTaskPatterns = (0, string_1.makePathPatterns)(data.options.packageTaskNames);
|
|
109
106
|
await git.clone({ repo: this.config.repo });
|
|
110
107
|
const tagNames = data.options.ids?.map((id) => `${GitRepository.refPrefix}/*/${id}*`) || [`${GitRepository.refPrefix}/*`];
|
|
111
108
|
const tags = await git.getTags(tagNames);
|
|
109
|
+
const filterPkg = (0, config_1.createPkgFilter)(data.options.packageNames);
|
|
110
|
+
const filterTask = (0, config_1.createTaskFilter)(data.options.packageTaskNames);
|
|
112
111
|
return tags
|
|
113
112
|
.reduce((result, tag) => {
|
|
114
113
|
const parsedTag = tag.message
|
|
@@ -116,9 +115,9 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
116
115
|
: null;
|
|
117
116
|
if (!parsedTag)
|
|
118
117
|
return result;
|
|
119
|
-
if (
|
|
118
|
+
if (!filterPkg(parsedTag.package))
|
|
120
119
|
return result;
|
|
121
|
-
if (
|
|
120
|
+
if (!filterTask(parsedTag.task))
|
|
122
121
|
return result;
|
|
123
122
|
if (data.options.tags &&
|
|
124
123
|
!parsedTag.tags.some((value) => data.options.tags?.includes(value)))
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ResticRepository = exports.resticRepositoryName = void 0;
|
|
7
7
|
const cli_1 = require("../utils/cli");
|
|
8
|
+
const config_1 = require("../utils/datatruck/config");
|
|
8
9
|
const paths_1 = require("../utils/datatruck/paths");
|
|
9
10
|
const error_1 = require("../utils/error");
|
|
10
11
|
const fs_1 = require("../utils/fs");
|
|
@@ -15,7 +16,6 @@ const temp_1 = require("../utils/temp");
|
|
|
15
16
|
const RepositoryAbstract_1 = require("./RepositoryAbstract");
|
|
16
17
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
17
18
|
const promises_1 = require("fs/promises");
|
|
18
|
-
const micromatch_1 = require("micromatch");
|
|
19
19
|
const path_1 = require("path");
|
|
20
20
|
exports.resticRepositoryName = "restic";
|
|
21
21
|
class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
@@ -83,21 +83,21 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
83
83
|
env: await this.buildEnv(),
|
|
84
84
|
log: data.options.verbose,
|
|
85
85
|
});
|
|
86
|
-
const packagePatterns = (0, string_1.makePathPatterns)(data.options.packageNames);
|
|
87
|
-
const taskNamePatterns = (0, string_1.makePathPatterns)(data.options.packageTaskNames);
|
|
88
86
|
const result = await restic.snapshots({
|
|
89
87
|
json: true,
|
|
90
88
|
tags: [
|
|
91
89
|
...(data.options.ids?.map((id) => ResticRepository.buildSnapshotTag(id.length === 8 ? RepositoryAbstract_1.SnapshotTagEnum.SHORT_ID : RepositoryAbstract_1.SnapshotTagEnum.ID, id)) ?? []),
|
|
92
90
|
],
|
|
93
91
|
});
|
|
92
|
+
const filterPkg = (0, config_1.createPkgFilter)(data.options.packageNames);
|
|
93
|
+
const filterTask = (0, config_1.createTaskFilter)(data.options.packageTaskNames);
|
|
94
94
|
return result.reduce((items, item) => {
|
|
95
95
|
const tag = ResticRepository.parseSnapshotTags(item.tags ?? []);
|
|
96
96
|
if (!tag.id)
|
|
97
97
|
return items;
|
|
98
|
-
if (
|
|
98
|
+
if (!filterPkg(tag.package))
|
|
99
99
|
return items;
|
|
100
|
-
if (
|
|
100
|
+
if (!filterTask(tag.task))
|
|
101
101
|
return items;
|
|
102
102
|
const itemTags = tag.tags ?? [];
|
|
103
103
|
if (data.options.tags && !itemTags.some((t) => itemTags.includes(t)))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TaskBackupData, TaskRestoreData, TaskAbstract } from "./TaskAbstract";
|
|
2
|
+
export type MongoDumpTaskConfig = {
|
|
3
|
+
command?: string;
|
|
4
|
+
hostname?: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
username?: string;
|
|
7
|
+
password?: string | {
|
|
8
|
+
path: string;
|
|
9
|
+
};
|
|
10
|
+
compress?: boolean;
|
|
11
|
+
concurrency?: number;
|
|
12
|
+
};
|
|
13
|
+
export declare const mongodumpTaskName = "mongo-dump";
|
|
14
|
+
export declare class MongoDumpTask extends TaskAbstract<MongoDumpTaskConfig> {
|
|
15
|
+
protected verbose?: boolean;
|
|
16
|
+
private get command();
|
|
17
|
+
backup(data: TaskBackupData): Promise<{
|
|
18
|
+
snapshotPath: string;
|
|
19
|
+
}>;
|
|
20
|
+
restore(data: TaskRestoreData): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MongoDumpTask = exports.mongodumpTaskName = void 0;
|
|
4
|
+
const async_process_1 = require("../utils/async-process");
|
|
5
|
+
const fs_1 = require("../utils/fs");
|
|
6
|
+
const temp_1 = require("../utils/temp");
|
|
7
|
+
const TaskAbstract_1 = require("./TaskAbstract");
|
|
8
|
+
exports.mongodumpTaskName = "mongo-dump";
|
|
9
|
+
class MongoDumpTask extends TaskAbstract_1.TaskAbstract {
|
|
10
|
+
verbose;
|
|
11
|
+
get command() {
|
|
12
|
+
return this.config.command ?? "mongodump";
|
|
13
|
+
}
|
|
14
|
+
async backup(data) {
|
|
15
|
+
this.verbose = data.options.verbose;
|
|
16
|
+
const snapshotPath = data.package.path ??
|
|
17
|
+
(await (0, temp_1.mkTmpDir)(exports.mongodumpTaskName, "task", "backup", "snapshot"));
|
|
18
|
+
await (0, fs_1.mkdirIfNotExists)(snapshotPath);
|
|
19
|
+
await (0, fs_1.ensureEmptyDir)(snapshotPath);
|
|
20
|
+
const p = new async_process_1.AsyncProcess(this.command, [
|
|
21
|
+
...(this.config.hostname ? ["/h", this.config.hostname] : []),
|
|
22
|
+
...(this.config.port ? ["/p", this.config.port] : []),
|
|
23
|
+
...(this.config.username ? ["/u", this.config.username] : []),
|
|
24
|
+
...(this.config.compress ? ["/gzip"] : []),
|
|
25
|
+
...(this.config.concurrency ? ["/j", this.config.concurrency] : []),
|
|
26
|
+
"/o",
|
|
27
|
+
snapshotPath,
|
|
28
|
+
], {
|
|
29
|
+
$log: this.verbose,
|
|
30
|
+
});
|
|
31
|
+
const password = this.config.password !== undefined
|
|
32
|
+
? (await (0, fs_1.fetchData)(this.config.password, (p) => p.path)) ?? ""
|
|
33
|
+
: "";
|
|
34
|
+
p.stdin.writable.write(`${password}\n`);
|
|
35
|
+
await p.stderr.parseLines((line) => {
|
|
36
|
+
data.onProgress({
|
|
37
|
+
absolute: {
|
|
38
|
+
description: line.slice(0, 255),
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
return { snapshotPath };
|
|
43
|
+
}
|
|
44
|
+
async restore(data) {
|
|
45
|
+
throw new Error("Not implemented");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.MongoDumpTask = MongoDumpTask;
|
package/lib/tasks/MssqlTask.js
CHANGED
|
@@ -5,10 +5,10 @@ const async_process_1 = require("../utils/async-process");
|
|
|
5
5
|
const config_1 = require("../utils/datatruck/config");
|
|
6
6
|
const error_1 = require("../utils/error");
|
|
7
7
|
const fs_1 = require("../utils/fs");
|
|
8
|
+
const string_1 = require("../utils/string");
|
|
8
9
|
const temp_1 = require("../utils/temp");
|
|
9
10
|
const TaskAbstract_1 = require("./TaskAbstract");
|
|
10
11
|
const promises_1 = require("fs/promises");
|
|
11
|
-
const micromatch_1 = require("micromatch");
|
|
12
12
|
const path_1 = require("path");
|
|
13
13
|
exports.mssqlTaskName = "mssql";
|
|
14
14
|
class MssqlTask extends TaskAbstract_1.TaskAbstract {
|
|
@@ -53,10 +53,10 @@ class MssqlTask extends TaskAbstract_1.TaskAbstract {
|
|
|
53
53
|
if (data.package.path)
|
|
54
54
|
throw new error_1.AppError(`'package.path' is required: ${data.package.path}`);
|
|
55
55
|
const snapshotPath = await (0, temp_1.mkTmpDir)(exports.mssqlTaskName, "task", "backup", "snapshot");
|
|
56
|
-
const databaseNames = (await this.fetchDatabaseNames()).filter((
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
const databaseNames = (await this.fetchDatabaseNames()).filter((0, string_1.createPatternFilter)({
|
|
57
|
+
include: this.config.includeDatabases,
|
|
58
|
+
exclude: this.config.excludeDatabases,
|
|
59
|
+
}));
|
|
60
60
|
for (const databaseName of databaseNames) {
|
|
61
61
|
const databasePath = (0, path_1.join)(snapshotPath, `${databaseName}${MssqlTask.SUFFIX}`);
|
|
62
62
|
await this.exec(`BACKUP DATABASE [${databaseName}] TO DISK='${databasePath}' WITH FORMAT`);
|
|
@@ -64,14 +64,26 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
64
64
|
const dumpProcess = new async_process_1.AsyncProcess("pg_dump", [
|
|
65
65
|
...(await this.buildConnectionArgs(this.config.database)),
|
|
66
66
|
...(tableNames?.flatMap((v) => ["-t", v]) ?? []),
|
|
67
|
-
], {
|
|
67
|
+
], {
|
|
68
|
+
$log: {
|
|
69
|
+
exec: this.verbose,
|
|
70
|
+
stderr: this.verbose,
|
|
71
|
+
allToStderr: true,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
68
74
|
await dumpProcess.stdout.pipe(output, onProgress);
|
|
69
75
|
}
|
|
70
76
|
async onExportStoredPrograms() {
|
|
71
77
|
throw new Error(`Method not implemented: onExportStoredPrograms`);
|
|
72
78
|
}
|
|
73
79
|
async onImport(path, database) {
|
|
74
|
-
await async_process_1.AsyncProcess.exec("psql", [...(await this.buildConnectionArgs(database)), "-f", (0, path_1.normalize)(path)], {
|
|
80
|
+
await async_process_1.AsyncProcess.exec("psql", [...(await this.buildConnectionArgs(database)), "-f", (0, path_1.normalize)(path)], {
|
|
81
|
+
$log: {
|
|
82
|
+
exec: this.verbose,
|
|
83
|
+
stderr: this.verbose,
|
|
84
|
+
allToStderr: true,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
75
87
|
}
|
|
76
88
|
}
|
|
77
89
|
exports.PostgresqlDumpTask = PostgresqlDumpTask;
|
|
@@ -6,11 +6,11 @@ const config_1 = require("../utils/datatruck/config");
|
|
|
6
6
|
const error_1 = require("../utils/error");
|
|
7
7
|
const fs_1 = require("../utils/fs");
|
|
8
8
|
const math_1 = require("../utils/math");
|
|
9
|
+
const string_1 = require("../utils/string");
|
|
9
10
|
const temp_1 = require("../utils/temp");
|
|
10
11
|
const TaskAbstract_1 = require("./TaskAbstract");
|
|
11
12
|
const assert_1 = require("assert");
|
|
12
13
|
const promises_1 = require("fs/promises");
|
|
13
|
-
const micromatch_1 = require("micromatch");
|
|
14
14
|
const path_1 = require("path");
|
|
15
15
|
function serializeSqlFile(input) {
|
|
16
16
|
if (input.database && input.table) {
|
|
@@ -71,13 +71,10 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
|
71
71
|
await (0, fs_1.ensureEmptyDir)(snapshotPath);
|
|
72
72
|
const config = this.config;
|
|
73
73
|
const allTableNames = await this.onFetchTableNames(this.config.database);
|
|
74
|
-
const tableNames = allTableNames.filter((
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return false;
|
|
79
|
-
return true;
|
|
80
|
-
});
|
|
74
|
+
const tableNames = allTableNames.filter((0, string_1.createPatternFilter)({
|
|
75
|
+
include: config.includeTables,
|
|
76
|
+
exclude: config.excludeTables,
|
|
77
|
+
}));
|
|
81
78
|
(0, assert_1.ok)(typeof snapshotPath === "string");
|
|
82
79
|
if (!(await (0, fs_1.existsDir)(snapshotPath)))
|
|
83
80
|
await (0, promises_1.mkdir)(snapshotPath, { recursive: true });
|
package/lib/utils/async.d.ts
CHANGED
package/lib/utils/async.js
CHANGED
|
@@ -12,7 +12,7 @@ async function runParallel(options) {
|
|
|
12
12
|
const controller = new AbortController();
|
|
13
13
|
buffer.set(item, controller);
|
|
14
14
|
try {
|
|
15
|
-
await options.onChange({
|
|
15
|
+
await options.onChange?.({
|
|
16
16
|
processed,
|
|
17
17
|
proccesing: buffer.size,
|
|
18
18
|
buffer,
|
|
@@ -37,7 +37,7 @@ async function runParallel(options) {
|
|
|
37
37
|
buffer.delete(item);
|
|
38
38
|
processed++;
|
|
39
39
|
await options.onFinished?.();
|
|
40
|
-
await options.onChange({
|
|
40
|
+
await options.onChange?.({
|
|
41
41
|
processed,
|
|
42
42
|
proccesing: buffer.size,
|
|
43
43
|
buffer,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GitTaskConfig, gitTaskName } from "../../tasks/GitTask";
|
|
2
2
|
import type { MariadbTaskConfig, mariadbTaskName } from "../../tasks/MariadbTask";
|
|
3
|
+
import { MongoDumpTaskConfig, mongodumpTaskName } from "../../tasks/MongoDumpTask";
|
|
3
4
|
import type { MssqlTaskConfig, mssqlTaskName } from "../../tasks/MssqlTask";
|
|
4
5
|
import type { MysqlDumpTaskConfig, mysqlDumpTaskName } from "../../tasks/MysqlDumpTask";
|
|
5
6
|
import type { PostgresqlDumpTaskConfig, postgresqlDumpTaskName } from "../../tasks/PostgresqlDumpTask";
|
|
@@ -24,8 +25,12 @@ export type PostgresqlDumpTaskConfigItem = {
|
|
|
24
25
|
name: typeof postgresqlDumpTaskName;
|
|
25
26
|
config: PostgresqlDumpTaskConfig;
|
|
26
27
|
};
|
|
28
|
+
export type MongodumpTaskConfigItem = {
|
|
29
|
+
name: typeof mongodumpTaskName;
|
|
30
|
+
config: MongoDumpTaskConfig;
|
|
31
|
+
};
|
|
27
32
|
export type ScriptTaskConfigItem = {
|
|
28
33
|
name: typeof scriptTaskName;
|
|
29
34
|
config: ScriptTaskConfig;
|
|
30
35
|
};
|
|
31
|
-
export type TaskConfig = GitTaskConfigItem | MariadbTaskConfigItem | MssqlTaskConfigItem | MysqlDumpTaskConfigItem | PostgresqlDumpTaskConfigItem | ScriptTaskConfigItem;
|
|
36
|
+
export type TaskConfig = GitTaskConfigItem | MariadbTaskConfigItem | MssqlTaskConfigItem | MysqlDumpTaskConfigItem | PostgresqlDumpTaskConfigItem | MongodumpTaskConfigItem | ScriptTaskConfigItem;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Filter } from "../string";
|
|
1
2
|
import type { Config } from "./config-type";
|
|
2
3
|
import type { PackageConfig, RepositoryConfigEnabledAction, RepositoryConfig } from "./config-type";
|
|
3
4
|
export declare function findRepositoryOrFail(config: Config, repositoryName: string): RepositoryConfig;
|
|
@@ -99,4 +100,6 @@ export declare const params: {
|
|
|
99
100
|
database: string;
|
|
100
101
|
};
|
|
101
102
|
};
|
|
103
|
+
export declare function createPkgFilter(patterns: string[] | undefined): Filter;
|
|
104
|
+
export declare function createTaskFilter(patterns: string[] | undefined): Filter<string | undefined>;
|
|
102
105
|
export {};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.params = exports.dbNameParams = exports.pkgRestorePathParams = exports.pkgExcludeParams = exports.pkgIncludeParams = exports.pkgPathParams = exports.resolvePackages = exports.resolvePackage = exports.resolveDatabaseName = exports.resolvePackagePath = exports.filterPackages = exports.filterRepositoryByEnabled = exports.ensureSameRepositoryType = exports.sortReposByType = exports.filterRepository = exports.findPackageRepositoryConfig = exports.findPackageOrFail = exports.findRepositoryOrFail = void 0;
|
|
3
|
+
exports.createTaskFilter = exports.createPkgFilter = exports.params = exports.dbNameParams = exports.pkgRestorePathParams = exports.pkgExcludeParams = exports.pkgIncludeParams = exports.pkgPathParams = exports.resolvePackages = exports.resolvePackage = exports.resolveDatabaseName = exports.resolvePackagePath = exports.filterPackages = exports.filterRepositoryByEnabled = exports.ensureSameRepositoryType = exports.sortReposByType = exports.filterRepository = exports.findPackageRepositoryConfig = exports.findPackageOrFail = exports.findRepositoryOrFail = void 0;
|
|
4
4
|
const error_1 = require("../error");
|
|
5
5
|
const string_1 = require("../string");
|
|
6
6
|
const temp_1 = require("../temp");
|
|
7
|
-
const micromatch_1 = require("micromatch");
|
|
8
7
|
function findRepositoryOrFail(config, repositoryName) {
|
|
9
8
|
const repo = config.repositories.find((v) => v.name === repositoryName);
|
|
10
9
|
if (!repo)
|
|
@@ -72,28 +71,26 @@ function filterRepositoryByEnabled(repository, action) {
|
|
|
72
71
|
}
|
|
73
72
|
exports.filterRepositoryByEnabled = filterRepositoryByEnabled;
|
|
74
73
|
function filterPackages(config, options) {
|
|
75
|
-
const
|
|
76
|
-
const
|
|
74
|
+
const filterRepo = (0, string_1.createPatternFilter)(options.repositoryNames);
|
|
75
|
+
const filterRepoType = (0, string_1.createPatternFilter)(options.repositoryTypes);
|
|
76
|
+
const filterTask = createTaskFilter(options.packageTaskNames);
|
|
77
|
+
const filterPkg = createPkgFilter(options.packageNames);
|
|
77
78
|
return config.packages
|
|
78
79
|
.map((pkg) => {
|
|
79
80
|
pkg = Object.assign({}, pkg);
|
|
80
81
|
pkg.repositoryNames = (pkg.repositoryNames ?? []).filter((name) => {
|
|
81
82
|
const repo = findRepositoryOrFail(config, name);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
options.repositoryNames.includes(name)) &&
|
|
86
|
-
(!options.repositoryTypes ||
|
|
87
|
-
options.repositoryTypes.includes(repo.type)));
|
|
83
|
+
return (filterRepositoryByEnabled(repo, options?.sourceAction) &&
|
|
84
|
+
filterRepo(name) &&
|
|
85
|
+
filterRepoType(repo.type));
|
|
88
86
|
});
|
|
89
87
|
return pkg;
|
|
90
88
|
})
|
|
91
89
|
.filter((pkg) => {
|
|
92
|
-
if (taskNamePatterns && !(0, string_1.checkMatch)(pkg.task?.name, taskNamePatterns))
|
|
93
|
-
return false;
|
|
94
90
|
return ((typeof pkg.enabled !== "boolean" || pkg.enabled) &&
|
|
95
91
|
!!pkg.repositoryNames?.length &&
|
|
96
|
-
(
|
|
92
|
+
filterTask(pkg.task?.name) &&
|
|
93
|
+
filterPkg(pkg.name));
|
|
97
94
|
});
|
|
98
95
|
}
|
|
99
96
|
exports.filterPackages = filterPackages;
|
|
@@ -166,3 +163,22 @@ exports.params = {
|
|
|
166
163
|
pkgExclude: exports.pkgExcludeParams,
|
|
167
164
|
dbName: exports.dbNameParams,
|
|
168
165
|
};
|
|
166
|
+
function createPkgFilter(patterns) {
|
|
167
|
+
if (patterns === undefined)
|
|
168
|
+
return () => true;
|
|
169
|
+
const map = (v) => (v[0] === "@" && !v.includes("/") ? `${v}/**` : v);
|
|
170
|
+
const { include, exclude } = (0, string_1.splitPatterns)(patterns, map);
|
|
171
|
+
return (subject) => (0, string_1.match)(subject, include, exclude);
|
|
172
|
+
}
|
|
173
|
+
exports.createPkgFilter = createPkgFilter;
|
|
174
|
+
function createTaskFilter(patterns) {
|
|
175
|
+
if (patterns === undefined)
|
|
176
|
+
return () => true;
|
|
177
|
+
const { include, exclude } = (0, string_1.splitPatterns)(patterns);
|
|
178
|
+
return (subject) => {
|
|
179
|
+
if (!subject?.length)
|
|
180
|
+
subject = "<empty>";
|
|
181
|
+
return (0, string_1.match)(subject, include, exclude);
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
exports.createTaskFilter = createTaskFilter;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createTask = void 0;
|
|
4
4
|
const GitTask_1 = require("../../tasks/GitTask");
|
|
5
5
|
const MariadbTask_1 = require("../../tasks/MariadbTask");
|
|
6
|
+
const MongoDumpTask_1 = require("../../tasks/MongoDumpTask");
|
|
6
7
|
const MssqlTask_1 = require("../../tasks/MssqlTask");
|
|
7
8
|
const MysqlDumpTask_1 = require("../../tasks/MysqlDumpTask");
|
|
8
9
|
const PostgresqlDumpTask_1 = require("../../tasks/PostgresqlDumpTask");
|
|
@@ -24,6 +25,9 @@ function createTask(task) {
|
|
|
24
25
|
else if (task.name === MssqlTask_1.mssqlTaskName) {
|
|
25
26
|
return new MssqlTask_1.MssqlTask(task.config ?? {});
|
|
26
27
|
}
|
|
28
|
+
else if (task.name === MongoDumpTask_1.mongodumpTaskName) {
|
|
29
|
+
return new MongoDumpTask_1.MongoDumpTask(task.config ?? {});
|
|
30
|
+
}
|
|
27
31
|
else if (task.name === ScriptTask_1.scriptTaskName) {
|
|
28
32
|
return new ScriptTask_1.ScriptTask(task.config ?? {});
|
|
29
33
|
}
|
package/lib/utils/mysql.js
CHANGED
|
@@ -62,8 +62,9 @@ async function createMysqlCli(options) {
|
|
|
62
62
|
`user = "${options.username}"`,
|
|
63
63
|
`password = "${password}"`,
|
|
64
64
|
];
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const path = (0, path_1.join)(dir, "mysql.conf");
|
|
66
|
+
await (0, promises_1.writeFile)(path, data.join("\n"));
|
|
67
|
+
return (sqlConfigPath = path);
|
|
67
68
|
}
|
|
68
69
|
async function args() {
|
|
69
70
|
return [`--defaults-file=${await createSqlConfig()}`];
|
|
@@ -84,7 +85,7 @@ async function createMysqlCli(options) {
|
|
|
84
85
|
table_name
|
|
85
86
|
`, [database]))
|
|
86
87
|
.map((r) => r.table_name)
|
|
87
|
-
.filter((0, string_1.
|
|
88
|
+
.filter((0, string_1.createPatternFilter)({ include, exclude }));
|
|
88
89
|
}
|
|
89
90
|
async function dump(input) {
|
|
90
91
|
const process = new async_process_1.AsyncProcess("mysqldump", [
|
package/lib/utils/string.d.ts
CHANGED
|
@@ -11,11 +11,18 @@ export type Uri = {
|
|
|
11
11
|
path?: string;
|
|
12
12
|
};
|
|
13
13
|
export declare function formatUri(input: Uri, hidePassword?: boolean): string;
|
|
14
|
-
export declare function
|
|
14
|
+
export declare function splitPatterns(patterns: string[], map?: (pattern: string) => string): {
|
|
15
|
+
include: string[] | undefined;
|
|
16
|
+
exclude: string[] | undefined;
|
|
17
|
+
};
|
|
15
18
|
export declare function match(path: string, include?: string[], exclude?: string[]): boolean;
|
|
19
|
+
export type Filter<V = string> = (subject: V) => boolean;
|
|
20
|
+
export declare function createPatternFilter(patterns: string[] | undefined): Filter;
|
|
21
|
+
export declare function createPatternFilter(patterns: {
|
|
22
|
+
include?: string[];
|
|
23
|
+
exclude?: string[];
|
|
24
|
+
} | undefined): Filter;
|
|
16
25
|
export declare function endsWith(input: string, patterns: string[]): boolean;
|
|
17
|
-
export declare function createMatchFilter(include?: string[], exclude?: string[]): (input: string) => boolean;
|
|
18
|
-
export declare function checkMatch(subject: string | undefined, patterns: string[]): boolean;
|
|
19
26
|
export declare function undefIfEmpty(input: string): string | undefined;
|
|
20
27
|
export declare function compareJsons(a: any, b: any): boolean;
|
|
21
28
|
export {};
|
package/lib/utils/string.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.compareJsons = exports.undefIfEmpty = exports.
|
|
3
|
+
exports.compareJsons = exports.undefIfEmpty = exports.endsWith = exports.createPatternFilter = exports.match = exports.splitPatterns = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = void 0;
|
|
4
4
|
const error_1 = require("./error");
|
|
5
5
|
const micromatch_1 = require("micromatch");
|
|
6
6
|
function snakeCase(value, char = "_") {
|
|
@@ -71,36 +71,44 @@ function formatUri(input, hidePassword) {
|
|
|
71
71
|
return uri;
|
|
72
72
|
}
|
|
73
73
|
exports.formatUri = formatUri;
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
function splitPatterns(patterns, map) {
|
|
75
|
+
const include = [];
|
|
76
|
+
const exclude = [];
|
|
77
|
+
for (const pattern of patterns) {
|
|
78
|
+
if (pattern.startsWith("!")) {
|
|
79
|
+
const includePattern = pattern.slice(1);
|
|
80
|
+
exclude.push(map ? map(includePattern) : includePattern);
|
|
78
81
|
}
|
|
79
82
|
else {
|
|
80
|
-
|
|
83
|
+
include.push(map ? map(pattern) : pattern);
|
|
81
84
|
}
|
|
82
|
-
}
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
include: include.length ? include : undefined,
|
|
88
|
+
exclude: exclude.length ? exclude : undefined,
|
|
89
|
+
};
|
|
83
90
|
}
|
|
84
|
-
exports.
|
|
91
|
+
exports.splitPatterns = splitPatterns;
|
|
85
92
|
function match(path, include, exclude) {
|
|
86
93
|
return ((!include || (0, micromatch_1.isMatch)(path, include, { dot: true })) &&
|
|
87
94
|
(!exclude || !(0, micromatch_1.isMatch)(path, exclude, { dot: true })));
|
|
88
95
|
}
|
|
89
96
|
exports.match = match;
|
|
97
|
+
function createPatternFilter(patterns) {
|
|
98
|
+
if (patterns === undefined) {
|
|
99
|
+
return () => true;
|
|
100
|
+
}
|
|
101
|
+
else if (Array.isArray(patterns)) {
|
|
102
|
+
patterns = splitPatterns(patterns);
|
|
103
|
+
}
|
|
104
|
+
const { include, exclude } = patterns;
|
|
105
|
+
return (input) => match(input, include, exclude);
|
|
106
|
+
}
|
|
107
|
+
exports.createPatternFilter = createPatternFilter;
|
|
90
108
|
function endsWith(input, patterns) {
|
|
91
109
|
return patterns.some((pattern) => input.endsWith(pattern));
|
|
92
110
|
}
|
|
93
111
|
exports.endsWith = endsWith;
|
|
94
|
-
function createMatchFilter(include, exclude) {
|
|
95
|
-
return (input) => match(input, include, exclude);
|
|
96
|
-
}
|
|
97
|
-
exports.createMatchFilter = createMatchFilter;
|
|
98
|
-
function checkMatch(subject, patterns) {
|
|
99
|
-
if (!subject?.length)
|
|
100
|
-
subject = "<empty>";
|
|
101
|
-
return (0, micromatch_1.isMatch)(subject, patterns);
|
|
102
|
-
}
|
|
103
|
-
exports.checkMatch = checkMatch;
|
|
104
112
|
function undefIfEmpty(input) {
|
|
105
113
|
return input.length ? input : undefined;
|
|
106
114
|
}
|