@datatruck/cli 0.35.0 → 0.36.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/config.schema.json +25 -28
- package/lib/actions/BackupAction.js +1 -0
- package/lib/actions/CopyAction.js +1 -0
- package/lib/actions/InitAction.js +5 -4
- package/lib/actions/RestoreAction.js +5 -4
- package/lib/actions/SnapshotsAction.d.ts +1 -0
- package/lib/actions/SnapshotsAction.js +9 -5
- package/lib/commands/RestoreCommand.d.ts +1 -0
- package/lib/commands/SnapshotsCommand.d.ts +1 -0
- package/lib/commands/SnapshotsCommand.js +8 -0
- package/lib/repositories/DatatruckRepository.d.ts +3 -9
- package/lib/repositories/DatatruckRepository.js +29 -23
- package/lib/repositories/GitRepository.d.ts +3 -5
- package/lib/repositories/GitRepository.js +15 -14
- package/lib/repositories/RepositoryAbstract.d.ts +5 -1
- package/lib/repositories/RepositoryAbstract.js +1 -0
- package/lib/repositories/ResticRepository.d.ts +3 -4
- package/lib/repositories/ResticRepository.js +32 -22
- package/lib/tasks/MssqlTask.js +5 -5
- 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.d.ts +3 -0
- package/lib/utils/datatruck/config.js +29 -13
- package/lib/utils/datatruck/cron-server.d.ts +1 -1
- package/lib/utils/datatruck/cron-server.js +3 -1
- package/lib/utils/mysql.js +1 -1
- 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
|
@@ -2073,7 +2073,7 @@
|
|
|
2073
2073
|
"const": "prune"
|
|
2074
2074
|
},
|
|
2075
2075
|
"options": {
|
|
2076
|
-
"$ref": "#/definitions/PruneCommandOptions"
|
|
2076
|
+
"$ref": "#/definitions/Omit<PruneCommandOptions,\"confirm\">"
|
|
2077
2077
|
}
|
|
2078
2078
|
},
|
|
2079
2079
|
"required": [
|
|
@@ -2084,62 +2084,59 @@
|
|
|
2084
2084
|
}
|
|
2085
2085
|
]
|
|
2086
2086
|
},
|
|
2087
|
-
"PruneCommandOptions": {
|
|
2088
|
-
"additionalProperties": false,
|
|
2087
|
+
"Omit<PruneCommandOptions,\"confirm\">": {
|
|
2089
2088
|
"type": "object",
|
|
2090
2089
|
"properties": {
|
|
2091
|
-
"
|
|
2092
|
-
"type": "
|
|
2090
|
+
"repository": {
|
|
2091
|
+
"type": "string"
|
|
2093
2092
|
},
|
|
2094
|
-
"
|
|
2093
|
+
"repositoryType": {
|
|
2094
|
+
"type": "string"
|
|
2095
|
+
},
|
|
2096
|
+
"id": {
|
|
2097
|
+
"type": "string"
|
|
2098
|
+
},
|
|
2099
|
+
"groupBy": {
|
|
2100
|
+
"type": "string"
|
|
2101
|
+
},
|
|
2102
|
+
"dryRun": {
|
|
2103
|
+
"type": "boolean"
|
|
2104
|
+
},
|
|
2105
|
+
"keepDaily": {
|
|
2095
2106
|
"type": "number"
|
|
2096
2107
|
},
|
|
2097
2108
|
"keepHourly": {
|
|
2098
2109
|
"type": "number"
|
|
2099
2110
|
},
|
|
2100
|
-
"
|
|
2111
|
+
"keepMinutely": {
|
|
2101
2112
|
"type": "number"
|
|
2102
2113
|
},
|
|
2103
|
-
"
|
|
2114
|
+
"keepLast": {
|
|
2104
2115
|
"type": "number"
|
|
2105
2116
|
},
|
|
2106
2117
|
"keepMonthly": {
|
|
2107
2118
|
"type": "number"
|
|
2108
2119
|
},
|
|
2109
|
-
"
|
|
2120
|
+
"keepWeekly": {
|
|
2110
2121
|
"type": "number"
|
|
2111
2122
|
},
|
|
2112
|
-
"
|
|
2113
|
-
"type": "
|
|
2114
|
-
},
|
|
2115
|
-
"longId": {
|
|
2116
|
-
"type": "boolean"
|
|
2123
|
+
"keepYearly": {
|
|
2124
|
+
"type": "number"
|
|
2117
2125
|
},
|
|
2118
2126
|
"package": {
|
|
2119
2127
|
"type": "string"
|
|
2120
2128
|
},
|
|
2121
|
-
"repository": {
|
|
2122
|
-
"type": "string"
|
|
2123
|
-
},
|
|
2124
|
-
"repositoryType": {
|
|
2125
|
-
"type": "string"
|
|
2126
|
-
},
|
|
2127
2129
|
"tag": {
|
|
2128
2130
|
"type": "string"
|
|
2129
2131
|
},
|
|
2130
|
-
"
|
|
2131
|
-
"type": "string"
|
|
2132
|
-
},
|
|
2133
|
-
"dryRun": {
|
|
2132
|
+
"longId": {
|
|
2134
2133
|
"type": "boolean"
|
|
2135
2134
|
},
|
|
2136
2135
|
"showAll": {
|
|
2137
2136
|
"type": "boolean"
|
|
2138
|
-
},
|
|
2139
|
-
"confirm": {
|
|
2140
|
-
"type": "boolean"
|
|
2141
2137
|
}
|
|
2142
|
-
}
|
|
2138
|
+
},
|
|
2139
|
+
"additionalProperties": false
|
|
2143
2140
|
}
|
|
2144
2141
|
},
|
|
2145
2142
|
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
@@ -164,6 +164,7 @@ class CopyAction {
|
|
|
164
164
|
if (this.config.minFreeDiskSpace)
|
|
165
165
|
await mirrorRepo.ensureFreeDiskSpace(mirrorConfig.config, this.config.minFreeDiskSpace);
|
|
166
166
|
return await mirrorRepo.backup({
|
|
167
|
+
hostname: snapshot.hostname,
|
|
167
168
|
options: {
|
|
168
169
|
verbose: this.options.verbose,
|
|
169
170
|
tags: snapshot.tags,
|
|
@@ -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 @@ import { IfRequireKeys } from "../utils/ts";
|
|
|
4
4
|
export type SnapshotGroupByType = keyof Pick<ExtendedSnapshot, "packageName" | "repositoryName" | "repositoryType">;
|
|
5
5
|
export type SnapshotsActionOptions = {
|
|
6
6
|
ids?: string[];
|
|
7
|
+
hostnames?: string[];
|
|
7
8
|
repositoryNames?: string[];
|
|
8
9
|
packageNames?: string[];
|
|
9
10
|
packageTaskNames?: string[];
|
|
@@ -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,15 @@ class SnapshotsAction {
|
|
|
15
16
|
if (!sourceAction)
|
|
16
17
|
sourceAction = "snapshots";
|
|
17
18
|
let result = [];
|
|
19
|
+
const filterHost = (0, string_1.createPatternFilter)(this.options.hostnames);
|
|
20
|
+
const filterRepo = (0, string_1.createPatternFilter)(this.options.repositoryNames);
|
|
21
|
+
const filterRepoType = (0, string_1.createPatternFilter)(this.options.repositoryTypes);
|
|
18
22
|
for (const repoConfig of this.config.repositories) {
|
|
19
23
|
if (!(0, config_1.filterRepositoryByEnabled)(repoConfig, sourceAction))
|
|
20
24
|
continue;
|
|
21
|
-
if (
|
|
22
|
-
!this.options.repositoryNames.includes(repoConfig.name))
|
|
25
|
+
if (!filterRepo(repoConfig.name))
|
|
23
26
|
continue;
|
|
24
|
-
if (
|
|
25
|
-
!this.options.repositoryTypes.includes(repoConfig.type))
|
|
27
|
+
if (!filterRepoType(repoConfig.type))
|
|
26
28
|
continue;
|
|
27
29
|
const repo = await (0, repository_1.createAndInitRepo)(repoConfig, this.options.verbose);
|
|
28
30
|
const configPackageNames = this.config.packages.map((pkg) => pkg.name);
|
|
@@ -35,12 +37,14 @@ class SnapshotsAction {
|
|
|
35
37
|
packageNames,
|
|
36
38
|
},
|
|
37
39
|
});
|
|
38
|
-
|
|
40
|
+
let extentedItems = snapshots.map((ss) => ({
|
|
39
41
|
...ss,
|
|
40
42
|
shortId: ss.id.slice(0, 8),
|
|
41
43
|
repositoryName: repoConfig.name,
|
|
42
44
|
repositoryType: repoConfig.type,
|
|
43
45
|
}));
|
|
46
|
+
if (this.options.hostnames)
|
|
47
|
+
extentedItems = extentedItems.filter((s) => filterHost(s.hostname));
|
|
44
48
|
result.push(...extentedItems);
|
|
45
49
|
}
|
|
46
50
|
result = result.sort((a, b) => b.date.localeCompare(a.date));
|
|
@@ -4,6 +4,7 @@ import { If } from "../utils/ts";
|
|
|
4
4
|
import { CommandAbstract } from "./CommandAbstract";
|
|
5
5
|
export type SnapshotsCommandOptions<TResolved = false> = {
|
|
6
6
|
id?: If<TResolved, string[]>;
|
|
7
|
+
host?: If<TResolved, string[]>;
|
|
7
8
|
package?: If<TResolved, string[]>;
|
|
8
9
|
packageTask?: If<TResolved, string[]>;
|
|
9
10
|
packageConfig?: boolean;
|
|
@@ -30,6 +30,11 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
30
30
|
description: "Filter by identifiers",
|
|
31
31
|
parser: string_1.parseStringList,
|
|
32
32
|
},
|
|
33
|
+
host: {
|
|
34
|
+
option: "-h,--host <names>",
|
|
35
|
+
description: "Filter by hostnames",
|
|
36
|
+
parser: string_1.parseStringList,
|
|
37
|
+
},
|
|
33
38
|
last: {
|
|
34
39
|
option: "-l,--last <number>",
|
|
35
40
|
description: "Filter by last snapshots",
|
|
@@ -101,6 +106,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
101
106
|
const config = await ConfigAction_1.ConfigAction.fromGlobalOptions(this.globalOptions);
|
|
102
107
|
const snapshots = new SnapshotsAction_1.SnapshotsAction(config, {
|
|
103
108
|
ids: this.options.id,
|
|
109
|
+
hostnames: this.options.host,
|
|
104
110
|
packageNames: this.options.package,
|
|
105
111
|
packageTaskNames: this.options.packageTask,
|
|
106
112
|
packageConfig: this.options.packageConfig,
|
|
@@ -125,6 +131,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
125
131
|
headers: [
|
|
126
132
|
{ value: "Id.", width: (this.options.longId ? 32 : 8) + 2 },
|
|
127
133
|
{ value: "Date", width: 23 + 2 },
|
|
134
|
+
{ value: "Host" },
|
|
128
135
|
{ value: "Package" },
|
|
129
136
|
{ value: "Task" },
|
|
130
137
|
{ value: "Size" },
|
|
@@ -134,6 +141,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
134
141
|
rows: () => result.map((item) => [
|
|
135
142
|
this.options.longId ? item.id : item.id.slice(0, 8),
|
|
136
143
|
item.date.replace("T", " ").replace("Z", ""),
|
|
144
|
+
item.hostname,
|
|
137
145
|
item.packageName,
|
|
138
146
|
item.packageTaskName || "",
|
|
139
147
|
(0, bytes_1.formatBytes)(item.size),
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { CompressOptions } from "../utils/tar";
|
|
2
|
-
import { RepositoryAbstract, RepoBackupData, RepoInitData, RepoRestoreData, RepoFetchSnapshotsData, Snapshot, RepoPruneData, RepoCopyData } from "./RepositoryAbstract";
|
|
3
|
-
export type MetaData = {
|
|
4
|
-
id: string;
|
|
5
|
-
date: string;
|
|
6
|
-
package: string;
|
|
7
|
-
task: string | undefined;
|
|
8
|
-
tags: string[];
|
|
9
|
-
version: string;
|
|
2
|
+
import { RepositoryAbstract, RepoBackupData, RepoInitData, RepoRestoreData, RepoFetchSnapshotsData, Snapshot, RepoPruneData, RepoCopyData, SnapshotTagObject } from "./RepositoryAbstract";
|
|
3
|
+
export type MetaData = Omit<SnapshotTagObject, "shortId" | "size"> & {
|
|
10
4
|
size: number;
|
|
11
5
|
tarStats?: Record<string, {
|
|
12
6
|
files: number;
|
|
@@ -32,7 +26,7 @@ export type DatatruckPackageRepositoryConfig = {
|
|
|
32
26
|
export declare const datatruckRepositoryName = "datatruck";
|
|
33
27
|
export declare class DatatruckRepository extends RepositoryAbstract<DatatruckRepositoryConfig> {
|
|
34
28
|
static zipBasenameTpl: string;
|
|
35
|
-
static
|
|
29
|
+
static createSnapshotName(snapshot: {
|
|
36
30
|
id: string;
|
|
37
31
|
date: string;
|
|
38
32
|
}, pkg: {
|
|
@@ -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,12 +16,11 @@ 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 {
|
|
21
22
|
static zipBasenameTpl = `.*.dd.tar.gz`;
|
|
22
|
-
static
|
|
23
|
+
static createSnapshotName(snapshot, pkg) {
|
|
23
24
|
const date = snapshot.date.replace(/:/g, "-");
|
|
24
25
|
const pkgName = encodeURIComponent(pkg.name)
|
|
25
26
|
.replace(/%40/g, "@")
|
|
@@ -54,7 +55,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
54
55
|
}
|
|
55
56
|
async prune(data) {
|
|
56
57
|
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
57
|
-
const snapshotName = DatatruckRepository.
|
|
58
|
+
const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, {
|
|
58
59
|
name: data.snapshot.packageName,
|
|
59
60
|
});
|
|
60
61
|
if (data.options.verbose)
|
|
@@ -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,12 +97,13 @@ 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,
|
|
100
104
|
packageTaskName: meta.task,
|
|
101
105
|
tags: meta.tags,
|
|
106
|
+
hostname: meta.hostname ?? "",
|
|
102
107
|
size: meta.size || 0,
|
|
103
108
|
});
|
|
104
109
|
}
|
|
@@ -106,7 +111,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
106
111
|
}
|
|
107
112
|
async backup(data) {
|
|
108
113
|
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
109
|
-
const snapshotName = DatatruckRepository.
|
|
114
|
+
const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, data.package);
|
|
110
115
|
const outPath = fs.isLocal()
|
|
111
116
|
? fs.resolvePath(snapshotName)
|
|
112
117
|
: await (0, temp_1.mkTmpDir)(exports.datatruckRepositoryName, "repo", "backup", "fs-remote");
|
|
@@ -209,6 +214,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
209
214
|
const nodePkg = (0, fs_1.parsePackageFile)();
|
|
210
215
|
const meta = {
|
|
211
216
|
id: data.snapshot.id,
|
|
217
|
+
hostname: data.hostname,
|
|
212
218
|
date: data.snapshot.date,
|
|
213
219
|
tags: data.options.tags ?? [],
|
|
214
220
|
package: data.package.name,
|
|
@@ -227,7 +233,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
227
233
|
async copy(data) {
|
|
228
234
|
const sourceFs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
229
235
|
const targetFs = (0, client_1.createFs)(data.mirrorRepositoryConfig.backend, this.verbose);
|
|
230
|
-
const snapshotName = DatatruckRepository.
|
|
236
|
+
const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, data.package);
|
|
231
237
|
if (data.options.verbose)
|
|
232
238
|
(0, cli_1.logExec)(`Copying backup files to ${data.mirrorRepositoryConfig.backend}`);
|
|
233
239
|
const tmpSnapshotName = `${snapshotName}_tmp`;
|
|
@@ -307,7 +313,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
307
313
|
});
|
|
308
314
|
if (!snapshot)
|
|
309
315
|
throw new error_1.AppError("Snapshot not found");
|
|
310
|
-
const snapshotName = DatatruckRepository.
|
|
316
|
+
const snapshotName = DatatruckRepository.createSnapshotName(snapshot, data.package);
|
|
311
317
|
const meta = await DatatruckRepository.parseMetaData(await fs.readFile(`${snapshotName}/meta.json`));
|
|
312
318
|
const progress = (0, fs_1.createProgress)({ onProgress: data.onProgress });
|
|
313
319
|
progress.update("Scanning files");
|
|
@@ -9,15 +9,13 @@ export declare class GitRepository extends RepositoryAbstract<GitRepositoryConfi
|
|
|
9
9
|
static refPrefix: string;
|
|
10
10
|
getSource(): string;
|
|
11
11
|
fetchDiskStats(config: GitRepositoryConfig): Promise<import("../utils/fs").DiskStats | undefined>;
|
|
12
|
-
static
|
|
13
|
-
static
|
|
12
|
+
static createSnapshotTagName(tag: Pick<SnapshotTagObject, SnapshotTagEnum.PACKAGE | SnapshotTagEnum.ID>): string;
|
|
13
|
+
static createSnapshotTags(tags: SnapshotTagObject): {
|
|
14
14
|
name: string;
|
|
15
15
|
message: string;
|
|
16
16
|
};
|
|
17
17
|
static isSnapshotTag(name: string): boolean;
|
|
18
|
-
static
|
|
19
|
-
tags: string[];
|
|
20
|
-
}) | null;
|
|
18
|
+
static parseSnapshotTags(name: string, message: string): SnapshotTagObject | null;
|
|
21
19
|
static buildBranchName(packageName: string): string;
|
|
22
20
|
init(data: RepoInitData): Promise<void>;
|
|
23
21
|
prune(data: RepoPruneData): Promise<void>;
|
|
@@ -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 {
|
|
@@ -25,19 +24,19 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
25
24
|
if ((0, fs_1.isLocalDir)(config.repo))
|
|
26
25
|
return await (0, fs_1.fetchDiskStats)(config.repo);
|
|
27
26
|
}
|
|
28
|
-
static
|
|
27
|
+
static createSnapshotTagName(tag) {
|
|
29
28
|
return `${GitRepository.refPrefix}/${tag.package}/${tag.id}`;
|
|
30
29
|
}
|
|
31
|
-
static
|
|
30
|
+
static createSnapshotTags(tags) {
|
|
32
31
|
return {
|
|
33
|
-
name: GitRepository.
|
|
34
|
-
message: JSON.stringify(
|
|
32
|
+
name: GitRepository.createSnapshotTagName(tags),
|
|
33
|
+
message: JSON.stringify(tags),
|
|
35
34
|
};
|
|
36
35
|
}
|
|
37
36
|
static isSnapshotTag(name) {
|
|
38
37
|
return name.startsWith(`${GitRepository.refPrefix}/`);
|
|
39
38
|
}
|
|
40
|
-
static
|
|
39
|
+
static parseSnapshotTags(name, message) {
|
|
41
40
|
if (GitRepository.isSnapshotTag(name))
|
|
42
41
|
return JSON.parse(message);
|
|
43
42
|
return null;
|
|
@@ -104,21 +103,21 @@ 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
|
|
115
|
-
? GitRepository.
|
|
114
|
+
? GitRepository.parseSnapshotTags(tag.name, tag.message)
|
|
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)))
|
|
@@ -130,6 +129,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
130
129
|
packageName: parsedTag.package,
|
|
131
130
|
packageTaskName: parsedTag.task,
|
|
132
131
|
tags: parsedTag.tags,
|
|
132
|
+
hostname: parsedTag.hostname ?? "",
|
|
133
133
|
size: Number(parsedTag.size) || 0,
|
|
134
134
|
});
|
|
135
135
|
return result;
|
|
@@ -197,8 +197,9 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
197
197
|
const nodePkg = (0, fs_1.parsePackageFile)();
|
|
198
198
|
const size = (await (0, fs_1.fastFolderSizeAsync)(tmpPath)) -
|
|
199
199
|
(await (0, fs_1.fastFolderSizeAsync)((0, path_1.join)(tmpPath, ".git")));
|
|
200
|
-
const meta = GitRepository.
|
|
200
|
+
const meta = GitRepository.createSnapshotTags({
|
|
201
201
|
id: data.snapshot.id,
|
|
202
|
+
hostname: data.hostname,
|
|
202
203
|
shortId: data.snapshot.id.slice(0, 8),
|
|
203
204
|
tags: data.options.tags ?? [],
|
|
204
205
|
date: data.snapshot.date,
|
|
@@ -221,7 +222,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
221
222
|
}
|
|
222
223
|
async restore(data) {
|
|
223
224
|
const restorePath = data.snapshotPath;
|
|
224
|
-
const tagName = GitRepository.
|
|
225
|
+
const tagName = GitRepository.createSnapshotTagName({
|
|
225
226
|
id: data.snapshot.id,
|
|
226
227
|
package: data.package.name,
|
|
227
228
|
});
|
|
@@ -13,6 +13,7 @@ export type Snapshot = PreSnapshot & {
|
|
|
13
13
|
packageName: string;
|
|
14
14
|
packageTaskName: string | undefined;
|
|
15
15
|
tags: string[];
|
|
16
|
+
hostname: string;
|
|
16
17
|
size: number;
|
|
17
18
|
};
|
|
18
19
|
export type RepoInitData = {
|
|
@@ -33,6 +34,7 @@ export type RepoCopyData<TRepositoryConfig> = {
|
|
|
33
34
|
export type RepoBackupData<TPackageConfig> = {
|
|
34
35
|
options: BackupActionOptions;
|
|
35
36
|
snapshot: PreSnapshot;
|
|
37
|
+
hostname: string;
|
|
36
38
|
package: Omit<PackageConfig, "path"> & {
|
|
37
39
|
path: string;
|
|
38
40
|
};
|
|
@@ -61,7 +63,8 @@ export declare enum SnapshotTagEnum {
|
|
|
61
63
|
TASK = "task",
|
|
62
64
|
TAGS = "tags",
|
|
63
65
|
VERSION = "version",
|
|
64
|
-
SIZE = "size"
|
|
66
|
+
SIZE = "size",
|
|
67
|
+
HOSTNAME = "hostname"
|
|
65
68
|
}
|
|
66
69
|
export type SnapshotTagObject = {
|
|
67
70
|
[SnapshotTagEnum.ID]: string;
|
|
@@ -72,6 +75,7 @@ export type SnapshotTagObject = {
|
|
|
72
75
|
[SnapshotTagEnum.TAGS]: string[];
|
|
73
76
|
[SnapshotTagEnum.VERSION]: string;
|
|
74
77
|
[SnapshotTagEnum.SIZE]: string;
|
|
78
|
+
[SnapshotTagEnum.HOSTNAME]: string;
|
|
75
79
|
};
|
|
76
80
|
export declare abstract class RepositoryAbstract<TConfig> {
|
|
77
81
|
readonly repository: RepositoryConfig;
|
|
@@ -12,6 +12,7 @@ var SnapshotTagEnum;
|
|
|
12
12
|
SnapshotTagEnum["TAGS"] = "tags";
|
|
13
13
|
SnapshotTagEnum["VERSION"] = "version";
|
|
14
14
|
SnapshotTagEnum["SIZE"] = "size";
|
|
15
|
+
SnapshotTagEnum["HOSTNAME"] = "hostname";
|
|
15
16
|
})(SnapshotTagEnum || (exports.SnapshotTagEnum = SnapshotTagEnum = {}));
|
|
16
17
|
class RepositoryAbstract {
|
|
17
18
|
repository;
|
|
@@ -20,14 +20,13 @@ export declare class ResticRepository extends RepositoryAbstract<ResticRepositor
|
|
|
20
20
|
RESTIC_PASSWORD_FILE?: string | undefined;
|
|
21
21
|
RESTIC_REPOSITORY: string;
|
|
22
22
|
}>;
|
|
23
|
-
static
|
|
23
|
+
static createSnapshotTag(name: SnapshotTagEnum, value: string): string;
|
|
24
|
+
static createSnapshotTags(object: Omit<SnapshotTagObject, "size">): string[];
|
|
24
25
|
static parseSnapshotTag(tag: string): {
|
|
25
26
|
name: SnapshotTagEnum;
|
|
26
27
|
value: string;
|
|
27
28
|
} | null;
|
|
28
|
-
static parseSnapshotTags(tags: string[]): SnapshotTagObject
|
|
29
|
-
tags: string[];
|
|
30
|
-
};
|
|
29
|
+
static parseSnapshotTags(tags: string[]): SnapshotTagObject;
|
|
31
30
|
getSource(): string;
|
|
32
31
|
fetchDiskStats(config: ResticRepositoryConfig): Promise<import("../utils/fs").DiskStats | undefined>;
|
|
33
32
|
init(data: RepoInitData): Promise<void>;
|
|
@@ -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 {
|
|
@@ -31,9 +31,21 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
31
31
|
RESTIC_REPOSITORY: await restic_1.Restic.formatRepository(this.config.repository),
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
static
|
|
34
|
+
static createSnapshotTag(name, value) {
|
|
35
35
|
return `${ResticRepository.refPrefix}${name}:${value}`;
|
|
36
36
|
}
|
|
37
|
+
static createSnapshotTags(object) {
|
|
38
|
+
const { tags: inTags, ...otherTags } = object;
|
|
39
|
+
const tags = [...inTags];
|
|
40
|
+
for (const key in otherTags) {
|
|
41
|
+
const value = object[key];
|
|
42
|
+
if (value !== undefined) {
|
|
43
|
+
const tag = ResticRepository.createSnapshotTag(key, value);
|
|
44
|
+
tags.push(tag);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return tags;
|
|
48
|
+
}
|
|
37
49
|
static parseSnapshotTag(tag) {
|
|
38
50
|
for (const metaName in RepositoryAbstract_1.SnapshotTagEnum) {
|
|
39
51
|
const name = RepositoryAbstract_1.SnapshotTagEnum[metaName];
|
|
@@ -83,21 +95,21 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
83
95
|
env: await this.buildEnv(),
|
|
84
96
|
log: data.options.verbose,
|
|
85
97
|
});
|
|
86
|
-
const packagePatterns = (0, string_1.makePathPatterns)(data.options.packageNames);
|
|
87
|
-
const taskNamePatterns = (0, string_1.makePathPatterns)(data.options.packageTaskNames);
|
|
88
98
|
const result = await restic.snapshots({
|
|
89
99
|
json: true,
|
|
90
100
|
tags: [
|
|
91
|
-
...(data.options.ids?.map((id) => ResticRepository.
|
|
101
|
+
...(data.options.ids?.map((id) => ResticRepository.createSnapshotTag(id.length === 8 ? RepositoryAbstract_1.SnapshotTagEnum.SHORT_ID : RepositoryAbstract_1.SnapshotTagEnum.ID, id)) ?? []),
|
|
92
102
|
],
|
|
93
103
|
});
|
|
104
|
+
const filterPkg = (0, config_1.createPkgFilter)(data.options.packageNames);
|
|
105
|
+
const filterTask = (0, config_1.createTaskFilter)(data.options.packageTaskNames);
|
|
94
106
|
return result.reduce((items, item) => {
|
|
95
107
|
const tag = ResticRepository.parseSnapshotTags(item.tags ?? []);
|
|
96
108
|
if (!tag.id)
|
|
97
109
|
return items;
|
|
98
|
-
if (
|
|
110
|
+
if (!filterPkg(tag.package))
|
|
99
111
|
return items;
|
|
100
|
-
if (
|
|
112
|
+
if (!filterTask(tag.task))
|
|
101
113
|
return items;
|
|
102
114
|
const itemTags = tag.tags ?? [];
|
|
103
115
|
if (data.options.tags && !itemTags.some((t) => itemTags.includes(t)))
|
|
@@ -109,6 +121,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
109
121
|
date: tag.date,
|
|
110
122
|
id: tag.id,
|
|
111
123
|
tags: itemTags,
|
|
124
|
+
hostname: tag.hostname ?? "",
|
|
112
125
|
size: Number(tag.size) || 0,
|
|
113
126
|
});
|
|
114
127
|
return items;
|
|
@@ -176,7 +189,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
176
189
|
}
|
|
177
190
|
if (data.options.tags?.some((tag) => tag.startsWith(ResticRepository.refPrefix)))
|
|
178
191
|
throw new error_1.AppError(`Tag prefix is not allowed`);
|
|
179
|
-
const packageTag = ResticRepository.
|
|
192
|
+
const packageTag = ResticRepository.createSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.PACKAGE, data.package.name);
|
|
180
193
|
data.onProgress({
|
|
181
194
|
relative: {
|
|
182
195
|
description: "Fetching last snapshot",
|
|
@@ -204,19 +217,16 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
204
217
|
allowEmptySnapshot: true,
|
|
205
218
|
excludeFile: gitignorePath ? [gitignorePath] : undefined,
|
|
206
219
|
parent: lastSnapshot?.id,
|
|
207
|
-
tags:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
: []),
|
|
218
|
-
...(data.options.tags ?? []),
|
|
219
|
-
],
|
|
220
|
+
tags: ResticRepository.createSnapshotTags({
|
|
221
|
+
id: data.snapshot.id,
|
|
222
|
+
hostname: data.hostname,
|
|
223
|
+
shortId: data.snapshot.id.slice(0, 8),
|
|
224
|
+
date: data.snapshot.date,
|
|
225
|
+
version: nodePkg.version,
|
|
226
|
+
package: data.package.name,
|
|
227
|
+
task: data.package.task?.name,
|
|
228
|
+
tags: data.options.tags || [],
|
|
229
|
+
}),
|
|
220
230
|
createEmptyDir: async () => await (0, temp_1.mkTmpDir)(exports.resticRepositoryName, "repo", "backup", "empty-dir"),
|
|
221
231
|
onStream: async (streamData) => {
|
|
222
232
|
if (streamData.message_type === "status") {
|
|
@@ -254,7 +264,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
254
264
|
throw new error_1.AppError(`Restic snapshot id is is not defined`);
|
|
255
265
|
if (typeof resticTotalBytes !== "number")
|
|
256
266
|
throw new error_1.AppError(`Restic snapshot total bytes is not defined`);
|
|
257
|
-
const sizeTag = ResticRepository.
|
|
267
|
+
const sizeTag = ResticRepository.createSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.SIZE, resticTotalBytes.toString());
|
|
258
268
|
await restic.exec(["tag", "--add", sizeTag, resticSnapshotId]);
|
|
259
269
|
data.onProgress({
|
|
260
270
|
absolute: {
|
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`);
|
|
@@ -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,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;
|
|
@@ -31,7 +31,9 @@ function createCronServer(options, config) {
|
|
|
31
31
|
try {
|
|
32
32
|
const Command = command_1.datatruckCommandMap[action.name];
|
|
33
33
|
const command = new Command({ config: { packages: [], repositories: [] } }, {});
|
|
34
|
-
const cliOptions = (0, cli_1.stringifyOptions)(command.optionsConfig(), action.
|
|
34
|
+
const cliOptions = (0, cli_1.stringifyOptions)(command.optionsConfig(), action.name === "prune"
|
|
35
|
+
? ({ ...action.options, confirm: true })
|
|
36
|
+
: action.options);
|
|
35
37
|
const [node, bin] = process.argv;
|
|
36
38
|
await async_process_1.AsyncProcess.exec(node, [bin, "-c", config.configPath, action.name, ...cliOptions], { $log: config.verbose });
|
|
37
39
|
if (config.log)
|
package/lib/utils/mysql.js
CHANGED
|
@@ -85,7 +85,7 @@ async function createMysqlCli(options) {
|
|
|
85
85
|
table_name
|
|
86
86
|
`, [database]))
|
|
87
87
|
.map((r) => r.table_name)
|
|
88
|
-
.filter((0, string_1.
|
|
88
|
+
.filter((0, string_1.createPatternFilter)({ include, exclude }));
|
|
89
89
|
}
|
|
90
90
|
async function dump(input) {
|
|
91
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
|
}
|