@datatruck/cli 0.0.6 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Action/BackupAction.js +1 -0
- package/Action/RestoreAction.js +1 -0
- package/Action/SnapshotsAction.d.ts +1 -0
- package/Action/SnapshotsAction.js +1 -0
- package/CHANGELOG.md +36 -0
- package/Command/SnapshotsCommand.js +3 -6
- package/Config/Config.js +1 -0
- package/Config/TaskConfig.d.ts +4 -0
- package/Config/TaskConfig.js +2 -0
- package/Factory/TaskFactory.js +4 -0
- package/JsonSchema/DefinitionEnum.d.ts +2 -1
- package/JsonSchema/DefinitionEnum.js +3 -2
- package/JsonSchema/JsonSchema.js +14 -0
- package/Repository/LocalRepository.js +2 -0
- package/Repository/ResticRepository.js +33 -13
- package/Task/MssqlTask.js +1 -0
- package/Task/ScriptTask.d.ts +42 -0
- package/Task/ScriptTask.js +180 -0
- package/Task/SqlDumpTaskAbstract.js +2 -0
- package/cli.js +1 -1
- package/config.schema.json +969 -0
- package/package.json +11 -12
- package/util/DataFormat.d.ts +1 -1
- package/util/DataFormat.js +12 -0
- package/util/ResticUtil.d.ts +6 -4
- package/util/ResticUtil.js +25 -3
- package/util/datatruck/config-util.d.ts +32 -0
- package/util/datatruck/config-util.js +12 -1
- package/util/fs-util.d.ts +3 -0
- package/util/fs-util.js +35 -1
- package/util/string-util.js +7 -1
package/package.json
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datatruck/cli",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"ajv": "^8.
|
|
5
|
+
"ajv": "^8.11.0",
|
|
6
6
|
"chalk": "^4.1.2",
|
|
7
|
-
"cli-table3": "^0.6.
|
|
8
|
-
"commander": "^9.
|
|
9
|
-
"
|
|
10
|
-
"dayjs": "^1.10.7",
|
|
7
|
+
"cli-table3": "^0.6.2",
|
|
8
|
+
"commander": "^9.2.0",
|
|
9
|
+
"dayjs": "^1.11.2",
|
|
11
10
|
"fast-glob": "^3.2.11",
|
|
12
|
-
"fs-extra": "^10.0
|
|
13
|
-
"micromatch": "^4.0.
|
|
14
|
-
"sqlite": "^4.
|
|
15
|
-
"sqlite3": "^5.0.
|
|
11
|
+
"fs-extra": "^10.1.0",
|
|
12
|
+
"micromatch": "^4.0.5",
|
|
13
|
+
"sqlite": "^4.1.1",
|
|
14
|
+
"sqlite3": "^5.0.8"
|
|
16
15
|
},
|
|
17
16
|
"optionalDependencies": {
|
|
18
|
-
"ts-node": "^10.
|
|
19
|
-
"yaml": "^1.
|
|
17
|
+
"ts-node": "^10.7.0",
|
|
18
|
+
"yaml": "^2.1.0"
|
|
20
19
|
},
|
|
21
20
|
"engine": {
|
|
22
21
|
"node": ">=16.0.0"
|
package/util/DataFormat.d.ts
CHANGED
package/util/DataFormat.js
CHANGED
|
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.DataFormat = void 0;
|
|
7
|
+
const AppError_1 = require("../Error/AppError");
|
|
7
8
|
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
8
9
|
const util_1 = require("util");
|
|
10
|
+
const customPrefix = "custom=";
|
|
9
11
|
class DataFormat {
|
|
10
12
|
constructor(options) {
|
|
11
13
|
this.options = options;
|
|
@@ -45,6 +47,16 @@ class DataFormat {
|
|
|
45
47
|
else if (format === "yaml") {
|
|
46
48
|
return this.formatToYaml();
|
|
47
49
|
}
|
|
50
|
+
else if (format.startsWith(customPrefix)) {
|
|
51
|
+
const code = format.slice(customPrefix.length);
|
|
52
|
+
return runCustomCode(this.options.items, code);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
throw new AppError_1.AppError(`Invalid output format: ${format}`);
|
|
56
|
+
}
|
|
48
57
|
}
|
|
49
58
|
}
|
|
50
59
|
exports.DataFormat = DataFormat;
|
|
60
|
+
function runCustomCode($, __code) {
|
|
61
|
+
return eval(__code);
|
|
62
|
+
}
|
package/util/ResticUtil.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExecSettingsInterface } from "./process-util";
|
|
1
|
+
import { ExecResultType, ExecSettingsInterface } from "./process-util";
|
|
2
2
|
import { UriType } from "./string-util";
|
|
3
3
|
export declare type RepositoryType = {
|
|
4
4
|
name?: string;
|
|
@@ -43,7 +43,7 @@ export declare class ResticUtil {
|
|
|
43
43
|
static formatRepository(input: RepositoryType, hidePassword?: boolean): Promise<string>;
|
|
44
44
|
exec(args: string[], settings?: ExecSettingsInterface, options?: {
|
|
45
45
|
cwd?: string;
|
|
46
|
-
}): Promise<
|
|
46
|
+
}): Promise<ExecResultType>;
|
|
47
47
|
checkRepository(): Promise<boolean>;
|
|
48
48
|
forget(options: {
|
|
49
49
|
snapshotId?: string;
|
|
@@ -81,12 +81,14 @@ export declare class ResticUtil {
|
|
|
81
81
|
paths: string[];
|
|
82
82
|
setPaths?: string[];
|
|
83
83
|
exclude?: string[];
|
|
84
|
+
excludeFile?: string[];
|
|
84
85
|
parent?: string;
|
|
86
|
+
allowEmptySnapshot?: boolean;
|
|
85
87
|
onStream?: (data: BackupStreamType) => Promise<void>;
|
|
86
|
-
}): Promise<
|
|
88
|
+
}): Promise<ExecResultType>;
|
|
87
89
|
restore(options: {
|
|
88
90
|
id: string;
|
|
89
91
|
target: string;
|
|
90
92
|
onStream?: (data: BackupStreamType) => Promise<void>;
|
|
91
|
-
}): Promise<
|
|
93
|
+
}): Promise<ExecResultType>;
|
|
92
94
|
}
|
package/util/ResticUtil.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ResticUtil = void 0;
|
|
4
|
+
const fs_util_1 = require("./fs-util");
|
|
4
5
|
const process_util_1 = require("./process-util");
|
|
5
6
|
const string_util_1 = require("./string-util");
|
|
6
7
|
const fs_extra_1 = require("fs-extra");
|
|
8
|
+
const promises_1 = require("fs/promises");
|
|
7
9
|
const path_1 = require("path");
|
|
8
10
|
class ResticUtil {
|
|
9
11
|
constructor(options) {
|
|
@@ -13,7 +15,7 @@ class ResticUtil {
|
|
|
13
15
|
if (input.backend === "local") {
|
|
14
16
|
if (typeof input.path !== "string")
|
|
15
17
|
throw new Error(`Invalid path at "${input.name}" repository: ${input.path}`);
|
|
16
|
-
return (0, path_1.
|
|
18
|
+
return (0, path_1.resolve)(input.path);
|
|
17
19
|
}
|
|
18
20
|
if (input.passwordFile)
|
|
19
21
|
input = {
|
|
@@ -36,7 +38,7 @@ class ResticUtil {
|
|
|
36
38
|
stderr: true,
|
|
37
39
|
colorize: true,
|
|
38
40
|
allToStderr: true,
|
|
39
|
-
envNames: ["RESTIC_REPOSITORY"],
|
|
41
|
+
envNames: ["RESTIC_REPOSITORY", "RESTIC_PASSWORD_FILE"],
|
|
40
42
|
}
|
|
41
43
|
: {},
|
|
42
44
|
...(settings ?? {}),
|
|
@@ -99,10 +101,11 @@ class ResticUtil {
|
|
|
99
101
|
return result.stderr.includes("flag needs an argument");
|
|
100
102
|
}
|
|
101
103
|
async backup(options) {
|
|
102
|
-
|
|
104
|
+
const exec = async () => await this.exec([
|
|
103
105
|
"backup",
|
|
104
106
|
"--json",
|
|
105
107
|
...(options.exclude?.flatMap((v) => ["-e", v]) ?? []),
|
|
108
|
+
...(options.excludeFile?.flatMap((v) => ["--exclude-file", v]) ?? []),
|
|
106
109
|
...(options.tags?.flatMap((v) => ["--tag", v]) ?? []),
|
|
107
110
|
...(options.setPaths?.flatMap((v) => ["--set-path", v]) ?? []),
|
|
108
111
|
...(options.parent ? ["--parent", options.parent] : []),
|
|
@@ -123,6 +126,25 @@ class ResticUtil {
|
|
|
123
126
|
}, {
|
|
124
127
|
cwd: options.cwd,
|
|
125
128
|
});
|
|
129
|
+
try {
|
|
130
|
+
return await exec();
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (options.allowEmptySnapshot &&
|
|
134
|
+
error.message.includes("unable to save snapshot: snapshot is empty")) {
|
|
135
|
+
const emptyPath = await (0, fs_util_1.mkTmpDir)("empty");
|
|
136
|
+
await (0, promises_1.writeFile)(`${emptyPath}/.empty`, "");
|
|
137
|
+
return await this.backup({
|
|
138
|
+
...options,
|
|
139
|
+
cwd: emptyPath,
|
|
140
|
+
allowEmptySnapshot: false,
|
|
141
|
+
paths: ["."],
|
|
142
|
+
exclude: [],
|
|
143
|
+
excludeFile: [],
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
126
148
|
}
|
|
127
149
|
async restore(options) {
|
|
128
150
|
return await this.exec(["restore", "--json", options.id, "--target", options.target], {
|
|
@@ -18,6 +18,7 @@ declare type ResolveDatabaseNameParamsType = ResolvePackageParamsType & {
|
|
|
18
18
|
export declare function resolveDatabaseName(value: string, params: ResolveDatabaseNameParamsType): string;
|
|
19
19
|
declare type ResolvePackageParamsType = {
|
|
20
20
|
snapshotId: string;
|
|
21
|
+
snapshotDate: string;
|
|
21
22
|
action: "backup" | "restore";
|
|
22
23
|
};
|
|
23
24
|
export declare function resolvePackage(pkg: PackageConfigType, params: ResolvePackageParamsType): PackageConfigType;
|
|
@@ -25,6 +26,20 @@ export declare function resolvePackages(packages: PackageConfigType[], params: R
|
|
|
25
26
|
export declare const pkgPathParams: {
|
|
26
27
|
[name in "temp" | Exclude<keyof ResolvePackagePathParamsType, "path">]: string;
|
|
27
28
|
};
|
|
29
|
+
export declare const pkgIncludeParams: {
|
|
30
|
+
snapshotDate: string;
|
|
31
|
+
packageName: string;
|
|
32
|
+
temp: string;
|
|
33
|
+
snapshotId: string;
|
|
34
|
+
action: string;
|
|
35
|
+
};
|
|
36
|
+
export declare const pkgExcludeParams: {
|
|
37
|
+
snapshotDate: string;
|
|
38
|
+
packageName: string;
|
|
39
|
+
temp: string;
|
|
40
|
+
snapshotId: string;
|
|
41
|
+
action: string;
|
|
42
|
+
};
|
|
28
43
|
export declare const pkgRestorePathParams: {
|
|
29
44
|
[name in "temp" | keyof ResolvePackagePathParamsType]: string;
|
|
30
45
|
};
|
|
@@ -33,20 +48,37 @@ export declare const dbNameParams: {
|
|
|
33
48
|
};
|
|
34
49
|
export declare const params: {
|
|
35
50
|
pkgPath: {
|
|
51
|
+
snapshotDate: string;
|
|
36
52
|
packageName: string;
|
|
37
53
|
temp: string;
|
|
38
54
|
snapshotId: string;
|
|
39
55
|
action: string;
|
|
40
56
|
};
|
|
41
57
|
pkgRestorePath: {
|
|
58
|
+
snapshotDate: string;
|
|
42
59
|
packageName: string;
|
|
43
60
|
path: string;
|
|
44
61
|
temp: string;
|
|
45
62
|
snapshotId: string;
|
|
46
63
|
action: string;
|
|
47
64
|
};
|
|
65
|
+
pkgInclude: {
|
|
66
|
+
snapshotDate: string;
|
|
67
|
+
packageName: string;
|
|
68
|
+
temp: string;
|
|
69
|
+
snapshotId: string;
|
|
70
|
+
action: string;
|
|
71
|
+
};
|
|
72
|
+
pkgExclude: {
|
|
73
|
+
snapshotDate: string;
|
|
74
|
+
packageName: string;
|
|
75
|
+
temp: string;
|
|
76
|
+
snapshotId: string;
|
|
77
|
+
action: string;
|
|
78
|
+
};
|
|
48
79
|
dbName: {
|
|
49
80
|
snapshotId: string;
|
|
81
|
+
snapshotDate: string;
|
|
50
82
|
action: string;
|
|
51
83
|
packageName: string;
|
|
52
84
|
database: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.params = exports.dbNameParams = exports.pkgRestorePathParams = exports.pkgPathParams = exports.resolvePackages = exports.resolvePackage = exports.resolveDatabaseName = exports.resolvePackagePath = exports.filterPackages = exports.findRepositoryOrFail = void 0;
|
|
3
|
+
exports.params = exports.dbNameParams = exports.pkgRestorePathParams = exports.pkgExcludeParams = exports.pkgIncludeParams = exports.pkgPathParams = exports.resolvePackages = exports.resolvePackage = exports.resolveDatabaseName = exports.resolvePackagePath = exports.filterPackages = exports.findRepositoryOrFail = void 0;
|
|
4
4
|
const AppError_1 = require("../../Error/AppError");
|
|
5
5
|
const fs_util_1 = require("../fs-util");
|
|
6
6
|
const string_util_1 = require("../string-util");
|
|
@@ -53,6 +53,10 @@ function resolvePackage(pkg, params) {
|
|
|
53
53
|
packageName: pkg.name,
|
|
54
54
|
path: undefined,
|
|
55
55
|
};
|
|
56
|
+
if (pkg.include)
|
|
57
|
+
pkg.include = pkg.include.map((v) => typeof v === "string" ? (0, string_util_1.render)(v, pkgParams) : v);
|
|
58
|
+
if (pkg.exclude)
|
|
59
|
+
pkg.exclude = pkg.exclude.map((v) => typeof v === "string" ? (0, string_util_1.render)(v, pkgParams) : v);
|
|
56
60
|
if (pkg.path)
|
|
57
61
|
pkg.path = resolvePackagePath(pkg.path, pkgParams);
|
|
58
62
|
if (pkg.restorePath)
|
|
@@ -71,23 +75,30 @@ exports.pkgPathParams = {
|
|
|
71
75
|
action: "{action}",
|
|
72
76
|
packageName: "{packageName}",
|
|
73
77
|
snapshotId: "{snapshotId}",
|
|
78
|
+
snapshotDate: "{snapshotDate}",
|
|
74
79
|
temp: "{temp}",
|
|
75
80
|
};
|
|
81
|
+
exports.pkgIncludeParams = exports.pkgPathParams;
|
|
82
|
+
exports.pkgExcludeParams = exports.pkgPathParams;
|
|
76
83
|
exports.pkgRestorePathParams = {
|
|
77
84
|
action: "{action}",
|
|
78
85
|
packageName: "{packageName}",
|
|
79
86
|
path: "{path}",
|
|
80
87
|
snapshotId: "{snapshotId}",
|
|
88
|
+
snapshotDate: "{snapshotDate}",
|
|
81
89
|
temp: "{temp}",
|
|
82
90
|
};
|
|
83
91
|
exports.dbNameParams = {
|
|
84
92
|
action: "{action}",
|
|
85
93
|
packageName: "{packageName}",
|
|
86
94
|
snapshotId: "{snapshotId}",
|
|
95
|
+
snapshotDate: "{snapshotDate}",
|
|
87
96
|
database: "{database}",
|
|
88
97
|
};
|
|
89
98
|
exports.params = {
|
|
90
99
|
pkgPath: exports.pkgPathParams,
|
|
91
100
|
pkgRestorePath: exports.pkgRestorePathParams,
|
|
101
|
+
pkgInclude: exports.pkgIncludeParams,
|
|
102
|
+
pkgExclude: exports.pkgExcludeParams,
|
|
92
103
|
dbName: exports.dbNameParams,
|
|
93
104
|
};
|
package/util/fs-util.d.ts
CHANGED
|
@@ -23,6 +23,9 @@ export declare function readPartialFile(path: string, positions: [number, number
|
|
|
23
23
|
export declare function checkFile(path: string): Promise<boolean>;
|
|
24
24
|
export declare function checkDir(path: string): Promise<boolean>;
|
|
25
25
|
export declare function forEachFile(dirPath: string, cb: (path: string, dir: boolean) => void, includeDir?: boolean): Promise<void>;
|
|
26
|
+
export declare function writeGitIgnoreList(options: {
|
|
27
|
+
paths: NodeJS.ReadableStream | string[];
|
|
28
|
+
}): Promise<string>;
|
|
26
29
|
export declare function writePathLists(options: {
|
|
27
30
|
paths: NodeJS.ReadableStream | string[];
|
|
28
31
|
packs?: {
|
package/util/fs-util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.writePathLists = exports.forEachFile = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.tmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.existsFile = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.readdirIfExists = exports.writeJSONFile = exports.existsDir = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isDirEmpty = exports.isLocalDir = void 0;
|
|
3
|
+
exports.writePathLists = exports.writeGitIgnoreList = exports.forEachFile = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.tmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.existsFile = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.readdirIfExists = exports.writeJSONFile = exports.existsDir = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isDirEmpty = exports.isLocalDir = void 0;
|
|
4
4
|
const path_util_1 = require("./path-util");
|
|
5
5
|
const crypto_1 = require("crypto");
|
|
6
6
|
const fs_1 = require("fs");
|
|
@@ -190,6 +190,40 @@ async function forEachFile(dirPath, cb, includeDir) {
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
exports.forEachFile = forEachFile;
|
|
193
|
+
async function writeGitIgnoreList(options) {
|
|
194
|
+
const tempDir = await mkTmpDir("gitignore-list");
|
|
195
|
+
const path = (0, path_1.join)(tempDir, `.gitignore`);
|
|
196
|
+
const stream = (0, fs_2.createWriteStream)(path);
|
|
197
|
+
const dirs = new Set();
|
|
198
|
+
stream.write("*\n");
|
|
199
|
+
for await (const value of options.paths) {
|
|
200
|
+
const dir = (0, path_1.dirname)(value.toString());
|
|
201
|
+
if (dir !== ".") {
|
|
202
|
+
let parentPath;
|
|
203
|
+
for (const value of dir.split("/")) {
|
|
204
|
+
if (!parentPath) {
|
|
205
|
+
parentPath = `!${value}`;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
parentPath += `/${value}`;
|
|
209
|
+
}
|
|
210
|
+
if (!dirs.has(parentPath)) {
|
|
211
|
+
stream.write(`${parentPath}\n`);
|
|
212
|
+
stream.write(`${parentPath.slice(1)}/*\n`);
|
|
213
|
+
dirs.add(parentPath);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
stream.write(`!${value}\n`);
|
|
218
|
+
}
|
|
219
|
+
await new Promise((resolve, reject) => {
|
|
220
|
+
stream.close();
|
|
221
|
+
stream.on("close", resolve);
|
|
222
|
+
stream.on("error", reject);
|
|
223
|
+
});
|
|
224
|
+
return path;
|
|
225
|
+
}
|
|
226
|
+
exports.writeGitIgnoreList = writeGitIgnoreList;
|
|
193
227
|
async function writePathLists(options) {
|
|
194
228
|
const tempDir = await mkTmpDir("path-lists");
|
|
195
229
|
const includedPaths = [];
|
package/util/string-util.js
CHANGED
|
@@ -21,7 +21,13 @@ function snakeCase(value, char = "_") {
|
|
|
21
21
|
}
|
|
22
22
|
exports.snakeCase = snakeCase;
|
|
23
23
|
function render(subject, vars) {
|
|
24
|
-
return subject.replace(/{(\w
|
|
24
|
+
return subject.replace(/{([\w/]*)}/g, function (match, name) {
|
|
25
|
+
if (!name.length) {
|
|
26
|
+
return "{";
|
|
27
|
+
}
|
|
28
|
+
else if (name === "/") {
|
|
29
|
+
return "}";
|
|
30
|
+
}
|
|
25
31
|
const value = vars[name];
|
|
26
32
|
if (typeof value === "undefined")
|
|
27
33
|
throw new AppError_1.AppError(`Variable is not defined: '${subject}' (${name})`);
|