@datatruck/cli 0.6.1 → 0.9.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.d.ts +1 -0
- package/Action/BackupAction.js +4 -1
- package/Action/RestoreAction.d.ts +1 -0
- package/Action/RestoreAction.js +1 -0
- package/Action/SnapshotsAction.d.ts +1 -0
- package/Command/BackupCommand.d.ts +1 -0
- package/Command/BackupCommand.js +8 -2
- package/Command/BackupSessionsCommand.js +1 -1
- package/Command/ConfigCommand.d.ts +1 -0
- package/Command/ConfigCommand.js +7 -1
- package/Command/InitCommand.js +1 -1
- package/Command/PruneCommand.js +2 -2
- package/Command/RestoreCommand.d.ts +1 -0
- package/Command/RestoreCommand.js +8 -2
- package/Command/RestoreSessionsCommand.js +1 -1
- package/Command/SnapshotsCommand.d.ts +1 -0
- package/Command/SnapshotsCommand.js +16 -2
- package/Repository/GitRepository.js +5 -0
- package/Repository/LocalRepository.d.ts +1 -0
- package/Repository/LocalRepository.js +5 -0
- package/Repository/RepositoryAbstract.d.ts +4 -1
- package/Repository/RepositoryAbstract.js +1 -0
- package/Repository/ResticRepository.d.ts +2 -2
- package/Repository/ResticRepository.js +9 -0
- package/SessionDriver/ConsoleSessionDriver.d.ts +6 -2
- package/SessionDriver/ConsoleSessionDriver.js +19 -29
- package/SessionDriver/SessionDriverAbstract.d.ts +1 -1
- package/SessionDriver/SessionDriverAbstract.js +1 -1
- package/SessionManager/BackupSessionManager.d.ts +1 -1
- package/SessionManager/BackupSessionManager.js +2 -2
- package/Task/MysqlDumpTask.d.ts +3 -2
- package/Task/MysqlDumpTask.js +35 -3
- package/Task/PostgresqlDumpTask.d.ts +3 -2
- package/Task/PostgresqlDumpTask.js +6 -5
- package/Task/SqlDumpTaskAbstract.d.ts +4 -3
- package/Task/SqlDumpTaskAbstract.js +67 -19
- package/config.schema.json +3 -0
- package/package.json +9 -9
- package/util/cli-util.d.ts +1 -0
- package/util/cli-util.js +13 -1
- package/util/datatruck/config-util.d.ts +1 -0
- package/util/datatruck/config-util.js +3 -0
- package/util/date-util.d.ts +4 -0
- package/util/date-util.js +17 -1
- package/util/entity-util.d.ts +1 -1
- package/util/fs-util.d.ts +1 -0
- package/util/process-util.d.ts +1 -0
- package/util/process-util.js +2 -2
- package/util/string-util.d.ts +1 -0
- package/util/string-util.js +21 -1
- package/CHANGELOG.md +0 -119
package/Task/MysqlDumpTask.js
CHANGED
|
@@ -17,6 +17,7 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
17
17
|
const password = await this.fetchPassword();
|
|
18
18
|
return [
|
|
19
19
|
`--host=${this.config.hostname}`,
|
|
20
|
+
...(this.config.port ? [`--port=${this.config.port}`] : []),
|
|
20
21
|
`--user=${this.config.username}`,
|
|
21
22
|
`--password=${password ?? ""}`,
|
|
22
23
|
...(database && this.config.database ? [this.config.database] : []),
|
|
@@ -57,17 +58,17 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
57
58
|
},
|
|
58
59
|
});
|
|
59
60
|
}
|
|
60
|
-
async onFetchTableNames() {
|
|
61
|
+
async onFetchTableNames(database) {
|
|
61
62
|
return await this.fetchValues(`
|
|
62
63
|
SELECT
|
|
63
64
|
table_name
|
|
64
65
|
FROM
|
|
65
66
|
information_schema.tables
|
|
66
67
|
WHERE
|
|
67
|
-
table_schema = '${
|
|
68
|
+
table_schema = '${database}'
|
|
68
69
|
`);
|
|
69
70
|
}
|
|
70
|
-
async
|
|
71
|
+
async onExportTables(tableNames, output) {
|
|
71
72
|
const stream = (0, fs_1.createWriteStream)(output);
|
|
72
73
|
await Promise.all([
|
|
73
74
|
new Promise((resolve, reject) => {
|
|
@@ -77,6 +78,7 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
77
78
|
await (0, process_util_1.exec)("mysqldump", [
|
|
78
79
|
...(await this.buildConnectionArgs()),
|
|
79
80
|
"--lock-tables=false",
|
|
81
|
+
"--skip-add-drop-table=false",
|
|
80
82
|
...tableNames,
|
|
81
83
|
], null, {
|
|
82
84
|
pipe: { stream: stream },
|
|
@@ -105,6 +107,36 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
105
107
|
if (!successFooter)
|
|
106
108
|
throw new AppError_1.AppError("No end line found (incomplete backup)");
|
|
107
109
|
}
|
|
110
|
+
async onExportStoredPrograms(output) {
|
|
111
|
+
const stream = (0, fs_1.createWriteStream)(output);
|
|
112
|
+
await Promise.all([
|
|
113
|
+
new Promise((resolve, reject) => {
|
|
114
|
+
stream.on("close", resolve);
|
|
115
|
+
stream.on("error", reject);
|
|
116
|
+
}),
|
|
117
|
+
await (0, process_util_1.exec)("mysqldump", [
|
|
118
|
+
...(await this.buildConnectionArgs()),
|
|
119
|
+
"--lock-tables=false",
|
|
120
|
+
"--routines",
|
|
121
|
+
"--events",
|
|
122
|
+
"--skip-triggers",
|
|
123
|
+
"--no-create-info",
|
|
124
|
+
"--no-data",
|
|
125
|
+
"--no-create-db",
|
|
126
|
+
"--skip-opt",
|
|
127
|
+
], null, {
|
|
128
|
+
pipe: { stream: stream },
|
|
129
|
+
log: {
|
|
130
|
+
exec: this.verbose,
|
|
131
|
+
stderr: this.verbose,
|
|
132
|
+
allToStderr: true,
|
|
133
|
+
},
|
|
134
|
+
stderr: {
|
|
135
|
+
toExitCode: true,
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
108
140
|
async onImport(path, database) {
|
|
109
141
|
await (0, process_util_1.exec)("mysql", [...(await this.buildConnectionArgs(false)), database], null, {
|
|
110
142
|
pipe: {
|
|
@@ -8,7 +8,8 @@ export declare class PostgresqlDumpTask extends SqlDumpTaskAbstract<PostgresqlDu
|
|
|
8
8
|
onDatabaseIsEmpty(name: string): Promise<boolean>;
|
|
9
9
|
onCreateDatabase(database: TargetDatabaseType): Promise<void>;
|
|
10
10
|
onExecQuery(query: string): Promise<import("../util/process-util").ExecResultType>;
|
|
11
|
-
onFetchTableNames(): Promise<string[]>;
|
|
12
|
-
|
|
11
|
+
onFetchTableNames(database: string): Promise<string[]>;
|
|
12
|
+
onExportTables(tableNames: string[], output: string): Promise<void>;
|
|
13
|
+
onExportStoredPrograms(): Promise<void>;
|
|
13
14
|
onImport(path: string, database: string): Promise<void>;
|
|
14
15
|
}
|
|
@@ -60,18 +60,18 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
60
60
|
},
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
-
async onFetchTableNames() {
|
|
63
|
+
async onFetchTableNames(database) {
|
|
64
64
|
return await this.fetchValues(`
|
|
65
65
|
SELECT
|
|
66
66
|
CONCAT(table_schema, '.', table_name)
|
|
67
67
|
FROM
|
|
68
68
|
information_schema.tables
|
|
69
69
|
WHERE
|
|
70
|
-
table_catalog = '${
|
|
70
|
+
table_catalog = '${database}' AND
|
|
71
71
|
table_schema NOT IN ('pg_catalog', 'information_schema')
|
|
72
72
|
`);
|
|
73
73
|
}
|
|
74
|
-
async
|
|
74
|
+
async onExportTables(tableNames, output) {
|
|
75
75
|
const stream = (0, fs_1.createWriteStream)(output);
|
|
76
76
|
await Promise.all([
|
|
77
77
|
new Promise((resolve, reject) => {
|
|
@@ -80,8 +80,6 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
80
80
|
}),
|
|
81
81
|
(0, process_util_1.exec)("pg_dump", [
|
|
82
82
|
...(await this.buildConnectionArgs()),
|
|
83
|
-
"--clean",
|
|
84
|
-
"--if-exists",
|
|
85
83
|
...(tableNames?.flatMap((v) => ["-t", v]) ?? []),
|
|
86
84
|
], null, {
|
|
87
85
|
pipe: { stream: stream },
|
|
@@ -92,6 +90,9 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
92
90
|
}),
|
|
93
91
|
]);
|
|
94
92
|
}
|
|
93
|
+
async onExportStoredPrograms() {
|
|
94
|
+
throw new Error(`Method not implemented: onExportStoredPrograms`);
|
|
95
|
+
}
|
|
95
96
|
async onImport(path, database) {
|
|
96
97
|
await (0, process_util_1.exec)("psql", [...(await this.buildConnectionArgs(database)), "-f", (0, path_1.normalize)(path)], undefined, {
|
|
97
98
|
log: this.verbose,
|
|
@@ -14,6 +14,7 @@ export declare type SqlDumpTaskConfigType = {
|
|
|
14
14
|
port?: number;
|
|
15
15
|
database: string;
|
|
16
16
|
username: string;
|
|
17
|
+
storedPrograms?: boolean;
|
|
17
18
|
targetDatabase?: TargetDatabaseType;
|
|
18
19
|
includeTables?: string[];
|
|
19
20
|
excludeTables?: string[];
|
|
@@ -26,11 +27,11 @@ export declare abstract class SqlDumpTaskAbstract<TConfig extends SqlDumpTaskCon
|
|
|
26
27
|
fetchValues(query: string): Promise<string[]>;
|
|
27
28
|
abstract onCreateDatabase(database: TargetDatabaseType): Promise<void>;
|
|
28
29
|
abstract onDatabaseIsEmpty(databaseName: string): Promise<boolean>;
|
|
29
|
-
abstract onFetchTableNames(): Promise<string[]>;
|
|
30
|
+
abstract onFetchTableNames(database: string): Promise<string[]>;
|
|
30
31
|
abstract onExecQuery(query: string): ReturnType<typeof exec>;
|
|
31
|
-
abstract
|
|
32
|
+
abstract onExportTables(tableNames: string[], output: string): Promise<void>;
|
|
33
|
+
abstract onExportStoredPrograms(output: string): Promise<void>;
|
|
32
34
|
abstract onImport(path: string, database: string): Promise<void>;
|
|
33
|
-
fetchTableNames(): Promise<string[]>;
|
|
34
35
|
onBackup(data: BackupDataType): Promise<void>;
|
|
35
36
|
onRestore(data: RestoreDataType): Promise<void>;
|
|
36
37
|
}
|
|
@@ -44,11 +44,45 @@ exports.sqlDumpTaskDefinition = {
|
|
|
44
44
|
collate: { type: "string" },
|
|
45
45
|
},
|
|
46
46
|
},
|
|
47
|
+
storedPrograms: { type: "boolean" },
|
|
47
48
|
includeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
48
49
|
excludeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
49
50
|
oneFileByTable: { type: "boolean" },
|
|
50
51
|
},
|
|
51
52
|
};
|
|
53
|
+
function serializeSqlFile(input) {
|
|
54
|
+
if (input.database && input.table) {
|
|
55
|
+
return `${input.database}.${input.table}.table.sql`;
|
|
56
|
+
}
|
|
57
|
+
else if (input.database && !input.table) {
|
|
58
|
+
return `${input.database}.database.sql`;
|
|
59
|
+
}
|
|
60
|
+
else if (!input.database && input.table) {
|
|
61
|
+
return `${input.table}.table.sql`;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
throw new AppError_1.AppError(`Invalid sql file input: ${JSON.stringify(input)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function parseSqlFile(fileName) {
|
|
68
|
+
if (!fileName.endsWith(".sql"))
|
|
69
|
+
return;
|
|
70
|
+
const regex = /^(.+)\.(table|database)\.sql$/;
|
|
71
|
+
const matches = regex.exec(fileName);
|
|
72
|
+
if (!matches)
|
|
73
|
+
return { fileName };
|
|
74
|
+
const [, name, type] = matches;
|
|
75
|
+
const lastName = name.split(".").pop();
|
|
76
|
+
if (type === "table") {
|
|
77
|
+
return { fileName, table: lastName };
|
|
78
|
+
}
|
|
79
|
+
else if (type === "database") {
|
|
80
|
+
return { fileName, database: lastName };
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
throw new Error(`Invalid sql file type: ${type}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
52
86
|
class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
53
87
|
async fetchPassword() {
|
|
54
88
|
if (typeof this.config.password === "string")
|
|
@@ -66,27 +100,24 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
|
66
100
|
return result;
|
|
67
101
|
}, []);
|
|
68
102
|
}
|
|
69
|
-
async
|
|
70
|
-
|
|
103
|
+
async onBackup(data) {
|
|
104
|
+
this.verbose = data.options.verbose;
|
|
71
105
|
const config = this.config;
|
|
72
|
-
|
|
106
|
+
const outputPath = data.package.path;
|
|
107
|
+
const allTableNames = await this.onFetchTableNames(this.config.database);
|
|
108
|
+
const tableNames = allTableNames.filter((tableName) => {
|
|
73
109
|
if (config.includeTables && !(0, micromatch_1.isMatch)(tableName, config.includeTables))
|
|
74
110
|
return false;
|
|
75
111
|
if (config.excludeTables && (0, micromatch_1.isMatch)(tableName, config.excludeTables))
|
|
76
112
|
return false;
|
|
77
113
|
return true;
|
|
78
114
|
});
|
|
79
|
-
}
|
|
80
|
-
async onBackup(data) {
|
|
81
|
-
this.verbose = data.options.verbose;
|
|
82
|
-
const outputPath = data.package.path;
|
|
83
|
-
const tableNames = await this.fetchTableNames();
|
|
84
115
|
(0, assert_1.ok)(typeof outputPath === "string");
|
|
85
116
|
if (!(await (0, fs_util_1.checkDir)(outputPath)))
|
|
86
117
|
await (0, promises_1.mkdir)(outputPath, { recursive: true });
|
|
87
118
|
if (!this.config.oneFileByTable) {
|
|
88
|
-
const outPath = (0, path_1.join)(outputPath, this.config.database)
|
|
89
|
-
await this.
|
|
119
|
+
const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ database: this.config.database }));
|
|
120
|
+
await this.onExportTables(tableNames, outPath);
|
|
90
121
|
}
|
|
91
122
|
else {
|
|
92
123
|
let current = 0;
|
|
@@ -98,10 +129,14 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
|
98
129
|
step: tableName,
|
|
99
130
|
});
|
|
100
131
|
current++;
|
|
101
|
-
const outPath = (0, path_1.join)(outputPath, tableName)
|
|
102
|
-
await this.
|
|
132
|
+
const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ table: tableName }));
|
|
133
|
+
await this.onExportTables([tableName], outPath);
|
|
103
134
|
}
|
|
104
135
|
}
|
|
136
|
+
if (this.config.storedPrograms) {
|
|
137
|
+
const outPath = (0, path_1.join)(outputPath, "stored-programs.sql");
|
|
138
|
+
await this.onExportStoredPrograms(outPath);
|
|
139
|
+
}
|
|
105
140
|
}
|
|
106
141
|
async onRestore(data) {
|
|
107
142
|
const restorePath = data.package.restorePath;
|
|
@@ -125,20 +160,33 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
|
|
|
125
160
|
database: database.name,
|
|
126
161
|
});
|
|
127
162
|
}
|
|
128
|
-
|
|
163
|
+
const items = (await (0, promises_1.readdir)(restorePath))
|
|
164
|
+
.map(parseSqlFile)
|
|
165
|
+
.filter((v) => !!v);
|
|
166
|
+
// Database check
|
|
167
|
+
const databaseItems = items.filter((v) => v.database);
|
|
168
|
+
if (databaseItems.length && !(await this.onDatabaseIsEmpty(database.name)))
|
|
129
169
|
throw new AppError_1.AppError(`Target database is not empty: ${database.name}`);
|
|
170
|
+
// Table check
|
|
171
|
+
const restoreTables = items
|
|
172
|
+
.filter((v) => v.table)
|
|
173
|
+
.map((v) => v.table);
|
|
174
|
+
const serverTables = await this.onFetchTableNames(database.name);
|
|
175
|
+
const errorTables = restoreTables.filter((v) => serverTables.includes(v));
|
|
176
|
+
if (errorTables.length) {
|
|
177
|
+
throw new AppError_1.AppError(`Target table already exists: ${errorTables.join(", ")}`);
|
|
178
|
+
}
|
|
130
179
|
await this.onCreateDatabase(database);
|
|
131
180
|
if (this.verbose)
|
|
132
181
|
(0, cli_util_1.logExec)("readdir", [restorePath]);
|
|
133
|
-
const files = (await (0, promises_1.readdir)(restorePath)).filter((name) => /\.sql$/i.test(name));
|
|
134
182
|
let current = 0;
|
|
135
|
-
for (const
|
|
136
|
-
const path = (0, path_1.join)(restorePath,
|
|
183
|
+
for (const item of items) {
|
|
184
|
+
const path = (0, path_1.join)(restorePath, item.fileName);
|
|
137
185
|
data.onProgress({
|
|
138
|
-
total:
|
|
186
|
+
total: items.length,
|
|
139
187
|
current: current,
|
|
140
|
-
percent: (0, math_util_1.progressPercent)(
|
|
141
|
-
step:
|
|
188
|
+
percent: (0, math_util_1.progressPercent)(items.length, current),
|
|
189
|
+
step: item.fileName,
|
|
142
190
|
});
|
|
143
191
|
current++;
|
|
144
192
|
await this.onImport(path, database.name);
|
package/config.schema.json
CHANGED
package/package.json
CHANGED
|
@@ -1,29 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datatruck/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"ajv": "^8.11.0",
|
|
6
6
|
"async": "^3.2.4",
|
|
7
7
|
"chalk": "^4.1.2",
|
|
8
8
|
"cli-table3": "^0.6.2",
|
|
9
|
-
"commander": "^9.
|
|
10
|
-
"dayjs": "^1.11.
|
|
9
|
+
"commander": "^9.3.0",
|
|
10
|
+
"dayjs": "^1.11.3",
|
|
11
11
|
"fast-glob": "^3.2.11",
|
|
12
12
|
"micromatch": "^4.0.5",
|
|
13
13
|
"sqlite": "^4.1.1",
|
|
14
14
|
"sqlite3": "^5.0.8"
|
|
15
15
|
},
|
|
16
16
|
"optionalDependencies": {
|
|
17
|
-
"ts-node": "^10.
|
|
18
|
-
"yaml": "^2.1.
|
|
17
|
+
"ts-node": "^10.8.2",
|
|
18
|
+
"yaml": "^2.1.1"
|
|
19
19
|
},
|
|
20
20
|
"engine": {
|
|
21
21
|
"node": ">=16.0.0"
|
|
22
22
|
},
|
|
23
|
-
"bin": {
|
|
24
|
-
"datatruck": "bin.js",
|
|
25
|
-
"dtt": "bin.js"
|
|
26
|
-
},
|
|
27
23
|
"description": "Tool for creating and managing backups",
|
|
28
24
|
"homepage": "https://github.com/swordev/datatruck#readme",
|
|
29
25
|
"bugs": {
|
|
@@ -38,5 +34,9 @@
|
|
|
38
34
|
"name": "Juanra GM",
|
|
39
35
|
"email": "juanrgm724@gmail.com",
|
|
40
36
|
"url": "https://github.com/juanrgm"
|
|
37
|
+
},
|
|
38
|
+
"bin": {
|
|
39
|
+
"datatruck": "bin.js",
|
|
40
|
+
"dtt": "bin.js"
|
|
41
41
|
}
|
|
42
42
|
}
|
package/util/cli-util.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare const clearCommand = "\r\u001B[K";
|
|
|
6
6
|
export declare const hideCursorCommand = "\u001B[?25l";
|
|
7
7
|
export declare function renderSpinner(counter: number): string;
|
|
8
8
|
export declare function renderProgressBar(progress: number, size?: number): string;
|
|
9
|
+
export declare function logVars(data: Record<string, any>): void;
|
|
9
10
|
export declare function logExec(command: string, argv?: string[], env?: NodeJS.ProcessEnv, logToStderr?: boolean): void;
|
|
10
11
|
export declare function resultColumn(error: Error | null | string, state?: "started" | "ended"): "❌" | " ? " | "✅";
|
|
11
12
|
export declare function errorColumn(error: Error | null | string, verbose: number): string;
|
package/util/cli-util.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.confirm = exports.truncate = exports.parseOptions = exports.errorColumn = exports.resultColumn = exports.logExec = exports.renderProgressBar = exports.renderSpinner = exports.hideCursorCommand = exports.clearCommand = exports.showCursorCommand = exports.spinnerChars = exports.clearLastLine = void 0;
|
|
6
|
+
exports.confirm = exports.truncate = exports.parseOptions = exports.errorColumn = exports.resultColumn = exports.logExec = exports.logVars = exports.renderProgressBar = exports.renderSpinner = exports.hideCursorCommand = exports.clearCommand = exports.showCursorCommand = exports.spinnerChars = exports.clearLastLine = void 0;
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const chalk_2 = require("chalk");
|
|
9
9
|
const readline_1 = require("readline");
|
|
@@ -28,6 +28,18 @@ function renderProgressBar(progress, size = 10) {
|
|
|
28
28
|
return completeChar.repeat(completedSize) + incompleteChar.repeat(restSize);
|
|
29
29
|
}
|
|
30
30
|
exports.renderProgressBar = renderProgressBar;
|
|
31
|
+
function logVars(data) {
|
|
32
|
+
let first = true;
|
|
33
|
+
for (const key in data) {
|
|
34
|
+
if (first) {
|
|
35
|
+
console.log();
|
|
36
|
+
first = false;
|
|
37
|
+
}
|
|
38
|
+
const value = data[key];
|
|
39
|
+
console.log(`${chalk_1.default.cyan(key)}${chalk_1.default.grey(":")} ${chalk_1.default.white(value ?? "")}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.logVars = logVars;
|
|
31
43
|
function logExec(command, argv = [], env, logToStderr) {
|
|
32
44
|
const envText = env
|
|
33
45
|
? Object.keys(env)
|
|
@@ -5,6 +5,7 @@ export declare function findRepositoryOrFail(config: ConfigType, repositoryName:
|
|
|
5
5
|
export declare function filterRepository(repository: RepositoryConfigType, action?: RepositoryConfigEnabledActionType): boolean;
|
|
6
6
|
export declare function filterPackages(config: ConfigType, options: {
|
|
7
7
|
packageNames?: string[];
|
|
8
|
+
packageTaskNames?: string[];
|
|
8
9
|
repositoryNames?: string[];
|
|
9
10
|
repositoryTypes?: string[];
|
|
10
11
|
sourceAction?: RepositoryConfigEnabledActionType;
|
|
@@ -22,6 +22,7 @@ function filterRepository(repository, action) {
|
|
|
22
22
|
exports.filterRepository = filterRepository;
|
|
23
23
|
function filterPackages(config, options) {
|
|
24
24
|
const packagePatterns = (0, string_util_1.makePathPatterns)(options.packageNames);
|
|
25
|
+
const taskNamePatterns = (0, string_util_1.makePathPatterns)(options.packageTaskNames);
|
|
25
26
|
return config.packages
|
|
26
27
|
.map((pkg) => {
|
|
27
28
|
pkg = Object.assign({}, pkg);
|
|
@@ -37,6 +38,8 @@ function filterPackages(config, options) {
|
|
|
37
38
|
return pkg;
|
|
38
39
|
})
|
|
39
40
|
.filter((pkg) => {
|
|
41
|
+
if (taskNamePatterns && !(0, micromatch_1.isMatch)(pkg.task?.name ?? "", taskNamePatterns))
|
|
42
|
+
return false;
|
|
40
43
|
return ((typeof pkg.enabled !== "boolean" || pkg.enabled) &&
|
|
41
44
|
!!pkg.repositoryNames?.length &&
|
|
42
45
|
(!packagePatterns || (0, micromatch_1.isMatch)(pkg.name, packagePatterns)));
|
package/util/date-util.d.ts
CHANGED
|
@@ -10,3 +10,7 @@ export declare type FilterByLastOptionsType = {
|
|
|
10
10
|
export declare function filterByLast<TItem extends {
|
|
11
11
|
date: string;
|
|
12
12
|
}>(items: TItem[], options: FilterByLastOptionsType, reasons?: Record<number, string[]>): TItem[];
|
|
13
|
+
export declare function createChron(): {
|
|
14
|
+
start: () => number;
|
|
15
|
+
elapsed: (formatted?: boolean) => string | number;
|
|
16
|
+
};
|
package/util/date-util.js
CHANGED
|
@@ -3,7 +3,8 @@ 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.filterByLast = void 0;
|
|
6
|
+
exports.createChron = exports.filterByLast = void 0;
|
|
7
|
+
const string_util_1 = require("./string-util");
|
|
7
8
|
const dayjs_1 = __importDefault(require("dayjs"));
|
|
8
9
|
const advancedFormat_1 = __importDefault(require("dayjs/plugin/advancedFormat"));
|
|
9
10
|
const isoWeek_1 = __importDefault(require("dayjs/plugin/isoWeek"));
|
|
@@ -72,3 +73,18 @@ function filterByLast(items, options, reasons) {
|
|
|
72
73
|
return items.filter((item) => validItems.includes(item));
|
|
73
74
|
}
|
|
74
75
|
exports.filterByLast = filterByLast;
|
|
76
|
+
function createChron() {
|
|
77
|
+
let startTime;
|
|
78
|
+
return {
|
|
79
|
+
start: () => (startTime = Date.now()),
|
|
80
|
+
elapsed: (formatted) => {
|
|
81
|
+
if (!startTime)
|
|
82
|
+
throw new Error(`Chron was not started`);
|
|
83
|
+
const seconds = (Date.now() - startTime) / 1000;
|
|
84
|
+
if (formatted)
|
|
85
|
+
return (0, string_util_1.formatSeconds)(seconds);
|
|
86
|
+
return seconds;
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
exports.createChron = createChron;
|
package/util/entity-util.d.ts
CHANGED
package/util/fs-util.d.ts
CHANGED
package/util/process-util.d.ts
CHANGED
package/util/process-util.js
CHANGED
|
@@ -68,10 +68,10 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
68
68
|
stderr: "",
|
|
69
69
|
exitCode: 0,
|
|
70
70
|
};
|
|
71
|
-
let
|
|
71
|
+
let finishListeners = pipe?.stream instanceof fs_1.WriteStream ? 2 : 1;
|
|
72
72
|
let streamError;
|
|
73
73
|
const tryFinish = () => {
|
|
74
|
-
if (!--
|
|
74
|
+
if (!--finishListeners)
|
|
75
75
|
finish();
|
|
76
76
|
};
|
|
77
77
|
const finish = () => {
|
package/util/string-util.d.ts
CHANGED
|
@@ -13,5 +13,6 @@ export declare type UriType = {
|
|
|
13
13
|
path?: string;
|
|
14
14
|
};
|
|
15
15
|
export declare function formatUri(input: UriType, hidePassword?: boolean): string;
|
|
16
|
+
export declare function formatSeconds(seconds: number): string;
|
|
16
17
|
export declare function makePathPatterns(values: string[] | undefined): string[] | undefined;
|
|
17
18
|
export declare function formatDateTime(datetime: string): string;
|
package/util/string-util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatDateTime = exports.makePathPatterns = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.lcfirst = exports.ucfirst = exports.serialize = void 0;
|
|
3
|
+
exports.formatDateTime = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.lcfirst = exports.ucfirst = exports.serialize = void 0;
|
|
4
4
|
const AppError_1 = require("../Error/AppError");
|
|
5
5
|
function serialize(message, data) {
|
|
6
6
|
if (data)
|
|
@@ -67,6 +67,26 @@ function formatUri(input, hidePassword) {
|
|
|
67
67
|
return uri;
|
|
68
68
|
}
|
|
69
69
|
exports.formatUri = formatUri;
|
|
70
|
+
function formatSeconds(seconds) {
|
|
71
|
+
let unit;
|
|
72
|
+
let value;
|
|
73
|
+
if (seconds > 60 * 60) {
|
|
74
|
+
value = seconds / 60 / 60;
|
|
75
|
+
unit = `hour`;
|
|
76
|
+
}
|
|
77
|
+
else if (seconds > 60) {
|
|
78
|
+
value = seconds / 60;
|
|
79
|
+
unit = `minute`;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
value = seconds;
|
|
83
|
+
unit = `second`;
|
|
84
|
+
}
|
|
85
|
+
if (value !== 1)
|
|
86
|
+
unit += `s`;
|
|
87
|
+
return `${value.toFixed(2)} ${unit}`;
|
|
88
|
+
}
|
|
89
|
+
exports.formatSeconds = formatSeconds;
|
|
70
90
|
function makePathPatterns(values) {
|
|
71
91
|
return values?.flatMap((v) => [v, `${v}/**`]);
|
|
72
92
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
# @datatruck/cli
|
|
2
|
-
|
|
3
|
-
## 0.6.1
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- [`0ba6229`](https://github.com/swordev/datatruck/commit/0ba6229348c109a59783e72242ab7c0e61f25e36) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix progress bar in restic repository
|
|
8
|
-
|
|
9
|
-
## 0.6.0
|
|
10
|
-
|
|
11
|
-
### Minor Changes
|
|
12
|
-
|
|
13
|
-
- [`0c6877d`](https://github.com/swordev/datatruck/commit/0c6877d189761e75dd434b0a8d72b71621d024de) Thanks [@juanrgm](https://github.com/juanrgm)! - Show more progress stats
|
|
14
|
-
|
|
15
|
-
* [`751e1f6`](https://github.com/swordev/datatruck/commit/751e1f6d6b33d3fa96eb40d998fdd140ce0e3875) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `fileCopyConcurrency` option
|
|
16
|
-
|
|
17
|
-
- [`05487e6`](https://github.com/swordev/datatruck/commit/05487e6a33f875a3afb7ff0815b16da6f2a41301) Thanks [@juanrgm](https://github.com/juanrgm)! - Parse InnoDB error in `MariadbTask` to avoid infinite wait
|
|
18
|
-
|
|
19
|
-
### Patch Changes
|
|
20
|
-
|
|
21
|
-
- [`b62a6f8`](https://github.com/swordev/datatruck/commit/b62a6f8a82409339afd65d4f96476eb57bbfb5a2) Thanks [@juanrgm](https://github.com/juanrgm)! - Resolve target/restore path in local repository
|
|
22
|
-
|
|
23
|
-
## 0.5.0
|
|
24
|
-
|
|
25
|
-
### Minor Changes
|
|
26
|
-
|
|
27
|
-
- [`5aeb2af`](https://github.com/swordev/datatruck/commit/5aeb2afb96692e00bdba501b58df9cc0e02dceaa) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `enabled` option to repository config
|
|
28
|
-
|
|
29
|
-
* [`75de836`](https://github.com/swordev/datatruck/commit/75de8369356cf02ed3fd5c58b1f9bea66432cda8) Thanks [@juanrgm](https://github.com/juanrgm)! - Allow restic password without file
|
|
30
|
-
|
|
31
|
-
## 0.4.0
|
|
32
|
-
|
|
33
|
-
### Minor Changes
|
|
34
|
-
|
|
35
|
-
- [`eeb00a6`](https://github.com/swordev/datatruck/commit/eeb00a69d75c91da40711ae79475612b1d5193b6) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `tempDir` config option
|
|
36
|
-
|
|
37
|
-
## 0.3.2
|
|
38
|
-
|
|
39
|
-
### Patch Changes
|
|
40
|
-
|
|
41
|
-
- [`8957c3b`](https://github.com/swordev/datatruck/commit/8957c3b5846606db8b825fef357445210f2a3ac3) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix restic progress parser
|
|
42
|
-
|
|
43
|
-
* [`2989718`](https://github.com/swordev/datatruck/commit/29897185e3d6659359d51ab2212351005137f86c) Thanks [@juanrgm](https://github.com/juanrgm)! - Show closing reason
|
|
44
|
-
|
|
45
|
-
- [`b9e0843`](https://github.com/swordev/datatruck/commit/b9e0843c7970944cfd30a7d2a543f515adfa60e4) Thanks [@juanrgm](https://github.com/juanrgm)! - Show restic progress in megabytes
|
|
46
|
-
|
|
47
|
-
## 0.3.1
|
|
48
|
-
|
|
49
|
-
### Patch Changes
|
|
50
|
-
|
|
51
|
-
- [`c3bb4c6`](https://github.com/swordev/datatruck/commit/c3bb4c609887c5525cf35487ea237750addb6e75) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix restic stdout parser
|
|
52
|
-
|
|
53
|
-
## 0.3.0
|
|
54
|
-
|
|
55
|
-
### Minor Changes
|
|
56
|
-
|
|
57
|
-
- [`d63fd25`](https://github.com/swordev/datatruck/commit/d63fd25ffa8d2e539d2125dfd6a3f55020086804) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `snapshotDate` param
|
|
58
|
-
|
|
59
|
-
* [`486ef4a`](https://github.com/swordev/datatruck/commit/486ef4add27ae1dbfd166b16c257522f43537ecd) Thanks [@juanrgm](https://github.com/juanrgm)! - Resolve params in `include` and `exclude`
|
|
60
|
-
|
|
61
|
-
- [`617dae2`](https://github.com/swordev/datatruck/commit/617dae2c8ed90e6e65e8109f03cfad0e64bd7c02) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `script` task
|
|
62
|
-
|
|
63
|
-
### Patch Changes
|
|
64
|
-
|
|
65
|
-
- [`d1b3ea9`](https://github.com/swordev/datatruck/commit/d1b3ea9c9540d30898c00490963523a4fbc68193) Thanks [@juanrgm](https://github.com/juanrgm)! - Avoid use gitignore if is not necessary in restic repository
|
|
66
|
-
|
|
67
|
-
## 0.2.0
|
|
68
|
-
|
|
69
|
-
### Minor Changes
|
|
70
|
-
|
|
71
|
-
- [`120460c`](https://github.com/swordev/datatruck/commit/120460c8824cef4184e43f571a4cc0798b899b66) Thanks [@juanrgm](https://github.com/juanrgm)! - Enable `include` option in restic repository
|
|
72
|
-
|
|
73
|
-
### Patch Changes
|
|
74
|
-
|
|
75
|
-
- [`e30ede3`](https://github.com/swordev/datatruck/commit/e30ede371bc7ab3fc1cd47758fdac7a28e8e2705) Thanks [@juanrgm](https://github.com/juanrgm)! - Resolve `RESTIC_PASSWORD_FILE` path
|
|
76
|
-
|
|
77
|
-
* [`8539d28`](https://github.com/swordev/datatruck/commit/8539d285b2c51d700aa811cd772d573fa0d613eb) Thanks [@juanrgm](https://github.com/juanrgm)! - Allow empty backup in restic repository
|
|
78
|
-
|
|
79
|
-
## 0.1.0
|
|
80
|
-
|
|
81
|
-
### Minor Changes
|
|
82
|
-
|
|
83
|
-
- [`88d46cd`](https://github.com/swordev/datatruck/commit/88d46cd56293df4c6fc21a9ad61d6236ac91f325) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `custom` output format
|
|
84
|
-
|
|
85
|
-
### Patch Changes
|
|
86
|
-
|
|
87
|
-
- [`24a1e5e`](https://github.com/swordev/datatruck/commit/24a1e5e86336e7a92556287e49548dc542f0e579) Thanks [@juanrgm](https://github.com/juanrgm)! - Update dependencies
|
|
88
|
-
|
|
89
|
-
## 0.0.6
|
|
90
|
-
|
|
91
|
-
### Patch Changes
|
|
92
|
-
|
|
93
|
-
- [`8de6e6c`](https://github.com/swordev/datatruck/commit/8de6e6ceddb59635cb4634d884e7690eeaf59bac) Thanks [@juanrgm](https://github.com/juanrgm)! - Publish migrations
|
|
94
|
-
|
|
95
|
-
## 0.0.5
|
|
96
|
-
|
|
97
|
-
### Patch Changes
|
|
98
|
-
|
|
99
|
-
- [`78cb0c1`](https://github.com/swordev/datatruck/commit/78cb0c17558543841cd7080dc4c672e6cbfd5634) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix docker image
|
|
100
|
-
|
|
101
|
-
## 0.0.4
|
|
102
|
-
|
|
103
|
-
### Patch Changes
|
|
104
|
-
|
|
105
|
-
- [`d9e534b`](https://github.com/swordev/datatruck/commit/d9e534bd968acf9cd1c93f20e6152c004cb1f23b) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix package file read
|
|
106
|
-
|
|
107
|
-
* [`b882c58`](https://github.com/swordev/datatruck/commit/b882c58183e9a75abc876645e18d7b67186dd662) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix read of migrations
|
|
108
|
-
|
|
109
|
-
## 0.0.3
|
|
110
|
-
|
|
111
|
-
### Patch Changes
|
|
112
|
-
|
|
113
|
-
- [`051a7da`](https://github.com/swordev/datatruck/commit/051a7da225fcfea1c30a4fbfa8aea1b8f5538367) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix dist files
|
|
114
|
-
|
|
115
|
-
## 0.0.2
|
|
116
|
-
|
|
117
|
-
### Patch Changes
|
|
118
|
-
|
|
119
|
-
- [`0911351`](https://github.com/swordev/datatruck/commit/09113517e1a77f2d2a1e19e4c3d9af7da1e28415) Thanks [@juanrgm](https://github.com/juanrgm)! - Publish docker image
|