@datatruck/cli 0.32.3 → 0.34.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 +377 -31
- package/lib/{Action → actions}/BackupAction.d.ts +13 -19
- package/lib/{Action → actions}/BackupAction.js +52 -91
- package/lib/{Action → actions}/ConfigAction.d.ts +4 -2
- package/lib/{Action → actions}/ConfigAction.js +16 -8
- package/lib/{Action → actions}/CopyAction.d.ts +20 -13
- package/lib/actions/CopyAction.js +296 -0
- package/lib/{Action → actions}/InitAction.d.ts +1 -1
- package/lib/{Action → actions}/InitAction.js +3 -3
- package/lib/{Action → actions}/PruneAction.d.ts +1 -2
- package/lib/{Action → actions}/PruneAction.js +2 -2
- package/lib/{Action → actions}/RestoreAction.d.ts +4 -13
- package/lib/{Action → actions}/RestoreAction.js +17 -17
- package/lib/{Action → actions}/SnapshotsAction.d.ts +2 -3
- package/lib/{Action → actions}/SnapshotsAction.js +3 -3
- package/lib/cli.d.ts +3 -3
- package/lib/cli.js +18 -17
- package/lib/commands/BackupCommand.d.ts +45 -0
- package/lib/{Command → commands}/BackupCommand.js +7 -6
- package/lib/{Command → commands}/CleanCacheCommand.d.ts +4 -2
- package/lib/{Command → commands}/CleanCacheCommand.js +6 -5
- package/lib/{Command → commands}/CommandAbstract.d.ts +10 -6
- package/lib/{Command → commands}/CommandAbstract.js +5 -3
- package/lib/commands/ConfigCommand.d.ts +22 -0
- package/lib/{Command → commands}/ConfigCommand.js +5 -5
- package/lib/commands/CopyCommand.d.ts +17 -0
- package/lib/{Command → commands}/CopyCommand.js +7 -6
- package/lib/commands/InitCommand.d.ts +19 -0
- package/lib/{Command → commands}/InitCommand.js +9 -9
- package/lib/{Command → commands}/PruneCommand.d.ts +7 -4
- package/lib/{Command → commands}/PruneCommand.js +11 -11
- package/lib/commands/RestoreCommand.d.ts +38 -0
- package/lib/{Command → commands}/RestoreCommand.js +7 -6
- package/lib/{Command → commands}/SnapshotsCommand.d.ts +8 -6
- package/lib/{Command → commands}/SnapshotsCommand.js +12 -12
- package/lib/{Command → commands}/StartServerCommand.d.ts +4 -2
- package/lib/{Command → commands}/StartServerCommand.js +5 -5
- package/lib/index.d.ts +20 -23
- package/lib/index.js +8 -8
- package/lib/{Repository → repositories}/DatatruckRepository.d.ts +6 -2
- package/lib/{Repository → repositories}/DatatruckRepository.js +13 -5
- package/lib/{Repository → repositories}/GitRepository.d.ts +6 -2
- package/lib/{Repository → repositories}/GitRepository.js +8 -3
- package/lib/{Repository → repositories}/RepositoryAbstract.d.ts +13 -9
- package/lib/{Repository → repositories}/ResticRepository.d.ts +6 -2
- package/lib/{Repository → repositories}/ResticRepository.js +17 -10
- package/lib/{Task → tasks}/MssqlTask.js +2 -2
- package/lib/{Task → tasks}/MysqlDumpTask.js +4 -4
- package/lib/{Task → tasks}/ScriptTask.d.ts +2 -2
- package/lib/{Task → tasks}/SqlDumpTaskAbstract.js +4 -4
- package/lib/{Task → tasks}/TaskAbstract.d.ts +4 -4
- package/lib/utils/DataFormat.js +3 -3
- package/lib/utils/Restic.d.ts +2 -2
- package/lib/utils/Restic.js +12 -10
- package/lib/utils/cli.d.ts +9 -3
- package/lib/utils/cli.js +17 -1
- package/lib/utils/cron.d.ts +11 -0
- package/lib/utils/cron.js +27 -0
- package/lib/utils/datatruck/client.d.ts +3 -1
- package/lib/utils/datatruck/client.js +1 -1
- package/lib/utils/datatruck/command.d.ts +29 -0
- package/lib/utils/datatruck/command.js +61 -0
- package/lib/{Config/RepositoryConfig.d.ts → utils/datatruck/config-repository-type.d.ts} +19 -8
- package/lib/{Config/TaskConfig.d.ts → utils/datatruck/config-task-type.d.ts} +6 -6
- package/lib/utils/datatruck/config-type.d.ts +51 -0
- package/lib/utils/datatruck/config.d.ts +19 -10
- package/lib/utils/datatruck/config.js +43 -7
- package/lib/utils/datatruck/cron-server.d.ts +27 -6
- package/lib/utils/datatruck/cron-server.js +38 -20
- package/lib/utils/datatruck/paths.d.ts +2 -2
- package/lib/utils/datatruck/report-list.d.ts +14 -0
- package/lib/utils/datatruck/report-list.js +57 -0
- package/lib/utils/datatruck/repository-server.js +3 -2
- package/lib/utils/datatruck/repository.d.ts +16 -0
- package/lib/utils/datatruck/repository.js +30 -0
- package/lib/utils/datatruck/snapshot.d.ts +2 -2
- package/lib/utils/datatruck/task.d.ts +3 -0
- package/lib/{Factory/TaskFactory.js → utils/datatruck/task.js} +8 -8
- package/lib/utils/date.js +6 -2
- package/lib/utils/fs.d.ts +3 -0
- package/lib/utils/fs.js +24 -4
- package/lib/utils/http.d.ts +3 -1
- package/lib/utils/http.js +6 -1
- package/lib/utils/list.d.ts +5 -5
- package/lib/utils/mysql.js +5 -5
- package/lib/utils/object.d.ts +13 -0
- package/lib/utils/object.js +32 -1
- package/lib/utils/process.js +4 -1
- package/lib/utils/string.d.ts +1 -0
- package/lib/utils/string.js +7 -3
- package/lib/utils/ts.d.ts +16 -0
- package/lib/utils/virtual-fs.d.ts +6 -2
- package/lib/utils/virtual-fs.js +4 -1
- package/lib/utils/watcher.d.ts +10 -0
- package/lib/utils/watcher.js +34 -0
- package/package.json +4 -4
- package/lib/Action/CopyAction.js +0 -164
- package/lib/Command/BackupCommand.d.ts +0 -19
- package/lib/Command/ConfigCommand.d.ts +0 -15
- package/lib/Command/CopyCommand.d.ts +0 -16
- package/lib/Command/InitCommand.d.ts +0 -13
- package/lib/Command/RestoreCommand.d.ts +0 -17
- package/lib/Config/Config.d.ts +0 -28
- package/lib/Config/PackageConfig.d.ts +0 -24
- package/lib/Config/PackageRepositoryConfig.d.ts +0 -15
- package/lib/Config/PrunePolicyConfig.d.ts +0 -2
- package/lib/Config/RepositoryConfig.js +0 -2
- package/lib/Config/TaskConfig.js +0 -2
- package/lib/Factory/CommandFactory.d.ts +0 -45
- package/lib/Factory/CommandFactory.js +0 -96
- package/lib/Factory/RepositoryFactory.d.ts +0 -3
- package/lib/Factory/RepositoryFactory.js +0 -23
- package/lib/Factory/TaskFactory.d.ts +0 -3
- /package/lib/{Action → actions}/CleanCacheAction.d.ts +0 -0
- /package/lib/{Action → actions}/CleanCacheAction.js +0 -0
- /package/lib/{Repository → repositories}/RepositoryAbstract.js +0 -0
- /package/lib/{Task → tasks}/GitTask.d.ts +0 -0
- /package/lib/{Task → tasks}/GitTask.js +0 -0
- /package/lib/{Task → tasks}/MariadbTask.d.ts +0 -0
- /package/lib/{Task → tasks}/MariadbTask.js +0 -0
- /package/lib/{Task → tasks}/MssqlTask.d.ts +0 -0
- /package/lib/{Task → tasks}/MysqlDumpTask.d.ts +0 -0
- /package/lib/{Task → tasks}/PostgresqlDumpTask.d.ts +0 -0
- /package/lib/{Task → tasks}/PostgresqlDumpTask.js +0 -0
- /package/lib/{Task → tasks}/ScriptTask.js +0 -0
- /package/lib/{Task → tasks}/SqlDumpTaskAbstract.d.ts +0 -0
- /package/lib/{Task → tasks}/TaskAbstract.js +0 -0
- /package/lib/{Config/Config.js → utils/datatruck/config-repository-type.js} +0 -0
- /package/lib/{Config/PackageConfig.js → utils/datatruck/config-task-type.js} +0 -0
- /package/lib/{Config/PackageRepositoryConfig.js → utils/datatruck/config-type.js} +0 -0
- /package/lib/{Error/AppError.d.ts → utils/datatruck/error.d.ts} +0 -0
- /package/lib/{Error/AppError.js → utils/datatruck/error.js} +0 -0
- /package/lib/{Config/PrunePolicyConfig.js → utils/ts.js} +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DatatruckRepository } from "../../repositories/DatatruckRepository";
|
|
2
|
+
import { GitRepository } from "../../repositories/GitRepository";
|
|
3
|
+
import type { RepositoryAbstract } from "../../repositories/RepositoryAbstract";
|
|
4
|
+
import { ResticRepository } from "../../repositories/ResticRepository";
|
|
5
|
+
import type { RepositoryConfig } from "./config-type";
|
|
6
|
+
declare const repoMap: {
|
|
7
|
+
git: typeof GitRepository;
|
|
8
|
+
restic: typeof ResticRepository;
|
|
9
|
+
datatruck: typeof DatatruckRepository;
|
|
10
|
+
};
|
|
11
|
+
export declare function getRepoConstructor(type: keyof typeof repoMap): {
|
|
12
|
+
new (config: RepositoryConfig): RepositoryAbstract<any>;
|
|
13
|
+
};
|
|
14
|
+
export declare function createRepo(repository: RepositoryConfig): RepositoryAbstract<any>;
|
|
15
|
+
export declare function createAndInitRepo(repository: RepositoryConfig, verbose?: boolean): Promise<RepositoryAbstract<any>>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAndInitRepo = exports.createRepo = exports.getRepoConstructor = void 0;
|
|
4
|
+
const DatatruckRepository_1 = require("../../repositories/DatatruckRepository");
|
|
5
|
+
const GitRepository_1 = require("../../repositories/GitRepository");
|
|
6
|
+
const ResticRepository_1 = require("../../repositories/ResticRepository");
|
|
7
|
+
const error_1 = require("./error");
|
|
8
|
+
const repoMap = {
|
|
9
|
+
[GitRepository_1.gitRepositoryName]: GitRepository_1.GitRepository,
|
|
10
|
+
[ResticRepository_1.resticRepositoryName]: ResticRepository_1.ResticRepository,
|
|
11
|
+
[DatatruckRepository_1.datatruckRepositoryName]: DatatruckRepository_1.DatatruckRepository,
|
|
12
|
+
};
|
|
13
|
+
function getRepoConstructor(type) {
|
|
14
|
+
const Constructor = repoMap[type];
|
|
15
|
+
if (!Constructor)
|
|
16
|
+
throw new error_1.AppError(`Invalid repository type: ${type}`);
|
|
17
|
+
return Constructor;
|
|
18
|
+
}
|
|
19
|
+
exports.getRepoConstructor = getRepoConstructor;
|
|
20
|
+
function createRepo(repository) {
|
|
21
|
+
const Constructor = getRepoConstructor(repository.type);
|
|
22
|
+
return new Constructor(repository);
|
|
23
|
+
}
|
|
24
|
+
exports.createRepo = createRepo;
|
|
25
|
+
async function createAndInitRepo(repository, verbose) {
|
|
26
|
+
const repo = createRepo(repository);
|
|
27
|
+
await repo.init({ options: { verbose } });
|
|
28
|
+
return repo;
|
|
29
|
+
}
|
|
30
|
+
exports.createAndInitRepo = createAndInitRepo;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SnapshotGroupByType } from "../../
|
|
2
|
-
import { Snapshot } from "../../
|
|
1
|
+
import { SnapshotGroupByType } from "../../actions/SnapshotsAction";
|
|
2
|
+
import { Snapshot } from "../../repositories/RepositoryAbstract";
|
|
3
3
|
import { FilterByLastOptions } from "../date";
|
|
4
4
|
export declare function groupAndFilter<TSnapshot extends Snapshot>(snapshots: TSnapshot[], groupKeys?: SnapshotGroupByType[], inFilter?: FilterByLastOptions | ((group: TSnapshot[]) => FilterByLastOptions | string)): {
|
|
5
5
|
item: TSnapshot;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createTask = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
4
|
+
const GitTask_1 = require("../../tasks/GitTask");
|
|
5
|
+
const MariadbTask_1 = require("../../tasks/MariadbTask");
|
|
6
|
+
const MssqlTask_1 = require("../../tasks/MssqlTask");
|
|
7
|
+
const MysqlDumpTask_1 = require("../../tasks/MysqlDumpTask");
|
|
8
|
+
const PostgresqlDumpTask_1 = require("../../tasks/PostgresqlDumpTask");
|
|
9
|
+
const ScriptTask_1 = require("../../tasks/ScriptTask");
|
|
10
|
+
const error_1 = require("./error");
|
|
11
11
|
function createTask(task) {
|
|
12
12
|
if (task.name === GitTask_1.gitTaskName) {
|
|
13
13
|
return new GitTask_1.GitTask(task.config ?? {});
|
|
@@ -28,7 +28,7 @@ function createTask(task) {
|
|
|
28
28
|
return new ScriptTask_1.ScriptTask(task.config ?? {});
|
|
29
29
|
}
|
|
30
30
|
else {
|
|
31
|
-
throw new
|
|
31
|
+
throw new error_1.AppError(`Invalid task name: ${task["name"]}`);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
exports.createTask = createTask;
|
package/lib/utils/date.js
CHANGED
|
@@ -27,7 +27,10 @@ function createFilterByLastOptions(keep) {
|
|
|
27
27
|
exports.createFilterByLastOptions = createFilterByLastOptions;
|
|
28
28
|
function filterByLast(items, options) {
|
|
29
29
|
const filters = {
|
|
30
|
-
last: {
|
|
30
|
+
last: {
|
|
31
|
+
handler: (_, i) => i.toString(),
|
|
32
|
+
value: options.last,
|
|
33
|
+
},
|
|
31
34
|
lastMinutely: {
|
|
32
35
|
handler: (d) => d.format("YYYYMMDDHHmm"),
|
|
33
36
|
value: options.lastMinutely,
|
|
@@ -53,7 +56,8 @@ function filterByLast(items, options) {
|
|
|
53
56
|
let someFilter = false;
|
|
54
57
|
for (const key in filters) {
|
|
55
58
|
const object = filters[key];
|
|
56
|
-
if (object?.value
|
|
59
|
+
if (object?.value ||
|
|
60
|
+
(key === "last" && typeof object?.value === "number")) {
|
|
57
61
|
someFilter = true;
|
|
58
62
|
}
|
|
59
63
|
}
|
package/lib/utils/fs.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare function existsDir(path: string): Promise<boolean>;
|
|
|
18
18
|
export declare function existsFile(path: string): Promise<boolean>;
|
|
19
19
|
export declare function writeJSONFile<T = any>(path: string, json: T): Promise<void>;
|
|
20
20
|
export declare const parseFileExtensions: string[];
|
|
21
|
+
export declare function include(path: string): any;
|
|
21
22
|
export declare function parseFile(path: string, jsKey?: string): Promise<any>;
|
|
22
23
|
export declare function parsePackageFile(): {
|
|
23
24
|
name: string;
|
|
@@ -41,6 +42,8 @@ export declare function waitForClose(stream: WriteStream | ReadStream): Promise<
|
|
|
41
42
|
export declare function copyFileWithStreams(source: string, target: string): Promise<unknown>;
|
|
42
43
|
export declare function updateFileStats(path: string, fileInfo: Stats): Promise<void>;
|
|
43
44
|
export declare function isNotFoundError(error: unknown): boolean;
|
|
45
|
+
export declare function readTextFile(path: string): Promise<string>;
|
|
46
|
+
export declare function readTextFile(path: string, onlyIfExists: true): Promise<string | undefined>;
|
|
44
47
|
export declare function cpy(options: {
|
|
45
48
|
input: {
|
|
46
49
|
type: "glob";
|
package/lib/utils/fs.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.asFile = exports.groupFiles = exports.ensureFreeDiskSpace = exports.checkFreeDiskSpace = exports.fetchDiskStats = exports.initEmptyDir = exports.tryRm = exports.safeRename = exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.createProgress = exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.fastFolderSizeAsync = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureExistsDir = exports.ensureSingleFile = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
|
|
6
|
+
exports.asFile = exports.groupFiles = exports.ensureFreeDiskSpace = exports.checkFreeDiskSpace = exports.fetchDiskStats = exports.initEmptyDir = exports.tryRm = exports.safeRename = exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.createProgress = exports.cpy = exports.readTextFile = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.fastFolderSizeAsync = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.include = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureExistsDir = exports.ensureSingleFile = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
|
|
7
7
|
const pkg_1 = require("../pkg");
|
|
8
8
|
const bytes_1 = require("./bytes");
|
|
9
9
|
const math_1 = require("./math");
|
|
@@ -20,6 +20,7 @@ const path_1 = require("path");
|
|
|
20
20
|
const path_2 = require("path");
|
|
21
21
|
const readline_1 = require("readline");
|
|
22
22
|
const util_1 = require("util");
|
|
23
|
+
const yaml_1 = require("yaml");
|
|
23
24
|
exports.isWSLSystem = (0, os_1.release)().includes("microsoft-standard-WSL");
|
|
24
25
|
async function isEmptyDir(path) {
|
|
25
26
|
const iterator = await (0, promises_1.opendir)(path);
|
|
@@ -87,6 +88,12 @@ async function writeJSONFile(path, json) {
|
|
|
87
88
|
}
|
|
88
89
|
exports.writeJSONFile = writeJSONFile;
|
|
89
90
|
exports.parseFileExtensions = ["json", "js", "ts", "yaml", "yml"];
|
|
91
|
+
function include(path) {
|
|
92
|
+
path = (0, path_1.resolve)(path);
|
|
93
|
+
delete require.cache[path];
|
|
94
|
+
return require(path);
|
|
95
|
+
}
|
|
96
|
+
exports.include = include;
|
|
90
97
|
async function parseFile(path, jsKey) {
|
|
91
98
|
if (!(0, path_2.isAbsolute)(path))
|
|
92
99
|
path = (0, path_1.join)(process.cwd(), path);
|
|
@@ -95,13 +102,13 @@ async function parseFile(path, jsKey) {
|
|
|
95
102
|
$require("ts-node").register();
|
|
96
103
|
if (path.endsWith(".yaml") || path.endsWith("yml")) {
|
|
97
104
|
const contents = await (0, promises_1.readFile)(path);
|
|
98
|
-
return
|
|
105
|
+
return (0, yaml_1.parse)(contents.toString());
|
|
99
106
|
}
|
|
100
107
|
else if (path.endsWith(".json")) {
|
|
101
|
-
return
|
|
108
|
+
return include(path);
|
|
102
109
|
}
|
|
103
110
|
else {
|
|
104
|
-
const object =
|
|
111
|
+
const object = include(path);
|
|
105
112
|
const value = jsKey ? object[jsKey] : object;
|
|
106
113
|
return typeof value === "function" ? await value() : value;
|
|
107
114
|
}
|
|
@@ -275,6 +282,19 @@ function isNotFoundError(error) {
|
|
|
275
282
|
return error.code === "ENOENT";
|
|
276
283
|
}
|
|
277
284
|
exports.isNotFoundError = isNotFoundError;
|
|
285
|
+
async function readTextFile(path, onlyIfExists) {
|
|
286
|
+
let buffer;
|
|
287
|
+
try {
|
|
288
|
+
buffer = await (0, promises_1.readFile)(path);
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
if (onlyIfExists && isNotFoundError(error))
|
|
292
|
+
return;
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
return buffer.toString();
|
|
296
|
+
}
|
|
297
|
+
exports.readTextFile = readTextFile;
|
|
278
298
|
async function cpy(options) {
|
|
279
299
|
const stats = { paths: 0, files: 0, dirs: 0 };
|
|
280
300
|
const dirs = new Set();
|
package/lib/utils/http.d.ts
CHANGED
|
@@ -22,7 +22,9 @@ export declare function downloadFile(url: string, output: string, options?: {
|
|
|
22
22
|
query?: Record<string, string>;
|
|
23
23
|
timeout?: number;
|
|
24
24
|
onProgress?: (progress: BasicProgress) => void;
|
|
25
|
-
}): Promise<
|
|
25
|
+
}): Promise<{
|
|
26
|
+
bytes: number;
|
|
27
|
+
}>;
|
|
26
28
|
export declare function uploadFile(url: string, path: string, options?: {
|
|
27
29
|
headers?: Record<string, string>;
|
|
28
30
|
query?: Record<string, string>;
|
package/lib/utils/http.js
CHANGED
|
@@ -90,6 +90,7 @@ exports.post = post;
|
|
|
90
90
|
async function downloadFile(url, output, options = {}) {
|
|
91
91
|
const timeout = options.timeout ?? 3600 * 1000; // 60m
|
|
92
92
|
const file = (0, fs_1.createWriteStream)(output);
|
|
93
|
+
let total = 0;
|
|
93
94
|
await new Promise((resolve, reject) => {
|
|
94
95
|
const req = request(href(url, options.query), {
|
|
95
96
|
headers: options.headers,
|
|
@@ -97,7 +98,7 @@ async function downloadFile(url, output, options = {}) {
|
|
|
97
98
|
const contentLength = res.headers["content-length"] ?? "";
|
|
98
99
|
if (!/^\d+$/.test(contentLength))
|
|
99
100
|
return reject(new Error(`Invalid 'content-length': ${contentLength}`));
|
|
100
|
-
|
|
101
|
+
total = Number(contentLength);
|
|
101
102
|
let current = 0;
|
|
102
103
|
if (res.statusCode === 200) {
|
|
103
104
|
if (options.onProgress) {
|
|
@@ -145,6 +146,10 @@ async function downloadFile(url, output, options = {}) {
|
|
|
145
146
|
});
|
|
146
147
|
req.end();
|
|
147
148
|
});
|
|
149
|
+
const { size: bytes } = await (0, promises_1.stat)(output);
|
|
150
|
+
if (total !== bytes)
|
|
151
|
+
throw new Error(`Invalid download size: ${total} != ${bytes}`);
|
|
152
|
+
return { bytes };
|
|
148
153
|
}
|
|
149
154
|
exports.downloadFile = downloadFile;
|
|
150
155
|
async function uploadFile(url, path, options = {}) {
|
package/lib/utils/list.d.ts
CHANGED
|
@@ -32,13 +32,13 @@ type List3TaskResultObject<K, D extends Record<string, any>> = {
|
|
|
32
32
|
elapsed: number;
|
|
33
33
|
error?: Error;
|
|
34
34
|
};
|
|
35
|
-
type
|
|
35
|
+
export type List3SummaryResult = List3TaskResultObject<"summary", {
|
|
36
36
|
errors: number;
|
|
37
37
|
}>;
|
|
38
38
|
export type Listr3TaskResult<T extends Listr3Context> = {
|
|
39
39
|
[K in keyof T]: List3TaskResultObject<K, T[K]>;
|
|
40
40
|
}[keyof T];
|
|
41
|
-
export type Listr3TaskResultEnd<T extends Listr3Context> = Listr3TaskResult<T> |
|
|
41
|
+
export type Listr3TaskResultEnd<T extends Listr3Context> = Listr3TaskResult<T> | List3SummaryResult;
|
|
42
42
|
export declare class Listr3<T extends Listr3Context> extends Listr<void, "default", "simple"> {
|
|
43
43
|
readonly $options: {
|
|
44
44
|
streams?: Streams;
|
|
@@ -58,9 +58,9 @@ export declare class Listr3<T extends Listr3Context> extends Listr<void, "defaul
|
|
|
58
58
|
$task<K extends keyof T>(item: Listr3Task<T, K>): ListrTask;
|
|
59
59
|
$tasks<K extends keyof T>(...items: (Listr3Task<T, K> | ListrTask | false)[]): ListrTask[];
|
|
60
60
|
add(tasks: ListrTask<void, ListrGetRendererClassFromValue<"default">> | ListrTask<void, ListrGetRendererClassFromValue<"default">>[]): this;
|
|
61
|
-
getSummaryResult():
|
|
62
|
-
getResult(): (
|
|
61
|
+
getSummaryResult(): List3SummaryResult;
|
|
62
|
+
getResult(): (List3SummaryResult | Listr3TaskResult<T>)[];
|
|
63
63
|
protected release(): void;
|
|
64
|
-
exec(): Promise<(Listr3TaskResult<T> |
|
|
64
|
+
exec(): Promise<(Listr3TaskResult<T> | List3SummaryResult)[]>;
|
|
65
65
|
}
|
|
66
66
|
export {};
|
package/lib/utils/mysql.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createMysqlCli = exports.assertDumpFile = void 0;
|
|
4
|
-
const AppError_1 = require("../Error/AppError");
|
|
5
4
|
const cli_1 = require("./cli");
|
|
5
|
+
const error_1 = require("./datatruck/error");
|
|
6
6
|
const fs_1 = require("./fs");
|
|
7
7
|
const process_1 = require("./process");
|
|
8
8
|
const string_1 = require("./string");
|
|
@@ -32,12 +32,12 @@ async function assertDumpFile(path) {
|
|
|
32
32
|
firstLine.startsWith("-- mariadb dump"));
|
|
33
33
|
});
|
|
34
34
|
if (!successHeader)
|
|
35
|
-
throw new
|
|
35
|
+
throw new error_1.AppError("No start line found");
|
|
36
36
|
const successFooter = footerContents
|
|
37
37
|
.split(/\r?\n/)
|
|
38
38
|
.some((line) => line.trim().toLowerCase().startsWith("-- dump completed"));
|
|
39
39
|
if (!successFooter)
|
|
40
|
-
throw new
|
|
40
|
+
throw new error_1.AppError("No end line found (incomplete backup)");
|
|
41
41
|
}
|
|
42
42
|
exports.assertDumpFile = assertDumpFile;
|
|
43
43
|
async function createMysqlCli(options) {
|
|
@@ -223,7 +223,7 @@ async function createMysqlCli(options) {
|
|
|
223
223
|
async function initSharedDir(sharedDir) {
|
|
224
224
|
const secure_file_priv = await fetchVariable("secure_file_priv");
|
|
225
225
|
if (secure_file_priv?.toUpperCase() === "NULL")
|
|
226
|
-
throw new
|
|
226
|
+
throw new error_1.AppError("'secure_file_priv' is null in MySQL Server");
|
|
227
227
|
const dir = sharedDir ??
|
|
228
228
|
secure_file_priv ??
|
|
229
229
|
(await fetchVariable("tmpdir")) ??
|
|
@@ -241,7 +241,7 @@ async function createMysqlCli(options) {
|
|
|
241
241
|
await sql.execute(`SELECT 1 INTO OUTFILE ${outFileVar}`);
|
|
242
242
|
const exists = await (0, fs_1.existsFile)(outFile);
|
|
243
243
|
if (!exists)
|
|
244
|
-
throw new
|
|
244
|
+
throw new error_1.AppError(`MySQL shared dir is not reached: ${dir}`);
|
|
245
245
|
}
|
|
246
246
|
finally {
|
|
247
247
|
try {
|
package/lib/utils/object.d.ts
CHANGED
|
@@ -4,4 +4,17 @@ export declare function getErrorProperties(error: Error): Record<string, string>
|
|
|
4
4
|
type GroupByKeyParamType<TItem> = ((item: TItem) => string[] | string) | (keyof TItem)[] | keyof TItem;
|
|
5
5
|
export declare function groupBy<TItem>(items: TItem[], keyOrCb: GroupByKeyParamType<TItem>): Record<string, TItem[]>;
|
|
6
6
|
export declare function groupBy<TItem>(items: TItem[], keyOrCb: GroupByKeyParamType<TItem>, single: true): Record<string, TItem>;
|
|
7
|
+
export declare class StrictMap<K, V> {
|
|
8
|
+
readonly serializeKey: (params: K) => string;
|
|
9
|
+
constructor(serializeKey: (params: K) => string);
|
|
10
|
+
readonly map: Map<string, V | undefined>;
|
|
11
|
+
has(key: K): boolean;
|
|
12
|
+
get(key: K): NonNullable<V>;
|
|
13
|
+
set(key: K, value: V): void;
|
|
14
|
+
with(key: K): {
|
|
15
|
+
has: () => boolean;
|
|
16
|
+
get: () => NonNullable<V>;
|
|
17
|
+
set: (value: V) => void;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
7
20
|
export {};
|
package/lib/utils/object.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.groupBy = exports.getErrorProperties = exports.omitProp = exports.merge = void 0;
|
|
3
|
+
exports.StrictMap = exports.groupBy = exports.getErrorProperties = exports.omitProp = exports.merge = void 0;
|
|
4
4
|
function merge(target, ...sources) {
|
|
5
5
|
const isObject = (o) => typeof o === "object" && o !== null;
|
|
6
6
|
for (const source of sources)
|
|
@@ -56,3 +56,34 @@ function groupBy(items, keyOrCb, single) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
exports.groupBy = groupBy;
|
|
59
|
+
class StrictMap {
|
|
60
|
+
serializeKey;
|
|
61
|
+
constructor(serializeKey) {
|
|
62
|
+
this.serializeKey = serializeKey;
|
|
63
|
+
}
|
|
64
|
+
map = new Map();
|
|
65
|
+
has(key) {
|
|
66
|
+
return this.map.has(this.serializeKey(key));
|
|
67
|
+
}
|
|
68
|
+
get(key) {
|
|
69
|
+
const stringKey = this.serializeKey(key);
|
|
70
|
+
const value = this.map.get(stringKey);
|
|
71
|
+
if (!value)
|
|
72
|
+
throw new Error(`Map key does not exist: ${stringKey}`);
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
set(key, value) {
|
|
76
|
+
const stringKey = this.serializeKey(key);
|
|
77
|
+
if (this.map.has(stringKey))
|
|
78
|
+
throw new Error(`Map key already exists: ${stringKey}`);
|
|
79
|
+
this.map.set(stringKey, value);
|
|
80
|
+
}
|
|
81
|
+
with(key) {
|
|
82
|
+
return {
|
|
83
|
+
has: () => this.has(key),
|
|
84
|
+
get: () => this.get(key),
|
|
85
|
+
set: (value) => this.set(key, value),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.StrictMap = StrictMap;
|
package/lib/utils/process.js
CHANGED
|
@@ -322,7 +322,10 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
322
322
|
rl.on("line", onData);
|
|
323
323
|
rl.on("close", tryFinish);
|
|
324
324
|
}
|
|
325
|
-
else if (log[type] ||
|
|
325
|
+
else if (log[type] ||
|
|
326
|
+
settings[type]?.save ||
|
|
327
|
+
settings[type]?.onData ||
|
|
328
|
+
(type === "stderr" && settings[type]?.toExitCode)) {
|
|
326
329
|
p[type].on("data", onData);
|
|
327
330
|
}
|
|
328
331
|
}
|
package/lib/utils/string.d.ts
CHANGED
|
@@ -17,4 +17,5 @@ export declare function endsWith(input: string, patterns: string[]): boolean;
|
|
|
17
17
|
export declare function createMatchFilter(include?: string[], exclude?: string[]): (input: string) => boolean;
|
|
18
18
|
export declare function checkMatch(subject: string | undefined, patterns: string[]): boolean;
|
|
19
19
|
export declare function undefIfEmpty(input: string): string | undefined;
|
|
20
|
+
export declare function compareJsons(a: any, b: any): boolean;
|
|
20
21
|
export {};
|
package/lib/utils/string.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.undefIfEmpty = exports.checkMatch = exports.createMatchFilter = exports.endsWith = exports.match = exports.makePathPatterns = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = void 0;
|
|
4
|
-
const
|
|
3
|
+
exports.compareJsons = exports.undefIfEmpty = exports.checkMatch = exports.createMatchFilter = exports.endsWith = exports.match = exports.makePathPatterns = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = void 0;
|
|
4
|
+
const error_1 = require("./datatruck/error");
|
|
5
5
|
const micromatch_1 = require("micromatch");
|
|
6
6
|
function snakeCase(value, char = "_") {
|
|
7
7
|
return value.replace(/[A-Z]/g, (letter) => `${char}${letter.toLowerCase()}`);
|
|
@@ -47,7 +47,7 @@ function parseStringList(value, validValues, defaultsValues) {
|
|
|
47
47
|
if (validValues)
|
|
48
48
|
for (const v of result)
|
|
49
49
|
if (!validValues.includes(v))
|
|
50
|
-
throw new
|
|
50
|
+
throw new error_1.AppError(`Invalid value: ${v}`);
|
|
51
51
|
return result;
|
|
52
52
|
}
|
|
53
53
|
exports.parseStringList = parseStringList;
|
|
@@ -105,3 +105,7 @@ function undefIfEmpty(input) {
|
|
|
105
105
|
return input.length ? input : undefined;
|
|
106
106
|
}
|
|
107
107
|
exports.undefIfEmpty = undefIfEmpty;
|
|
108
|
+
function compareJsons(a, b) {
|
|
109
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
110
|
+
}
|
|
111
|
+
exports.compareJsons = compareJsons;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type DeepReadonly<T> = T extends (infer R)[] ? DeepReadonlyArray<R> : T extends Function ? T : T extends object ? DeepReadonlyObject<T> : T;
|
|
2
|
+
export interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {
|
|
3
|
+
}
|
|
4
|
+
export type DeepReadonlyObject<T> = {
|
|
5
|
+
readonly [P in keyof T]: DeepReadonly<T[P]>;
|
|
6
|
+
};
|
|
7
|
+
export type If<TResolved, T1, T2 = string> = TResolved extends true ? T1 : T2;
|
|
8
|
+
export type IfRequireKeys<TResolved, T1> = TResolved extends true ? RequiredKeys<T1> : T1;
|
|
9
|
+
export type Unwrap<T> = T extends Promise<infer U> ? U : T extends (...args: any) => Promise<infer U> ? U : T extends (...args: any) => infer U ? U : T;
|
|
10
|
+
export type RequiredKeys<T> = {
|
|
11
|
+
[K in keyof Required<T>]: T[K];
|
|
12
|
+
};
|
|
13
|
+
export type SimilarObject<T1> = {
|
|
14
|
+
[K in keyof T1]: unknown;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -23,7 +23,9 @@ export declare abstract class AbstractFs {
|
|
|
23
23
|
abstract download(source: string, target: string, options?: {
|
|
24
24
|
timeout?: number;
|
|
25
25
|
onProgress?: (progress: BasicProgress) => void;
|
|
26
|
-
}): Promise<
|
|
26
|
+
}): Promise<{
|
|
27
|
+
bytes: number;
|
|
28
|
+
}>;
|
|
27
29
|
abstract fetchDiskStats(source: string): Promise<DiskStats>;
|
|
28
30
|
}
|
|
29
31
|
export declare class LocalFs extends AbstractFs {
|
|
@@ -39,5 +41,7 @@ export declare class LocalFs extends AbstractFs {
|
|
|
39
41
|
rmAll(path: string): Promise<void>;
|
|
40
42
|
fetchDiskStats(source: string): Promise<DiskStats>;
|
|
41
43
|
upload(source: string, target: string): Promise<void>;
|
|
42
|
-
download(source: string, target: string): Promise<
|
|
44
|
+
download(source: string, target: string): Promise<{
|
|
45
|
+
bytes: number;
|
|
46
|
+
}>;
|
|
43
47
|
}
|
package/lib/utils/virtual-fs.js
CHANGED
|
@@ -62,7 +62,10 @@ class LocalFs extends AbstractFs {
|
|
|
62
62
|
await (0, promises_1.cp)(source, this.resolvePath(target));
|
|
63
63
|
}
|
|
64
64
|
async download(source, target) {
|
|
65
|
-
|
|
65
|
+
const path = this.resolvePath(source);
|
|
66
|
+
const { size: bytes } = await (0, promises_1.stat)(path);
|
|
67
|
+
await (0, promises_1.cp)(path, target);
|
|
68
|
+
return { bytes };
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
exports.LocalFs = LocalFs;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function createWatcher<T = string>(options: {
|
|
2
|
+
onRead: () => Promise<T>;
|
|
3
|
+
onCheck?: (prev: T | undefined, current: T | undefined) => boolean;
|
|
4
|
+
onChange?: (data: T | undefined) => void;
|
|
5
|
+
onError?: (error: Error) => void;
|
|
6
|
+
interval?: number;
|
|
7
|
+
}): {
|
|
8
|
+
start: () => void;
|
|
9
|
+
stop: () => void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWatcher = void 0;
|
|
4
|
+
function createWatcher(options) {
|
|
5
|
+
let prev;
|
|
6
|
+
let interval;
|
|
7
|
+
const onCheck = options.onCheck || ((prev, current) => prev === current);
|
|
8
|
+
const rutine = async (initial = false) => {
|
|
9
|
+
try {
|
|
10
|
+
let current = await options.onRead();
|
|
11
|
+
if (!onCheck(prev, current)) {
|
|
12
|
+
prev = current;
|
|
13
|
+
if (!initial)
|
|
14
|
+
options.onChange?.(current);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
options.onError?.(error);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
start: () => {
|
|
23
|
+
clearInterval(interval);
|
|
24
|
+
rutine(true).finally(() => {
|
|
25
|
+
interval = setInterval(rutine, options.interval ?? 5000);
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
stop: () => {
|
|
29
|
+
clearInterval(interval);
|
|
30
|
+
interval = undefined;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
exports.createWatcher = createWatcher;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datatruck/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Tool for creating and managing backups",
|
|
5
5
|
"homepage": "https://github.com/swordev/datatruck#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"async": "^3.2.5",
|
|
32
32
|
"chalk": "^4.1.2",
|
|
33
33
|
"commander": "^11.1.0",
|
|
34
|
-
"croner": "^
|
|
34
|
+
"croner": "^8.0.0",
|
|
35
35
|
"dayjs": "^1.11.10",
|
|
36
36
|
"fast-folder-size": "^2.2.0",
|
|
37
37
|
"fast-glob": "^3.3.2",
|
|
38
|
-
"listr2": "^8.0.
|
|
38
|
+
"listr2": "^8.0.1",
|
|
39
39
|
"micromatch": "^4.0.5",
|
|
40
40
|
"mysql2": "^3.6.5",
|
|
41
41
|
"tty-table": "^4.2.3",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@types/micromatch": "^4.0.6"
|
|
47
47
|
},
|
|
48
48
|
"optionalDependencies": {
|
|
49
|
-
"ts-node": "^10.9.
|
|
49
|
+
"ts-node": "^10.9.2"
|
|
50
50
|
},
|
|
51
51
|
"engine": {
|
|
52
52
|
"node": ">=20.0.0"
|