@datatruck/cli 0.0.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/lib/Action/BackupAction.d.ts +32 -0
- package/lib/Action/BackupAction.js +201 -0
- package/lib/Action/BackupSessionsAction.d.ts +13 -0
- package/lib/Action/BackupSessionsAction.js +16 -0
- package/lib/Action/CleanCacheAction.d.ts +9 -0
- package/lib/Action/CleanCacheAction.js +18 -0
- package/lib/Action/ConfigAction.d.ts +14 -0
- package/lib/Action/ConfigAction.js +64 -0
- package/lib/Action/InitAction.d.ts +18 -0
- package/lib/Action/InitAction.js +39 -0
- package/lib/Action/PruneAction.d.ts +37 -0
- package/lib/Action/PruneAction.js +80 -0
- package/lib/Action/RestoreAction.d.ts +36 -0
- package/lib/Action/RestoreAction.js +246 -0
- package/lib/Action/RestoreSessionsAction.d.ts +13 -0
- package/lib/Action/RestoreSessionsAction.js +16 -0
- package/lib/Action/SnapshotsAction.d.ts +30 -0
- package/lib/Action/SnapshotsAction.js +35 -0
- package/lib/Command/BackupCommand.d.ts +15 -0
- package/lib/Command/BackupCommand.js +83 -0
- package/lib/Command/BackupSessionsCommand.d.ts +12 -0
- package/lib/Command/BackupSessionsCommand.js +88 -0
- package/lib/Command/CleanCacheCommand.d.ts +6 -0
- package/lib/Command/CleanCacheCommand.js +20 -0
- package/lib/Command/CommandAbstract.d.ts +19 -0
- package/lib/Command/CommandAbstract.js +14 -0
- package/lib/Command/ConfigCommand.d.ts +17 -0
- package/lib/Command/ConfigCommand.js +61 -0
- package/lib/Command/InitCommand.d.ts +13 -0
- package/lib/Command/InitCommand.js +67 -0
- package/lib/Command/PruneCommand.d.ts +27 -0
- package/lib/Command/PruneCommand.js +160 -0
- package/lib/Command/RestoreCommand.d.ts +14 -0
- package/lib/Command/RestoreCommand.js +71 -0
- package/lib/Command/RestoreSessionsCommand.d.ts +12 -0
- package/lib/Command/RestoreSessionsCommand.js +87 -0
- package/lib/Command/SnapshotsCommand.d.ts +25 -0
- package/lib/Command/SnapshotsCommand.js +128 -0
- package/lib/Config/Config.d.ts +8 -0
- package/lib/Config/Config.js +19 -0
- package/lib/Config/PackageConfig.d.ts +27 -0
- package/lib/Config/PackageConfig.js +69 -0
- package/lib/Config/PackageRepositoryConfig.d.ts +17 -0
- package/lib/Config/PackageRepositoryConfig.js +37 -0
- package/lib/Config/PrunePolicyConfig.d.ts +4 -0
- package/lib/Config/PrunePolicyConfig.js +28 -0
- package/lib/Config/RepositoryConfig.d.ts +18 -0
- package/lib/Config/RepositoryConfig.js +37 -0
- package/lib/Config/TaskConfig.d.ts +23 -0
- package/lib/Config/TaskConfig.js +39 -0
- package/lib/Decorator/EntityDecorator.d.ts +11 -0
- package/lib/Decorator/EntityDecorator.js +17 -0
- package/lib/Entity/BackupSessionEntity.d.ts +6 -0
- package/lib/Entity/BackupSessionEntity.js +22 -0
- package/lib/Entity/BackupSessionRepositoryEntity.d.ts +6 -0
- package/lib/Entity/BackupSessionRepositoryEntity.js +22 -0
- package/lib/Entity/BackupSessionTaskEntity.d.ts +5 -0
- package/lib/Entity/BackupSessionTaskEntity.js +22 -0
- package/lib/Entity/CrudEntityAbstract.d.ts +5 -0
- package/lib/Entity/CrudEntityAbstract.js +6 -0
- package/lib/Entity/RestoreSessionEntity.d.ts +5 -0
- package/lib/Entity/RestoreSessionEntity.js +22 -0
- package/lib/Entity/RestoreSessionRepositoryEntity.d.ts +6 -0
- package/lib/Entity/RestoreSessionRepositoryEntity.js +22 -0
- package/lib/Entity/RestoreSessionTaskEntity.d.ts +5 -0
- package/lib/Entity/RestoreSessionTaskEntity.js +22 -0
- package/lib/Entity/StateEntityAbstract.d.ts +12 -0
- package/lib/Entity/StateEntityAbstract.js +7 -0
- package/lib/Error/AppError.d.ts +2 -0
- package/lib/Error/AppError.js +6 -0
- package/lib/Factory/CommandFactory.d.ts +42 -0
- package/lib/Factory/CommandFactory.js +79 -0
- package/lib/Factory/EntityFactory.d.ts +6 -0
- package/lib/Factory/EntityFactory.js +40 -0
- package/lib/Factory/RepositoryFactory.d.ts +3 -0
- package/lib/Factory/RepositoryFactory.js +23 -0
- package/lib/Factory/TaskFactory.d.ts +3 -0
- package/lib/Factory/TaskFactory.js +30 -0
- package/lib/JsonSchema/DefinitionEnum.d.ts +25 -0
- package/lib/JsonSchema/DefinitionEnum.js +32 -0
- package/lib/JsonSchema/JsonSchema.d.ts +4 -0
- package/lib/JsonSchema/JsonSchema.js +50 -0
- package/lib/Repository/GitRepository.d.ts +29 -0
- package/lib/Repository/GitRepository.js +237 -0
- package/lib/Repository/LocalRepository.d.ts +51 -0
- package/lib/Repository/LocalRepository.js +358 -0
- package/lib/Repository/RepositoryAbstract.d.ts +77 -0
- package/lib/Repository/RepositoryAbstract.js +19 -0
- package/lib/Repository/ResticRepository.d.ts +36 -0
- package/lib/Repository/ResticRepository.js +230 -0
- package/lib/SessionDriver/ConsoleSessionDriver.d.ts +37 -0
- package/lib/SessionDriver/ConsoleSessionDriver.js +178 -0
- package/lib/SessionDriver/SessionDriverAbstract.d.ts +78 -0
- package/lib/SessionDriver/SessionDriverAbstract.js +27 -0
- package/lib/SessionDriver/SqliteSessionDriver.d.ts +20 -0
- package/lib/SessionDriver/SqliteSessionDriver.js +169 -0
- package/lib/SessionManager/BackupSessionManager.d.ts +44 -0
- package/lib/SessionManager/BackupSessionManager.js +206 -0
- package/lib/SessionManager/RestoreSessionManager.d.ts +44 -0
- package/lib/SessionManager/RestoreSessionManager.js +206 -0
- package/lib/Task/GitTask.d.ts +35 -0
- package/lib/Task/GitTask.js +248 -0
- package/lib/Task/MariadbTask.d.ts +25 -0
- package/lib/Task/MariadbTask.js +139 -0
- package/lib/Task/MssqlTask.d.ts +22 -0
- package/lib/Task/MssqlTask.js +109 -0
- package/lib/Task/MysqlDumpTask.d.ts +14 -0
- package/lib/Task/MysqlDumpTask.js +129 -0
- package/lib/Task/PostgresqlDumpTask.d.ts +14 -0
- package/lib/Task/PostgresqlDumpTask.js +101 -0
- package/lib/Task/SqlDumpTaskAbstract.d.ts +36 -0
- package/lib/Task/SqlDumpTaskAbstract.js +146 -0
- package/lib/Task/TaskAbstract.d.ts +37 -0
- package/lib/Task/TaskAbstract.js +17 -0
- package/lib/bin.d.ts +2 -0
- package/lib/bin.js +5 -0
- package/lib/cli.d.ts +4 -0
- package/lib/cli.js +110 -0
- package/lib/index.d.ts +0 -0
- package/lib/index.js +1 -0
- package/lib/util/DataFormat.d.ts +24 -0
- package/lib/util/DataFormat.js +50 -0
- package/lib/util/GitUtil.d.ts +38 -0
- package/lib/util/GitUtil.js +105 -0
- package/lib/util/ObjectVault.d.ts +13 -0
- package/lib/util/ObjectVault.js +31 -0
- package/lib/util/ResticUtil.d.ts +92 -0
- package/lib/util/ResticUtil.js +144 -0
- package/lib/util/cli-util.d.ts +27 -0
- package/lib/util/cli-util.js +118 -0
- package/lib/util/datatruck/config-util.d.ts +55 -0
- package/lib/util/datatruck/config-util.js +93 -0
- package/lib/util/datatruck/paths-util.d.ts +5 -0
- package/lib/util/datatruck/paths-util.js +22 -0
- package/lib/util/datatruck/snapshot-util.d.ts +4 -0
- package/lib/util/datatruck/snapshot-util.js +31 -0
- package/lib/util/date-util.d.ts +12 -0
- package/lib/util/date-util.js +74 -0
- package/lib/util/entity-util.d.ts +4 -0
- package/lib/util/entity-util.js +10 -0
- package/lib/util/fs-util.d.ts +43 -0
- package/lib/util/fs-util.js +278 -0
- package/lib/util/math-util.d.ts +1 -0
- package/lib/util/math-util.js +7 -0
- package/lib/util/object-util.d.ts +7 -0
- package/lib/util/object-util.js +58 -0
- package/lib/util/process-util.d.ts +50 -0
- package/lib/util/process-util.js +181 -0
- package/lib/util/string-util.d.ts +17 -0
- package/lib/util/string-util.js +77 -0
- package/lib/util/zip-util.d.ts +52 -0
- package/lib/util/zip-util.js +135 -0
- package/migrations/001-initial.sql +122 -0
- package/package.json +62 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BackupDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
|
|
2
|
+
import { JSONSchema7 } from "json-schema";
|
|
3
|
+
export declare type GitTaskConfigType = {
|
|
4
|
+
command?: string;
|
|
5
|
+
/**
|
|
6
|
+
* @default true
|
|
7
|
+
*/
|
|
8
|
+
includeModified?: boolean | string[];
|
|
9
|
+
/**
|
|
10
|
+
* @default true
|
|
11
|
+
*/
|
|
12
|
+
includeUntracked?: boolean | string[];
|
|
13
|
+
/**
|
|
14
|
+
* @default false
|
|
15
|
+
*/
|
|
16
|
+
includeIgnored?: boolean | string[];
|
|
17
|
+
/**
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
includeConfig?: boolean;
|
|
21
|
+
};
|
|
22
|
+
export declare const gitTaskName = "git";
|
|
23
|
+
export declare const gitTaskDefinition: JSONSchema7;
|
|
24
|
+
export declare class GitTask extends TaskAbstract<GitTaskConfigType> {
|
|
25
|
+
protected verbose?: boolean;
|
|
26
|
+
private get command();
|
|
27
|
+
onBeforeBackup(): Promise<{
|
|
28
|
+
targetPath: string;
|
|
29
|
+
}>;
|
|
30
|
+
onBackup(data: BackupDataType): Promise<void>;
|
|
31
|
+
onBeforeRestore(): Promise<{
|
|
32
|
+
targetPath: string;
|
|
33
|
+
}>;
|
|
34
|
+
onRestore(data: RestoreDataType): Promise<void>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GitTask = exports.gitTaskDefinition = exports.gitTaskName = void 0;
|
|
4
|
+
const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
|
|
5
|
+
const cli_util_1 = require("../util/cli-util");
|
|
6
|
+
const fs_util_1 = require("../util/fs-util");
|
|
7
|
+
const math_util_1 = require("../util/math-util");
|
|
8
|
+
const process_util_1 = require("../util/process-util");
|
|
9
|
+
const TaskAbstract_1 = require("./TaskAbstract");
|
|
10
|
+
const assert_1 = require("assert");
|
|
11
|
+
const fs_1 = require("fs");
|
|
12
|
+
const fs_extra_1 = require("fs-extra");
|
|
13
|
+
const promises_1 = require("fs/promises");
|
|
14
|
+
const micromatch_1 = require("micromatch");
|
|
15
|
+
const path_1 = require("path");
|
|
16
|
+
const readline_1 = require("readline");
|
|
17
|
+
exports.gitTaskName = "git";
|
|
18
|
+
exports.gitTaskDefinition = {
|
|
19
|
+
type: "object",
|
|
20
|
+
additionalProperties: false,
|
|
21
|
+
properties: {
|
|
22
|
+
command: {
|
|
23
|
+
type: "string",
|
|
24
|
+
},
|
|
25
|
+
includeModified: {
|
|
26
|
+
anyOf: [
|
|
27
|
+
{
|
|
28
|
+
type: "boolean",
|
|
29
|
+
},
|
|
30
|
+
(0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
includeUntracked: {
|
|
34
|
+
anyOf: [
|
|
35
|
+
{
|
|
36
|
+
type: "boolean",
|
|
37
|
+
},
|
|
38
|
+
(0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
includeIgnored: {
|
|
42
|
+
anyOf: [
|
|
43
|
+
{
|
|
44
|
+
type: "boolean",
|
|
45
|
+
},
|
|
46
|
+
(0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
includeConfig: {
|
|
50
|
+
type: "boolean",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
class GitTask extends TaskAbstract_1.TaskAbstract {
|
|
55
|
+
get command() {
|
|
56
|
+
return this.config.command ?? "git";
|
|
57
|
+
}
|
|
58
|
+
async onBeforeBackup() {
|
|
59
|
+
return {
|
|
60
|
+
targetPath: await (0, fs_util_1.mkTmpDir)(GitTask.name),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async onBackup(data) {
|
|
64
|
+
this.verbose = data.options.verbose;
|
|
65
|
+
const config = this.config;
|
|
66
|
+
const path = data.package.path;
|
|
67
|
+
const targetPath = data.targetPath;
|
|
68
|
+
(0, assert_1.ok)(typeof path === "string");
|
|
69
|
+
(0, assert_1.ok)(typeof targetPath === "string");
|
|
70
|
+
// Bundle
|
|
71
|
+
const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
|
|
72
|
+
await (0, process_util_1.exec)(this.command, ["bundle", "create", bundlePath, "--all"], {
|
|
73
|
+
cwd: path,
|
|
74
|
+
}, {
|
|
75
|
+
log: this.verbose,
|
|
76
|
+
});
|
|
77
|
+
// Config
|
|
78
|
+
if (this.config.includeConfig ?? true) {
|
|
79
|
+
const configPath = (0, path_1.join)(targetPath, "repo.config");
|
|
80
|
+
await (0, promises_1.copyFile)((0, path_1.join)(path, ".git", "config"), configPath);
|
|
81
|
+
}
|
|
82
|
+
// git ls-files
|
|
83
|
+
const lsFilesConfig = [
|
|
84
|
+
{
|
|
85
|
+
name: "untracked",
|
|
86
|
+
argv: ["--others"],
|
|
87
|
+
include: config.includeUntracked ?? true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "modified",
|
|
91
|
+
argv: ["--modified"],
|
|
92
|
+
include: config.includeModified ?? true,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "ignored",
|
|
96
|
+
argv: ["--others", "--ignored"],
|
|
97
|
+
include: config.includeIgnored,
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
// Paths list
|
|
101
|
+
let total = 0;
|
|
102
|
+
let currentFiles = 0;
|
|
103
|
+
for (const option of lsFilesConfig) {
|
|
104
|
+
if (!option.include)
|
|
105
|
+
continue;
|
|
106
|
+
option.pathsPath = (0, path_1.join)(targetPath, `repo.${option.name}-paths.txt`);
|
|
107
|
+
const stream = (0, fs_1.createWriteStream)(option.pathsPath);
|
|
108
|
+
let streamError;
|
|
109
|
+
stream.on("error", (e) => (streamError = e));
|
|
110
|
+
try {
|
|
111
|
+
await (0, process_util_1.exec)(this.command, [
|
|
112
|
+
"-c",
|
|
113
|
+
"core.quotepath=off",
|
|
114
|
+
"ls-files",
|
|
115
|
+
...option.argv,
|
|
116
|
+
"--exclude-standard",
|
|
117
|
+
], {
|
|
118
|
+
cwd: data.package.path,
|
|
119
|
+
}, {
|
|
120
|
+
log: {
|
|
121
|
+
exec: this.verbose,
|
|
122
|
+
},
|
|
123
|
+
onSpawn: (p) => {
|
|
124
|
+
const iface = (0, readline_1.createInterface)(p.stdout, stream);
|
|
125
|
+
iface.on("close", () => stream.end());
|
|
126
|
+
iface.on("line", (path) => {
|
|
127
|
+
path = path.trim();
|
|
128
|
+
if (!path.length)
|
|
129
|
+
return;
|
|
130
|
+
let found = false;
|
|
131
|
+
if (option.include === true) {
|
|
132
|
+
found = true;
|
|
133
|
+
}
|
|
134
|
+
else if (option.include) {
|
|
135
|
+
found = (0, micromatch_1.isMatch)(path, option.include);
|
|
136
|
+
}
|
|
137
|
+
if (found) {
|
|
138
|
+
total++;
|
|
139
|
+
stream.write(`${path}\n`);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
await new Promise((resolve) => stream.end(resolve));
|
|
147
|
+
if (streamError)
|
|
148
|
+
throw streamError;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Copy
|
|
152
|
+
for (const option of lsFilesConfig) {
|
|
153
|
+
if (!option.include)
|
|
154
|
+
continue;
|
|
155
|
+
const createdPaths = [];
|
|
156
|
+
const outPath = (0, path_1.join)(targetPath, `repo.${option.name}`);
|
|
157
|
+
await (0, fs_util_1.mkdirIfNotExists)(outPath);
|
|
158
|
+
if (data.options.verbose)
|
|
159
|
+
(0, cli_util_1.logExec)(`Copying ${option.name} files to ${outPath}`);
|
|
160
|
+
const reader = (0, readline_1.createInterface)({
|
|
161
|
+
input: (0, fs_1.createReadStream)(option.pathsPath),
|
|
162
|
+
});
|
|
163
|
+
for await (const entry of reader) {
|
|
164
|
+
const source = (0, path_1.join)(path, entry);
|
|
165
|
+
const target = (0, path_1.join)(outPath, entry);
|
|
166
|
+
if (entry.endsWith("/")) {
|
|
167
|
+
await (0, promises_1.mkdir)(target, {
|
|
168
|
+
recursive: true,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
currentFiles++;
|
|
173
|
+
await data.onProgress({
|
|
174
|
+
total,
|
|
175
|
+
current: currentFiles,
|
|
176
|
+
percent: (0, math_util_1.progressPercent)(total, currentFiles),
|
|
177
|
+
step: entry,
|
|
178
|
+
});
|
|
179
|
+
const dir = (0, path_1.dirname)(target);
|
|
180
|
+
if (!createdPaths.includes(dir)) {
|
|
181
|
+
await (0, promises_1.mkdir)(dir, {
|
|
182
|
+
recursive: true,
|
|
183
|
+
});
|
|
184
|
+
createdPaths.push(dir);
|
|
185
|
+
}
|
|
186
|
+
await (0, promises_1.copyFile)(source, target);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
await (0, promises_1.rm)(option.pathsPath);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async onBeforeRestore() {
|
|
193
|
+
return {
|
|
194
|
+
targetPath: await (0, fs_util_1.mkTmpDir)(GitTask.name),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async onRestore(data) {
|
|
198
|
+
this.verbose = data.options.verbose;
|
|
199
|
+
const restorePath = data.package.restorePath;
|
|
200
|
+
const targetPath = data.targetPath;
|
|
201
|
+
(0, assert_1.ok)(typeof restorePath === "string");
|
|
202
|
+
(0, assert_1.ok)(typeof targetPath === "string");
|
|
203
|
+
await (0, fs_util_1.mkdirIfNotExists)(restorePath);
|
|
204
|
+
await (0, fs_util_1.ensureEmptyDir)(restorePath);
|
|
205
|
+
// Stats
|
|
206
|
+
let totalFiles = 0;
|
|
207
|
+
let currentFiles = 0;
|
|
208
|
+
await (0, fs_util_1.forEachFile)(targetPath, () => totalFiles++, true);
|
|
209
|
+
const incrementProgress = async (step = "") => {
|
|
210
|
+
await data.onProgress({
|
|
211
|
+
total: totalFiles,
|
|
212
|
+
current: Math.max(currentFiles, 0),
|
|
213
|
+
percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
|
|
214
|
+
step,
|
|
215
|
+
});
|
|
216
|
+
currentFiles++;
|
|
217
|
+
};
|
|
218
|
+
// Bundle
|
|
219
|
+
const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
|
|
220
|
+
await (0, process_util_1.exec)(this.command, ["clone", bundlePath, "."], {
|
|
221
|
+
cwd: restorePath,
|
|
222
|
+
}, {
|
|
223
|
+
log: this.verbose,
|
|
224
|
+
});
|
|
225
|
+
await incrementProgress();
|
|
226
|
+
// Config
|
|
227
|
+
const configPath = (0, path_1.join)(targetPath, "repo.config");
|
|
228
|
+
if (await (0, fs_util_1.checkFile)(configPath)) {
|
|
229
|
+
await (0, promises_1.copyFile)(configPath, (0, path_1.join)(restorePath, ".git", "config"));
|
|
230
|
+
await incrementProgress();
|
|
231
|
+
}
|
|
232
|
+
// ls-files
|
|
233
|
+
for (const name of ["untracked", "modified", "ignored"]) {
|
|
234
|
+
const sourcePath = (0, path_1.join)(targetPath, `repo.${name}`);
|
|
235
|
+
if (await (0, fs_util_1.checkDir)(sourcePath)) {
|
|
236
|
+
if (data.options.verbose)
|
|
237
|
+
(0, cli_util_1.logExec)(`Copying ${name} files to ${restorePath}`);
|
|
238
|
+
await (0, fs_extra_1.copy)(sourcePath, restorePath, {
|
|
239
|
+
filter: async (path) => {
|
|
240
|
+
await incrementProgress((0, path_1.relative)(sourcePath, path));
|
|
241
|
+
return true;
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
exports.GitTask = GitTask;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BackupDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
|
|
2
|
+
import { JSONSchema7 } from "json-schema";
|
|
3
|
+
export declare type MariadbTaskConfigType = {
|
|
4
|
+
command?: string;
|
|
5
|
+
hostname: string;
|
|
6
|
+
username: string;
|
|
7
|
+
password: string | {
|
|
8
|
+
path: string;
|
|
9
|
+
};
|
|
10
|
+
includeTables?: string[];
|
|
11
|
+
excludeTables?: string[];
|
|
12
|
+
includeDatabases?: string[];
|
|
13
|
+
excludeDatabases?: string[];
|
|
14
|
+
};
|
|
15
|
+
export declare const mariadbTaskName = "mariadb";
|
|
16
|
+
export declare const mariadbTaskDefinition: JSONSchema7;
|
|
17
|
+
export declare class MariadbTask extends TaskAbstract<MariadbTaskConfigType> {
|
|
18
|
+
protected verbose?: boolean;
|
|
19
|
+
private get command();
|
|
20
|
+
onBeforeBackup(): Promise<{
|
|
21
|
+
targetPath: string;
|
|
22
|
+
}>;
|
|
23
|
+
onBackup(data: BackupDataType): Promise<void>;
|
|
24
|
+
onRestore(data: RestoreDataType): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MariadbTask = exports.mariadbTaskDefinition = exports.mariadbTaskName = void 0;
|
|
4
|
+
const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
|
|
5
|
+
const cli_util_1 = require("../util/cli-util");
|
|
6
|
+
const fs_util_1 = require("../util/fs-util");
|
|
7
|
+
const math_util_1 = require("../util/math-util");
|
|
8
|
+
const process_util_1 = require("../util/process-util");
|
|
9
|
+
const TaskAbstract_1 = require("./TaskAbstract");
|
|
10
|
+
const assert_1 = require("assert");
|
|
11
|
+
const promises_1 = require("fs/promises");
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
const posix_1 = require("path/posix");
|
|
14
|
+
exports.mariadbTaskName = "mariadb";
|
|
15
|
+
exports.mariadbTaskDefinition = {
|
|
16
|
+
type: "object",
|
|
17
|
+
required: ["hostname", "username", "password"],
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
properties: {
|
|
20
|
+
command: { type: "string" },
|
|
21
|
+
hostname: { type: "string" },
|
|
22
|
+
username: { type: "string" },
|
|
23
|
+
password: {
|
|
24
|
+
anyOf: [
|
|
25
|
+
{
|
|
26
|
+
type: "string",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
type: "object",
|
|
30
|
+
additionalProperties: false,
|
|
31
|
+
required: ["path"],
|
|
32
|
+
properties: {
|
|
33
|
+
path: { type: "string" },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
includeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
39
|
+
excludeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
40
|
+
includeDatabases: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
41
|
+
excludeDatabases: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
class MariadbTask extends TaskAbstract_1.TaskAbstract {
|
|
45
|
+
get command() {
|
|
46
|
+
return this.config.command ?? "mariabackup";
|
|
47
|
+
}
|
|
48
|
+
async onBeforeBackup() {
|
|
49
|
+
return {
|
|
50
|
+
targetPath: await (0, fs_util_1.mkTmpDir)(MariadbTask.name),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async onBackup(data) {
|
|
54
|
+
this.verbose = data.options.verbose;
|
|
55
|
+
const config = this.config;
|
|
56
|
+
const command = this.command;
|
|
57
|
+
const sourcePath = data.package.path;
|
|
58
|
+
const targetPath = data.targetPath;
|
|
59
|
+
(0, assert_1.ok)(typeof sourcePath === "string");
|
|
60
|
+
(0, assert_1.ok)(typeof targetPath === "string");
|
|
61
|
+
const args = [
|
|
62
|
+
`--backup`,
|
|
63
|
+
`--datadir=${sourcePath}`,
|
|
64
|
+
`--target-dir=${targetPath}`,
|
|
65
|
+
`--host=${config.hostname}`,
|
|
66
|
+
`--user=${config.username}`,
|
|
67
|
+
`--password=${typeof config.password === "string"
|
|
68
|
+
? config.password
|
|
69
|
+
: config.password
|
|
70
|
+
? (await (0, promises_1.readFile)(config.password.path)).toString()
|
|
71
|
+
: ""}`,
|
|
72
|
+
];
|
|
73
|
+
if (config.includeDatabases)
|
|
74
|
+
args.push(`--databases=${config.includeDatabases.join(" ")}`);
|
|
75
|
+
if (config.excludeDatabases)
|
|
76
|
+
args.push(`--databases-exclude=${config.excludeDatabases.join(" ")}`);
|
|
77
|
+
if (config.includeTables)
|
|
78
|
+
args.push(`--tables=^(${config.includeTables.join("|")})$`);
|
|
79
|
+
if (config.excludeTables)
|
|
80
|
+
args.push(`--tables-exclude=^(${config.excludeTables.join("|")})$`);
|
|
81
|
+
let total = 0;
|
|
82
|
+
let current = 0;
|
|
83
|
+
await (0, fs_util_1.forEachFile)(sourcePath, () => {
|
|
84
|
+
total++;
|
|
85
|
+
});
|
|
86
|
+
const onData = async (lines) => {
|
|
87
|
+
const regex = /\[\d{1,}\] \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} Copying (.+) to/;
|
|
88
|
+
let path = lines
|
|
89
|
+
.split(/\r?\n/)
|
|
90
|
+
.reduce((result, line) => {
|
|
91
|
+
const matches = regex.exec(line);
|
|
92
|
+
if (matches) {
|
|
93
|
+
current++;
|
|
94
|
+
result.push(matches[1]);
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}, [])
|
|
98
|
+
.pop();
|
|
99
|
+
if (path) {
|
|
100
|
+
path = (0, posix_1.normalize)(path);
|
|
101
|
+
await data.onProgress({
|
|
102
|
+
current,
|
|
103
|
+
percent: (0, math_util_1.progressPercent)(total, current),
|
|
104
|
+
total,
|
|
105
|
+
step: `Copying ${path}`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
await (0, process_util_1.exec)(command, args, undefined, {
|
|
110
|
+
log: this.verbose,
|
|
111
|
+
stdout: {
|
|
112
|
+
onData,
|
|
113
|
+
},
|
|
114
|
+
stderr: {
|
|
115
|
+
onData,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
await (0, process_util_1.exec)(command, [`--prepare`, `--target-dir=${targetPath}`], undefined, {
|
|
119
|
+
log: this.verbose,
|
|
120
|
+
stderr: { onData: async () => { } },
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
async onRestore(data) {
|
|
124
|
+
this.verbose = data.options.verbose;
|
|
125
|
+
const restorePath = data.package.restorePath;
|
|
126
|
+
(0, assert_1.ok)(typeof restorePath === "string");
|
|
127
|
+
await (0, fs_util_1.mkdirIfNotExists)(restorePath);
|
|
128
|
+
const files = await (0, promises_1.readdir)(restorePath);
|
|
129
|
+
for (const file of files) {
|
|
130
|
+
if (file.startsWith("ib_logfile")) {
|
|
131
|
+
const filePath = (0, path_1.join)(restorePath, file);
|
|
132
|
+
if (this.verbose)
|
|
133
|
+
(0, cli_util_1.logExec)("rm", [filePath]);
|
|
134
|
+
await (0, promises_1.rm)(filePath);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.MariadbTask = MariadbTask;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BackupDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
|
|
2
|
+
import { JSONSchema7 } from "json-schema";
|
|
3
|
+
export declare type MssqlTaskConfigType = {
|
|
4
|
+
command?: string;
|
|
5
|
+
hostname?: string;
|
|
6
|
+
username?: string;
|
|
7
|
+
passwordFile?: string;
|
|
8
|
+
targetDatabase?: string;
|
|
9
|
+
includeDatabases?: string[];
|
|
10
|
+
excludeDatabases?: string[];
|
|
11
|
+
};
|
|
12
|
+
export declare const mssqlTaskName = "mssql";
|
|
13
|
+
export declare const mssqlTaskDefinition: JSONSchema7;
|
|
14
|
+
export declare class MssqlTask extends TaskAbstract<MssqlTaskConfigType> {
|
|
15
|
+
static SUFFIX: string;
|
|
16
|
+
protected verbose?: boolean;
|
|
17
|
+
private get command();
|
|
18
|
+
exec(query: string): Promise<string[][]>;
|
|
19
|
+
fetchDatabaseNames(name?: string): Promise<string[]>;
|
|
20
|
+
onBackup(data: BackupDataType): Promise<void>;
|
|
21
|
+
onRestore(data: RestoreDataType): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MssqlTask = exports.mssqlTaskDefinition = exports.mssqlTaskName = void 0;
|
|
4
|
+
const AppError_1 = require("../Error/AppError");
|
|
5
|
+
const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
|
|
6
|
+
const config_util_1 = require("../util/datatruck/config-util");
|
|
7
|
+
const fs_util_1 = require("../util/fs-util");
|
|
8
|
+
const process_util_1 = require("../util/process-util");
|
|
9
|
+
const TaskAbstract_1 = require("./TaskAbstract");
|
|
10
|
+
const assert_1 = require("assert");
|
|
11
|
+
const fs_extra_1 = require("fs-extra");
|
|
12
|
+
const promises_1 = require("fs/promises");
|
|
13
|
+
const micromatch_1 = require("micromatch");
|
|
14
|
+
const path_1 = require("path");
|
|
15
|
+
exports.mssqlTaskName = "mssql";
|
|
16
|
+
exports.mssqlTaskDefinition = {
|
|
17
|
+
type: "object",
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
properties: {
|
|
20
|
+
command: { type: "string" },
|
|
21
|
+
hostname: { type: "string" },
|
|
22
|
+
username: { type: "string" },
|
|
23
|
+
passwordFile: { type: "string" },
|
|
24
|
+
includeDatabases: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
25
|
+
excludeDatabases: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
class MssqlTask extends TaskAbstract_1.TaskAbstract {
|
|
29
|
+
get command() {
|
|
30
|
+
return this.config.command ?? "sqlcmd";
|
|
31
|
+
}
|
|
32
|
+
async exec(query) {
|
|
33
|
+
const result = await (0, process_util_1.exec)(this.command, [
|
|
34
|
+
...(this.config.hostname ? ["-S", this.config.hostname] : []),
|
|
35
|
+
...(this.config.username ? ["-U", this.config.username] : []),
|
|
36
|
+
...(this.config.passwordFile
|
|
37
|
+
? ["-P", (await (0, promises_1.readFile)(this.config.passwordFile)).toString()]
|
|
38
|
+
: []),
|
|
39
|
+
"-E",
|
|
40
|
+
"-W",
|
|
41
|
+
"-s",
|
|
42
|
+
",",
|
|
43
|
+
"-w",
|
|
44
|
+
"999",
|
|
45
|
+
"-Q",
|
|
46
|
+
`SET nocount ON; ${query.replace(/[\n\t]/g, " ")}`,
|
|
47
|
+
], undefined, {
|
|
48
|
+
log: this.verbose,
|
|
49
|
+
stderr: {
|
|
50
|
+
toExitCode: true,
|
|
51
|
+
},
|
|
52
|
+
stdout: {
|
|
53
|
+
save: true,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
return result.stdout
|
|
57
|
+
.split(/\n/g)
|
|
58
|
+
.map((row) => row.split(","))
|
|
59
|
+
.filter((row) => row.length);
|
|
60
|
+
}
|
|
61
|
+
async fetchDatabaseNames(name) {
|
|
62
|
+
const query = `SELECT name FROM master.dbo.sysdatabases ${name ? `WHERE name = '${name}'` : ""}`;
|
|
63
|
+
const rows = await this.exec(query);
|
|
64
|
+
const privateDatabases = ["master", "tempdb", "model", "msdb"];
|
|
65
|
+
return rows
|
|
66
|
+
.map(([database]) => database)
|
|
67
|
+
.filter((database) => !privateDatabases.includes(database));
|
|
68
|
+
}
|
|
69
|
+
async onBackup(data) {
|
|
70
|
+
this.verbose = data.options.verbose;
|
|
71
|
+
const targetPath = data.package.path;
|
|
72
|
+
(0, assert_1.ok)(typeof targetPath === "string");
|
|
73
|
+
const databaseNames = (await this.fetchDatabaseNames()).filter((databaseName) => (!this.config.includeDatabases ||
|
|
74
|
+
(0, micromatch_1.isMatch)(databaseName, this.config.includeDatabases)) &&
|
|
75
|
+
(!this.config.excludeDatabases ||
|
|
76
|
+
!(0, micromatch_1.isMatch)(databaseName, this.config.excludeDatabases)));
|
|
77
|
+
await (0, fs_util_1.mkdirIfNotExists)(targetPath);
|
|
78
|
+
for (const databaseName of databaseNames) {
|
|
79
|
+
const databasePath = (0, path_1.join)(targetPath, `${databaseName}${MssqlTask.SUFFIX}`);
|
|
80
|
+
await this.exec(`BACKUP DATABASE [${databaseName}] TO DISK='${databasePath}' WITH FORMAT`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async onRestore(data) {
|
|
84
|
+
this.verbose = data.options.verbose;
|
|
85
|
+
const restorePath = data.package.restorePath;
|
|
86
|
+
(0, assert_1.ok)(typeof restorePath === "string");
|
|
87
|
+
await (0, fs_util_1.mkdirIfNotExists)(restorePath);
|
|
88
|
+
const files = await (0, fs_extra_1.readdir)(restorePath);
|
|
89
|
+
for (const file of files) {
|
|
90
|
+
if (!file.endsWith(MssqlTask.SUFFIX))
|
|
91
|
+
continue;
|
|
92
|
+
let databaseName = file.slice(0, MssqlTask.SUFFIX.length * -1);
|
|
93
|
+
if (this.config.targetDatabase)
|
|
94
|
+
databaseName = (0, config_util_1.resolveDatabaseName)(this.config.targetDatabase, {
|
|
95
|
+
action: "restore",
|
|
96
|
+
database: databaseName,
|
|
97
|
+
packageName: data.package.name,
|
|
98
|
+
snapshotId: data.options.snapshotId,
|
|
99
|
+
});
|
|
100
|
+
const databasePath = (0, path_1.join)(restorePath, file);
|
|
101
|
+
const exists = await this.fetchDatabaseNames(databaseName);
|
|
102
|
+
if (exists.length)
|
|
103
|
+
throw new AppError_1.AppError(`Target database already exists: ${databaseName}`);
|
|
104
|
+
await this.exec(`RESTORE DATABASE [${databaseName}] FROM disk='${databasePath}'`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.MssqlTask = MssqlTask;
|
|
109
|
+
MssqlTask.SUFFIX = ".BAK";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SqlDumpTaskAbstract, SqlDumpTaskConfigType, TargetDatabaseType } from "./SqlDumpTaskAbstract";
|
|
2
|
+
import { JSONSchema7 } from "json-schema";
|
|
3
|
+
export declare const mysqlDumpTaskName = "mysql-dump";
|
|
4
|
+
export declare type MysqlDumpTaskConfigType = {} & SqlDumpTaskConfigType;
|
|
5
|
+
export declare const mysqlDumpTaskDefinition: JSONSchema7;
|
|
6
|
+
export declare class MysqlDumpTask extends SqlDumpTaskAbstract<MysqlDumpTaskConfigType> {
|
|
7
|
+
buildConnectionArgs(database?: boolean): Promise<string[]>;
|
|
8
|
+
onDatabaseIsEmpty(name: string): Promise<boolean>;
|
|
9
|
+
onCreateDatabase(database: TargetDatabaseType): Promise<void>;
|
|
10
|
+
onExecQuery(query: string): Promise<import("../util/process-util").ExecResultType>;
|
|
11
|
+
onFetchTableNames(): Promise<string[]>;
|
|
12
|
+
onExport(tableNames: string[], output: string): Promise<void>;
|
|
13
|
+
onImport(path: string, database: string): Promise<void>;
|
|
14
|
+
}
|