@datatruck/cli 0.21.0 → 0.22.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 +2 -3
- package/Action/BackupAction.js +16 -20
- package/Action/RestoreAction.d.ts +3 -1
- package/Action/RestoreAction.js +5 -5
- package/Command/BackupCommand.d.ts +1 -1
- package/Command/BackupCommand.js +1 -1
- package/Command/RestoreCommand.d.ts +1 -1
- package/Command/RestoreCommand.js +1 -1
- package/Error/AppError.d.ts +1 -0
- package/Error/AppError.js +8 -0
- package/JsonSchema/JsonSchema.js +1 -1
- package/Repository/DatatruckRepository.d.ts +3 -0
- package/Repository/DatatruckRepository.js +30 -12
- package/Task/MysqlDumpTask.d.ts +13 -15
- package/Task/MysqlDumpTask.js +207 -149
- package/Task/PostgresqlDumpTask.js +1 -1
- package/Task/SqlDumpTaskAbstract.d.ts +5 -2
- package/Task/SqlDumpTaskAbstract.js +4 -2
- package/config.schema.json +78 -4
- package/package.json +1 -1
- package/utils/cli.js +3 -1
- package/utils/datatruck/config.d.ts +1 -1
- package/utils/fs.d.ts +4 -1
- package/utils/fs.js +21 -6
- package/utils/mysql.d.ts +39 -0
- package/utils/mysql.js +211 -0
- package/utils/string.d.ts +5 -1
- package/utils/string.js +28 -6
- package/utils/tar.js +38 -33
package/Task/MysqlDumpTask.js
CHANGED
|
@@ -2,165 +2,223 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MysqlDumpTask = exports.mysqlDumpTaskDefinition = exports.mysqlDumpTaskName = void 0;
|
|
4
4
|
const AppError_1 = require("../Error/AppError");
|
|
5
|
-
const
|
|
5
|
+
const cli_1 = require("../utils/cli");
|
|
6
|
+
const config_1 = require("../utils/datatruck/config");
|
|
6
7
|
const fs_1 = require("../utils/fs");
|
|
7
|
-
const
|
|
8
|
+
const math_1 = require("../utils/math");
|
|
9
|
+
const mysql_1 = require("../utils/mysql");
|
|
10
|
+
const string_1 = require("../utils/string");
|
|
8
11
|
const SqlDumpTaskAbstract_1 = require("./SqlDumpTaskAbstract");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
12
|
+
const TaskAbstract_1 = require("./TaskAbstract");
|
|
13
|
+
const assert_1 = require("assert");
|
|
14
|
+
const promises_1 = require("fs/promises");
|
|
15
|
+
const path_1 = require("path");
|
|
11
16
|
exports.mysqlDumpTaskName = "mysql-dump";
|
|
12
|
-
exports.mysqlDumpTaskDefinition = {
|
|
13
|
-
|
|
17
|
+
exports.mysqlDumpTaskDefinition = (0, SqlDumpTaskAbstract_1.sqlDumpTaskDefinition)({
|
|
18
|
+
dataFormat: { enum: ["csv", "sql"] },
|
|
19
|
+
csvSharedPath: { type: "string" },
|
|
20
|
+
});
|
|
21
|
+
const suffix = {
|
|
22
|
+
database: ".database.sql",
|
|
23
|
+
stored: ".stored-programs.sql",
|
|
24
|
+
table: ".table.sql",
|
|
25
|
+
tableData: ".table-data.csv",
|
|
26
|
+
tableSchema: ".table-schema.sql",
|
|
14
27
|
};
|
|
15
|
-
class MysqlDumpTask extends
|
|
16
|
-
async
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
...(this.config.port ? [`--port=${this.config.port}`] : []),
|
|
21
|
-
`--user=${this.config.username}`,
|
|
22
|
-
`--password=${password ?? ""}`,
|
|
23
|
-
...(database && this.config.database ? [this.config.database] : []),
|
|
24
|
-
];
|
|
25
|
-
}
|
|
26
|
-
async onDatabaseIsEmpty(name) {
|
|
27
|
-
const [total] = await this.fetchValues(`
|
|
28
|
-
SELECT
|
|
29
|
-
COUNT(*) AS total
|
|
30
|
-
FROM
|
|
31
|
-
information_schema.tables
|
|
32
|
-
WHERE
|
|
33
|
-
table_schema = '${name}'
|
|
34
|
-
`);
|
|
35
|
-
return Number(total) ? false : true;
|
|
36
|
-
}
|
|
37
|
-
async onCreateDatabase(database) {
|
|
38
|
-
const query = `
|
|
39
|
-
CREATE DATABASE IF NOT EXISTS \`${database.name}\`
|
|
40
|
-
CHARACTER SET ${database.charset ?? "utf8"}
|
|
41
|
-
COLLATE ${database.charset ?? "utf8_general_ci"}
|
|
42
|
-
`;
|
|
43
|
-
await this.onExecQuery(query);
|
|
44
|
-
}
|
|
45
|
-
async onExecQuery(query) {
|
|
46
|
-
return await (0, process_1.exec)("mysql", [
|
|
47
|
-
...(await this.buildConnectionArgs()),
|
|
48
|
-
"-e",
|
|
49
|
-
query.replace(/\s{1,}/g, " "),
|
|
50
|
-
"-N",
|
|
51
|
-
], undefined, {
|
|
52
|
-
log: this.verbose,
|
|
53
|
-
stderr: {
|
|
54
|
-
toExitCode: true,
|
|
55
|
-
},
|
|
56
|
-
stdout: {
|
|
57
|
-
save: true,
|
|
58
|
-
},
|
|
28
|
+
class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
|
|
29
|
+
async onBackup(data) {
|
|
30
|
+
const sql = (0, mysql_1.createMysqlCli)({
|
|
31
|
+
...this.config,
|
|
32
|
+
verbose: data.options.verbose,
|
|
59
33
|
});
|
|
34
|
+
const tableNames = await sql.fetchTableNames(this.config.database, this.config.includeTables, this.config.excludeTables);
|
|
35
|
+
const outputPath = data.package.path;
|
|
36
|
+
(0, assert_1.ok)(typeof outputPath === "string");
|
|
37
|
+
const dataFormat = this.config.dataFormat ?? "sql";
|
|
38
|
+
await (0, promises_1.mkdir)(outputPath, { recursive: true });
|
|
39
|
+
const sharedDir = dataFormat === "csv"
|
|
40
|
+
? await sql.initSharedDir(this.config.csvSharedPath)
|
|
41
|
+
: undefined;
|
|
42
|
+
if (this.config.oneFileByTable || sharedDir) {
|
|
43
|
+
let current = 0;
|
|
44
|
+
for (const tableName of tableNames) {
|
|
45
|
+
await data.onProgress({
|
|
46
|
+
relative: {
|
|
47
|
+
description: "Exporting",
|
|
48
|
+
payload: tableName,
|
|
49
|
+
},
|
|
50
|
+
absolute: {
|
|
51
|
+
total: tableNames.length,
|
|
52
|
+
current,
|
|
53
|
+
percent: (0, math_1.progressPercent)(tableNames.length, current),
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
if (sharedDir) {
|
|
57
|
+
const tableSharedPath = (0, path_1.join)(sharedDir, `tmp-dtt-backup-${data.snapshot.id.slice(0, 8)}-${tableName}`);
|
|
58
|
+
if (data.options.verbose)
|
|
59
|
+
(0, cli_1.logExec)("mkdir", [tableSharedPath]);
|
|
60
|
+
await (0, promises_1.mkdir)(tableSharedPath, { recursive: true });
|
|
61
|
+
try {
|
|
62
|
+
await sql.csvDump({
|
|
63
|
+
sharedPath: tableSharedPath,
|
|
64
|
+
items: [tableName],
|
|
65
|
+
database: this.config.database,
|
|
66
|
+
});
|
|
67
|
+
const files = await (0, promises_1.readdir)(tableSharedPath);
|
|
68
|
+
const schemaFile = `${tableName}.sql`;
|
|
69
|
+
const dataFile = `${tableName}.txt`;
|
|
70
|
+
const successCsvDump = files.length === 2 &&
|
|
71
|
+
files.every((file) => file === schemaFile || file === dataFile);
|
|
72
|
+
if (!successCsvDump)
|
|
73
|
+
throw new AppError_1.AppError(`Invalid csv dump files: ${files.join(", ")}`);
|
|
74
|
+
await (0, promises_1.rename)((0, path_1.join)(tableSharedPath, schemaFile), (0, path_1.join)(outputPath, `${tableName}${suffix.tableSchema}`));
|
|
75
|
+
await (0, promises_1.rename)((0, path_1.join)(tableSharedPath, dataFile), (0, path_1.join)(outputPath, `${tableName}${suffix.tableData}`));
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await (0, promises_1.rm)(tableSharedPath, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const outPath = (0, path_1.join)(outputPath, `${tableName}${suffix.table}`);
|
|
83
|
+
await sql.dump({
|
|
84
|
+
output: outPath,
|
|
85
|
+
items: [tableName],
|
|
86
|
+
database: this.config.database,
|
|
87
|
+
onProgress(progress) {
|
|
88
|
+
data.onProgress({
|
|
89
|
+
relative: {
|
|
90
|
+
description: "Exporting",
|
|
91
|
+
payload: tableName,
|
|
92
|
+
current: progress.totalBytes,
|
|
93
|
+
format: "size",
|
|
94
|
+
},
|
|
95
|
+
absolute: {
|
|
96
|
+
total: tableNames.length,
|
|
97
|
+
current,
|
|
98
|
+
percent: (0, math_1.progressPercent)(tableNames.length, current),
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
current++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
await data.onProgress({
|
|
109
|
+
relative: { description: "Exporting" },
|
|
110
|
+
});
|
|
111
|
+
await sql.dump({
|
|
112
|
+
output: (0, path_1.join)(outputPath, `${this.config.database}${suffix.database}`),
|
|
113
|
+
items: tableNames,
|
|
114
|
+
database: this.config.database,
|
|
115
|
+
onProgress: (progress) => data.onProgress({
|
|
116
|
+
absolute: {
|
|
117
|
+
description: "Exporting in single file",
|
|
118
|
+
current: progress.totalBytes,
|
|
119
|
+
format: "size",
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (this.config.storedPrograms ?? true) {
|
|
125
|
+
await data.onProgress({
|
|
126
|
+
relative: { description: "Exporting stored programs" },
|
|
127
|
+
});
|
|
128
|
+
await sql.dump({
|
|
129
|
+
database: this.config.database,
|
|
130
|
+
output: (0, path_1.join)(outputPath, `${this.config.database}${suffix.stored}`),
|
|
131
|
+
onlyStoredPrograms: true,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
60
134
|
}
|
|
61
|
-
async
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
FROM
|
|
66
|
-
information_schema.tables
|
|
67
|
-
WHERE
|
|
68
|
-
table_schema = '${database}'
|
|
69
|
-
ORDER BY
|
|
70
|
-
table_name
|
|
71
|
-
`);
|
|
72
|
-
}
|
|
73
|
-
async onExportTables(tableNames, output, onProgress) {
|
|
74
|
-
const stream = (0, fs_2.createWriteStream)(output);
|
|
75
|
-
await Promise.all([
|
|
76
|
-
new Promise((resolve, reject) => {
|
|
77
|
-
stream.on("close", resolve);
|
|
78
|
-
stream.on("error", reject);
|
|
79
|
-
}),
|
|
80
|
-
await (0, process_1.exec)("mysqldump", [
|
|
81
|
-
...(await this.buildConnectionArgs()),
|
|
82
|
-
"--lock-tables=false",
|
|
83
|
-
"--skip-add-drop-table=false",
|
|
84
|
-
...tableNames,
|
|
85
|
-
], null, {
|
|
86
|
-
pipe: {
|
|
87
|
-
stream,
|
|
88
|
-
onWriteProgress: onProgress,
|
|
89
|
-
},
|
|
90
|
-
log: {
|
|
91
|
-
exec: this.verbose,
|
|
92
|
-
stderr: this.verbose,
|
|
93
|
-
allToStderr: true,
|
|
94
|
-
},
|
|
95
|
-
stderr: {
|
|
96
|
-
toExitCode: true,
|
|
97
|
-
},
|
|
98
|
-
}),
|
|
99
|
-
]);
|
|
100
|
-
const headerContents = await (0, fs_1.readPartialFile)(output, [0, 100]);
|
|
101
|
-
const footerContents = await (0, fs_1.readPartialFile)(output, [-100]);
|
|
102
|
-
const successHeader = headerContents.split(/\r?\n/).some((line) => {
|
|
103
|
-
const firstLine = line.trim().toLowerCase();
|
|
104
|
-
return (firstLine.startsWith("-- mysql dump") ||
|
|
105
|
-
firstLine.startsWith("-- mariadb dump"));
|
|
135
|
+
async onRestore(data) {
|
|
136
|
+
const sql = (0, mysql_1.createMysqlCli)({
|
|
137
|
+
...this.config,
|
|
138
|
+
verbose: data.options.verbose,
|
|
106
139
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
const restorePath = data.package.restorePath;
|
|
141
|
+
(0, assert_1.ok)(typeof restorePath === "string");
|
|
142
|
+
const params = {
|
|
143
|
+
packageName: data.package.name,
|
|
144
|
+
snapshotId: data.options.snapshotId,
|
|
145
|
+
snapshotDate: data.snapshot.date,
|
|
146
|
+
action: "restore",
|
|
147
|
+
database: undefined,
|
|
148
|
+
};
|
|
149
|
+
const database = {
|
|
150
|
+
name: (0, config_1.resolveDatabaseName)(this.config.database, params),
|
|
151
|
+
};
|
|
152
|
+
if (this.config.targetDatabase)
|
|
153
|
+
database.name = (0, config_1.resolveDatabaseName)(this.config.targetDatabase.name, {
|
|
154
|
+
...params,
|
|
155
|
+
database: database.name,
|
|
156
|
+
});
|
|
157
|
+
const suffixes = Object.values(suffix);
|
|
158
|
+
const files = (await (0, fs_1.readDir)(restorePath)).filter((f) => (0, string_1.endsWith)(f, suffixes));
|
|
159
|
+
// Database check
|
|
160
|
+
if (files.some((f) => f.endsWith(suffix.database)) &&
|
|
161
|
+
!(await sql.isDatabaseEmpty(database.name)))
|
|
162
|
+
throw new AppError_1.AppError(`Target database is not empty: ${database.name}`);
|
|
163
|
+
// Table check
|
|
164
|
+
const restoreTables = [
|
|
165
|
+
...new Set(...files
|
|
166
|
+
.filter((f) => (0, string_1.endsWith)(f, [suffix.table, suffix.tableSchema, suffix.tableData]))
|
|
167
|
+
.map((f) => f.split(".")[0])),
|
|
168
|
+
];
|
|
169
|
+
const serverTables = await sql.fetchTableNames(database.name);
|
|
170
|
+
const errorTables = restoreTables.filter((v) => serverTables.includes(v));
|
|
171
|
+
if (errorTables.length)
|
|
172
|
+
throw new AppError_1.AppError(`Target table already exists: ${errorTables.join(", ")}`);
|
|
173
|
+
// Data check
|
|
174
|
+
const dataFiles = files.filter((f) => f.endsWith(suffix.tableData));
|
|
175
|
+
const sharedDir = dataFiles.length
|
|
176
|
+
? await sql.initSharedDir(this.config.csvSharedPath)
|
|
177
|
+
: undefined;
|
|
178
|
+
await sql.createDatabase(database);
|
|
179
|
+
if (data.options.verbose)
|
|
180
|
+
(0, cli_1.logExec)("readdir", [restorePath]);
|
|
181
|
+
let current = 0;
|
|
182
|
+
for (const file of files.filter((f) => !f.endsWith(suffix.tableData))) {
|
|
183
|
+
const path = (0, path_1.join)(restorePath, file);
|
|
184
|
+
data.onProgress({
|
|
185
|
+
relative: {
|
|
186
|
+
description: "Importing",
|
|
187
|
+
payload: file,
|
|
138
188
|
},
|
|
139
|
-
|
|
140
|
-
|
|
189
|
+
absolute: {
|
|
190
|
+
total: files.length,
|
|
191
|
+
current: current,
|
|
192
|
+
percent: (0, math_1.progressPercent)(files.length, current),
|
|
141
193
|
},
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
colorize: true,
|
|
154
|
-
stderr: true,
|
|
155
|
-
lineSalt: true,
|
|
156
|
-
});
|
|
194
|
+
});
|
|
195
|
+
await sql.importFile(path, database.name);
|
|
196
|
+
current++;
|
|
197
|
+
}
|
|
198
|
+
for (const file of dataFiles) {
|
|
199
|
+
const filePath = (0, path_1.join)(restorePath, file);
|
|
200
|
+
const tableName = file.slice(0, suffix.tableData.length * -1);
|
|
201
|
+
data.onProgress({
|
|
202
|
+
relative: {
|
|
203
|
+
description: "Importing",
|
|
204
|
+
payload: file,
|
|
157
205
|
},
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
206
|
+
absolute: {
|
|
207
|
+
total: files.length,
|
|
208
|
+
current: current,
|
|
209
|
+
percent: (0, math_1.progressPercent)(files.length, current),
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
const sharedFilePath = (0, path_1.join)(sharedDir, `tmp-dtt-restore-${data.snapshot.id.slice(0, 8)}-${tableName}.data.csv`);
|
|
213
|
+
try {
|
|
214
|
+
await (0, promises_1.rename)(filePath, sharedFilePath);
|
|
215
|
+
await sql.importCsvFile(sharedFilePath, database.name, tableName);
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
await (0, promises_1.rm)(sharedFilePath);
|
|
219
|
+
}
|
|
220
|
+
current++;
|
|
221
|
+
}
|
|
164
222
|
}
|
|
165
223
|
}
|
|
166
224
|
exports.MysqlDumpTask = MysqlDumpTask;
|
|
@@ -81,7 +81,7 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
|
|
|
81
81
|
stream.on("error", reject);
|
|
82
82
|
}),
|
|
83
83
|
(0, process_1.exec)("pg_dump", [
|
|
84
|
-
...(await this.buildConnectionArgs()),
|
|
84
|
+
...(await this.buildConnectionArgs(this.config.database)),
|
|
85
85
|
...(tableNames?.flatMap((v) => ["-t", v]) ?? []),
|
|
86
86
|
], null, {
|
|
87
87
|
pipe: { stream, onWriteProgress: onProgress },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { exec } from "../utils/process";
|
|
2
2
|
import { BackupDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
|
|
3
|
-
import { JSONSchema7 } from "json-schema";
|
|
3
|
+
import { JSONSchema7, JSONSchema7Definition } from "json-schema";
|
|
4
4
|
export type TargetDatabaseType = {
|
|
5
5
|
name: string;
|
|
6
6
|
charset?: string;
|
|
@@ -14,13 +14,16 @@ export type SqlDumpTaskConfigType = {
|
|
|
14
14
|
port?: number;
|
|
15
15
|
database: string;
|
|
16
16
|
username: string;
|
|
17
|
+
/**
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
17
20
|
storedPrograms?: boolean;
|
|
18
21
|
targetDatabase?: TargetDatabaseType;
|
|
19
22
|
includeTables?: string[];
|
|
20
23
|
excludeTables?: string[];
|
|
21
24
|
oneFileByTable?: boolean;
|
|
22
25
|
};
|
|
23
|
-
export declare const sqlDumpTaskDefinition: JSONSchema7;
|
|
26
|
+
export declare const sqlDumpTaskDefinition: (props?: Record<string, JSONSchema7Definition>) => JSONSchema7;
|
|
24
27
|
export declare abstract class SqlDumpTaskAbstract<TConfig extends SqlDumpTaskConfigType> extends TaskAbstract<TConfig> {
|
|
25
28
|
protected verbose?: boolean;
|
|
26
29
|
fetchPassword(): Promise<string | null>;
|
|
@@ -12,11 +12,12 @@ const assert_1 = require("assert");
|
|
|
12
12
|
const promises_1 = require("fs/promises");
|
|
13
13
|
const micromatch_1 = require("micromatch");
|
|
14
14
|
const path_1 = require("path");
|
|
15
|
-
|
|
15
|
+
const sqlDumpTaskDefinition = (props = {}) => ({
|
|
16
16
|
type: "object",
|
|
17
17
|
required: ["password", "hostname", "username", "database"],
|
|
18
18
|
additionalProperties: false,
|
|
19
19
|
properties: {
|
|
20
|
+
...props,
|
|
20
21
|
password: {
|
|
21
22
|
anyOf: [
|
|
22
23
|
{
|
|
@@ -50,7 +51,8 @@ exports.sqlDumpTaskDefinition = {
|
|
|
50
51
|
excludeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
51
52
|
oneFileByTable: { type: "boolean" },
|
|
52
53
|
},
|
|
53
|
-
};
|
|
54
|
+
});
|
|
55
|
+
exports.sqlDumpTaskDefinition = sqlDumpTaskDefinition;
|
|
54
56
|
function serializeSqlFile(input) {
|
|
55
57
|
if (input.database && input.table) {
|
|
56
58
|
return `${input.database}.${input.table}.table.sql`;
|
package/config.schema.json
CHANGED
|
@@ -880,11 +880,85 @@
|
|
|
880
880
|
}
|
|
881
881
|
},
|
|
882
882
|
"mysql-dump-task": {
|
|
883
|
-
"
|
|
884
|
-
|
|
885
|
-
|
|
883
|
+
"type": "object",
|
|
884
|
+
"required": [
|
|
885
|
+
"password",
|
|
886
|
+
"hostname",
|
|
887
|
+
"username",
|
|
888
|
+
"database"
|
|
889
|
+
],
|
|
890
|
+
"additionalProperties": false,
|
|
891
|
+
"properties": {
|
|
892
|
+
"dataFormat": {
|
|
893
|
+
"enum": [
|
|
894
|
+
"csv",
|
|
895
|
+
"sql"
|
|
896
|
+
]
|
|
897
|
+
},
|
|
898
|
+
"csvSharedPath": {
|
|
899
|
+
"type": "string"
|
|
900
|
+
},
|
|
901
|
+
"password": {
|
|
902
|
+
"anyOf": [
|
|
903
|
+
{
|
|
904
|
+
"type": "string"
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
"type": "object",
|
|
908
|
+
"additionalProperties": false,
|
|
909
|
+
"required": [
|
|
910
|
+
"path"
|
|
911
|
+
],
|
|
912
|
+
"properties": {
|
|
913
|
+
"path": {
|
|
914
|
+
"type": "string"
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
]
|
|
919
|
+
},
|
|
920
|
+
"hostname": {
|
|
921
|
+
"type": "string"
|
|
922
|
+
},
|
|
923
|
+
"port": {
|
|
924
|
+
"type": "integer"
|
|
925
|
+
},
|
|
926
|
+
"username": {
|
|
927
|
+
"type": "string"
|
|
928
|
+
},
|
|
929
|
+
"database": {
|
|
930
|
+
"type": "string"
|
|
931
|
+
},
|
|
932
|
+
"targetDatabase": {
|
|
933
|
+
"type": "object",
|
|
934
|
+
"required": [
|
|
935
|
+
"name"
|
|
936
|
+
],
|
|
937
|
+
"properties": {
|
|
938
|
+
"name": {
|
|
939
|
+
"type": "string"
|
|
940
|
+
},
|
|
941
|
+
"charset": {
|
|
942
|
+
"type": "string"
|
|
943
|
+
},
|
|
944
|
+
"collate": {
|
|
945
|
+
"type": "string"
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
"storedPrograms": {
|
|
950
|
+
"type": "boolean"
|
|
951
|
+
},
|
|
952
|
+
"includeTables": {
|
|
953
|
+
"$ref": "#/definitions/stringlist-util"
|
|
954
|
+
},
|
|
955
|
+
"excludeTables": {
|
|
956
|
+
"$ref": "#/definitions/stringlist-util"
|
|
957
|
+
},
|
|
958
|
+
"oneFileByTable": {
|
|
959
|
+
"type": "boolean"
|
|
886
960
|
}
|
|
887
|
-
|
|
961
|
+
}
|
|
888
962
|
},
|
|
889
963
|
"postgresql-dump-task": {
|
|
890
964
|
"allOf": [
|
package/package.json
CHANGED
package/utils/cli.js
CHANGED
|
@@ -65,7 +65,9 @@ function logExec(command, argv = [], env, logToStderr) {
|
|
|
65
65
|
.join(" ")
|
|
66
66
|
: "";
|
|
67
67
|
const text = `+ ${envText ? envText + " " : ""}${chalk_1.default.yellow(`${command} ${argv.join(" ")}`)}`;
|
|
68
|
-
logToStderr
|
|
68
|
+
logToStderr /* && process.env.VITEST !== "true"*/
|
|
69
|
+
? process.stderr.write(`${text}\n`)
|
|
70
|
+
: console.info(text);
|
|
69
71
|
}
|
|
70
72
|
exports.logExec = logExec;
|
|
71
73
|
function resultColumn(error, state) {
|
|
@@ -15,7 +15,7 @@ type ResolvePackagePathParamsType = ResolvePackageParamsType & {
|
|
|
15
15
|
path: string | undefined;
|
|
16
16
|
};
|
|
17
17
|
export declare function resolvePackagePath(value: string, params: ResolvePackagePathParamsType): string;
|
|
18
|
-
type ResolveDatabaseNameParamsType = ResolvePackageParamsType & {
|
|
18
|
+
export type ResolveDatabaseNameParamsType = ResolvePackageParamsType & {
|
|
19
19
|
packageName: string;
|
|
20
20
|
database: string | undefined;
|
|
21
21
|
};
|
package/utils/fs.d.ts
CHANGED
|
@@ -96,12 +96,13 @@ export declare function createFileScanner(options: {
|
|
|
96
96
|
disposed: boolean;
|
|
97
97
|
total: number;
|
|
98
98
|
current: number;
|
|
99
|
-
progress: (description: string, path?: string) => Promise<void>;
|
|
99
|
+
progress: (description: string, path?: string, increment?: boolean) => Promise<void>;
|
|
100
100
|
end: () => Promise<void>;
|
|
101
101
|
start: (cb?: ((entry: Required<Entry>) => any) | undefined) => Promise<void>;
|
|
102
102
|
}>;
|
|
103
103
|
type StreamItem = {
|
|
104
104
|
key: string;
|
|
105
|
+
lines: number;
|
|
105
106
|
stream: WriteStream;
|
|
106
107
|
finished: boolean;
|
|
107
108
|
error?: Error;
|
|
@@ -113,8 +114,10 @@ export declare function createWriteStreamPool(options: {
|
|
|
113
114
|
}): {
|
|
114
115
|
pool: Record<string, StreamItem>;
|
|
115
116
|
path(key: string | number): string | undefined;
|
|
117
|
+
lines(key: string | number): number;
|
|
116
118
|
writeLine(key: string | number, v: string): boolean;
|
|
117
119
|
end(): Promise<void>;
|
|
118
120
|
};
|
|
119
121
|
export declare function countFileLines(path: string): Promise<number>;
|
|
122
|
+
export declare function fetchData<T>(input: T, onPath?: (input: Exclude<T, string>) => string | undefined): Promise<string | null>;
|
|
120
123
|
export {};
|
package/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.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = exports.tmpDir = exports.rmTmpDir = exports.isTmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
|
|
6
|
+
exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = exports.tmpDir = exports.rmTmpDir = exports.isTmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
|
|
7
7
|
const globalData_1 = __importDefault(require("../globalData"));
|
|
8
8
|
const math_1 = require("./math");
|
|
9
9
|
const path_1 = require("./path");
|
|
@@ -43,9 +43,8 @@ function isLocalDir(path) {
|
|
|
43
43
|
}
|
|
44
44
|
exports.isLocalDir = isLocalDir;
|
|
45
45
|
async function mkdirIfNotExists(path) {
|
|
46
|
-
|
|
47
|
-
recursive: true
|
|
48
|
-
});
|
|
46
|
+
if (!(await existsDir(path)))
|
|
47
|
+
await (0, promises_1.mkdir)(path, { recursive: true });
|
|
49
48
|
return path;
|
|
50
49
|
}
|
|
51
50
|
exports.mkdirIfNotExists = mkdirIfNotExists;
|
|
@@ -410,10 +409,10 @@ async function createFileScanner(options) {
|
|
|
410
409
|
disposed: false,
|
|
411
410
|
total: 0,
|
|
412
411
|
current: 0,
|
|
413
|
-
progress: async (description, path) => {
|
|
412
|
+
progress: async (description, path, increment = true) => {
|
|
414
413
|
if (object.disposed)
|
|
415
414
|
return;
|
|
416
|
-
if (path)
|
|
415
|
+
if (path && increment)
|
|
417
416
|
object.current++;
|
|
418
417
|
await options.onProgress({
|
|
419
418
|
relative: {
|
|
@@ -463,6 +462,7 @@ function createWriteStreamPool(options) {
|
|
|
463
462
|
const create = (key) => {
|
|
464
463
|
const item = {
|
|
465
464
|
key,
|
|
465
|
+
lines: 0,
|
|
466
466
|
stream: (0, fs_2.createWriteStream)((0, path_2.join)(options.path, options.onStreamPath ? options.onStreamPath(key) : key)),
|
|
467
467
|
finished: false,
|
|
468
468
|
};
|
|
@@ -484,16 +484,22 @@ function createWriteStreamPool(options) {
|
|
|
484
484
|
throw new Error(`Stream path is not defined: ${key}`);
|
|
485
485
|
return item.stream.path;
|
|
486
486
|
},
|
|
487
|
+
lines(key) {
|
|
488
|
+
const item = pool[key];
|
|
489
|
+
return item?.lines;
|
|
490
|
+
},
|
|
487
491
|
writeLine(key, v) {
|
|
488
492
|
const item = pool[key] || create(key.toString());
|
|
489
493
|
if (item.finished) {
|
|
490
494
|
return false;
|
|
491
495
|
}
|
|
492
496
|
else if (item.written) {
|
|
497
|
+
item.lines++;
|
|
493
498
|
return item.stream.write(`\n${v}`);
|
|
494
499
|
}
|
|
495
500
|
else {
|
|
496
501
|
item.written = true;
|
|
502
|
+
item.lines++;
|
|
497
503
|
return item.stream.write(`${v}`);
|
|
498
504
|
}
|
|
499
505
|
},
|
|
@@ -529,3 +535,12 @@ function countFileLines(path) {
|
|
|
529
535
|
});
|
|
530
536
|
}
|
|
531
537
|
exports.countFileLines = countFileLines;
|
|
538
|
+
async function fetchData(input, onPath) {
|
|
539
|
+
if (typeof input === "string")
|
|
540
|
+
return input;
|
|
541
|
+
const path = onPath?.(input);
|
|
542
|
+
if (typeof path === "string")
|
|
543
|
+
return (await (0, promises_1.readFile)(path)).toString();
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
exports.fetchData = fetchData;
|