@datatruck/cli 0.27.0 → 0.28.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.
Files changed (147) hide show
  1. package/Action/BackupAction.d.ts +69 -34
  2. package/Action/BackupAction.js +284 -244
  3. package/Action/CleanCacheAction.d.ts +8 -4
  4. package/Action/CleanCacheAction.js +8 -5
  5. package/Action/ConfigAction.d.ts +12 -5
  6. package/Action/ConfigAction.js +14 -18
  7. package/Action/CopyAction.d.ts +49 -0
  8. package/Action/CopyAction.js +144 -0
  9. package/Action/InitAction.d.ts +3 -3
  10. package/Action/InitAction.js +9 -9
  11. package/Action/PruneAction.d.ts +9 -9
  12. package/Action/PruneAction.js +39 -23
  13. package/Action/RestoreAction.d.ts +48 -23
  14. package/Action/RestoreAction.js +158 -195
  15. package/Action/SnapshotsAction.d.ts +8 -8
  16. package/Action/SnapshotsAction.js +8 -8
  17. package/CHANGELOG.md +495 -0
  18. package/Command/BackupCommand.d.ts +6 -4
  19. package/Command/BackupCommand.js +9 -26
  20. package/Command/CleanCacheCommand.d.ts +4 -4
  21. package/Command/CleanCacheCommand.js +26 -5
  22. package/Command/CommandAbstract.d.ts +10 -7
  23. package/Command/CommandAbstract.js +4 -1
  24. package/Command/ConfigCommand.d.ts +6 -9
  25. package/Command/ConfigCommand.js +13 -8
  26. package/Command/CopyCommand.d.ts +15 -0
  27. package/Command/CopyCommand.js +61 -0
  28. package/Command/InitCommand.d.ts +4 -4
  29. package/Command/InitCommand.js +11 -15
  30. package/Command/PruneCommand.d.ts +3 -3
  31. package/Command/PruneCommand.js +13 -12
  32. package/Command/RestoreCommand.js +9 -17
  33. package/Command/SnapshotsCommand.d.ts +4 -4
  34. package/Command/SnapshotsCommand.js +16 -15
  35. package/Command/StartServerCommand.d.ts +3 -3
  36. package/Config/Config.d.ts +9 -0
  37. package/Config/Config.js +17 -0
  38. package/Config/PrunePolicyConfig.d.ts +2 -2
  39. package/Factory/CommandFactory.d.ts +27 -34
  40. package/Factory/CommandFactory.js +27 -54
  41. package/Factory/RepositoryFactory.d.ts +1 -1
  42. package/Factory/RepositoryFactory.js +3 -3
  43. package/Factory/TaskFactory.d.ts +1 -1
  44. package/Factory/TaskFactory.js +3 -3
  45. package/Repository/DatatruckRepository.d.ts +9 -8
  46. package/Repository/DatatruckRepository.js +42 -25
  47. package/Repository/GitRepository.d.ts +9 -8
  48. package/Repository/GitRepository.js +22 -25
  49. package/Repository/RepositoryAbstract.d.ts +39 -37
  50. package/Repository/RepositoryAbstract.js +4 -5
  51. package/Repository/ResticRepository.d.ts +9 -8
  52. package/Repository/ResticRepository.js +30 -28
  53. package/Task/GitTask.d.ts +6 -7
  54. package/Task/GitTask.js +24 -30
  55. package/Task/MariadbTask.d.ts +4 -5
  56. package/Task/MariadbTask.js +26 -32
  57. package/Task/MssqlTask.d.ts +5 -3
  58. package/Task/MssqlTask.js +11 -12
  59. package/Task/MysqlDumpTask.d.ts +10 -3
  60. package/Task/MysqlDumpTask.js +107 -31
  61. package/Task/ScriptTask.d.ts +23 -18
  62. package/Task/ScriptTask.js +34 -24
  63. package/Task/SqlDumpTaskAbstract.d.ts +8 -3
  64. package/Task/SqlDumpTaskAbstract.js +31 -19
  65. package/Task/TaskAbstract.d.ts +24 -25
  66. package/Task/TaskAbstract.js +6 -10
  67. package/cli.js +13 -5
  68. package/config.schema.json +86 -1
  69. package/package.json +4 -5
  70. package/utils/DataFormat.d.ts +23 -12
  71. package/utils/DataFormat.js +36 -14
  72. package/utils/cli.d.ts +2 -9
  73. package/utils/cli.js +9 -52
  74. package/utils/datatruck/client.d.ts +2 -0
  75. package/utils/datatruck/client.js +3 -0
  76. package/utils/datatruck/config.d.ts +2 -0
  77. package/utils/datatruck/config.js +18 -3
  78. package/utils/datatruck/paths.d.ts +5 -9
  79. package/utils/datatruck/paths.js +2 -2
  80. package/utils/datatruck/snapshot.d.ts +2 -2
  81. package/utils/date.d.ts +7 -3
  82. package/utils/date.js +22 -14
  83. package/utils/fs.d.ts +16 -11
  84. package/utils/fs.js +81 -48
  85. package/utils/list.d.ts +64 -0
  86. package/utils/list.js +145 -0
  87. package/utils/mysql.d.ts +2 -0
  88. package/utils/mysql.js +21 -2
  89. package/utils/process.d.ts +1 -0
  90. package/utils/process.js +24 -31
  91. package/utils/progress.d.ts +33 -0
  92. package/utils/progress.js +113 -0
  93. package/utils/steps.d.ts +11 -0
  94. package/utils/steps.js +22 -10
  95. package/utils/stream.d.ts +7 -0
  96. package/utils/stream.js +10 -0
  97. package/utils/string.d.ts +0 -1
  98. package/utils/string.js +1 -13
  99. package/utils/tar.d.ts +10 -3
  100. package/utils/tar.js +70 -44
  101. package/utils/temp.d.ts +26 -0
  102. package/utils/temp.js +133 -0
  103. package/utils/virtual-fs.d.ts +6 -2
  104. package/utils/virtual-fs.js +6 -0
  105. package/Action/BackupSessionsAction.d.ts +0 -13
  106. package/Action/BackupSessionsAction.js +0 -18
  107. package/Action/RestoreSessionsAction.d.ts +0 -13
  108. package/Action/RestoreSessionsAction.js +0 -18
  109. package/Command/BackupSessionsCommand.d.ts +0 -12
  110. package/Command/BackupSessionsCommand.js +0 -92
  111. package/Command/RestoreSessionsCommand.d.ts +0 -12
  112. package/Command/RestoreSessionsCommand.js +0 -91
  113. package/Decorator/EntityDecorator.d.ts +0 -11
  114. package/Decorator/EntityDecorator.js +0 -17
  115. package/Entity/BackupSessionEntity.d.ts +0 -6
  116. package/Entity/BackupSessionEntity.js +0 -25
  117. package/Entity/BackupSessionRepositoryEntity.d.ts +0 -6
  118. package/Entity/BackupSessionRepositoryEntity.js +0 -25
  119. package/Entity/BackupSessionTaskEntity.d.ts +0 -5
  120. package/Entity/BackupSessionTaskEntity.js +0 -24
  121. package/Entity/CrudEntityAbstract.d.ts +0 -5
  122. package/Entity/CrudEntityAbstract.js +0 -9
  123. package/Entity/RestoreSessionEntity.d.ts +0 -5
  124. package/Entity/RestoreSessionEntity.js +0 -24
  125. package/Entity/RestoreSessionRepositoryEntity.d.ts +0 -6
  126. package/Entity/RestoreSessionRepositoryEntity.js +0 -25
  127. package/Entity/RestoreSessionTaskEntity.d.ts +0 -5
  128. package/Entity/RestoreSessionTaskEntity.js +0 -24
  129. package/Entity/StateEntityAbstract.d.ts +0 -9
  130. package/Entity/StateEntityAbstract.js +0 -12
  131. package/Factory/EntityFactory.d.ts +0 -6
  132. package/Factory/EntityFactory.js +0 -40
  133. package/SessionDriver/ConsoleSessionDriver.d.ts +0 -42
  134. package/SessionDriver/ConsoleSessionDriver.js +0 -208
  135. package/SessionDriver/SessionDriverAbstract.d.ts +0 -77
  136. package/SessionDriver/SessionDriverAbstract.js +0 -28
  137. package/SessionDriver/SqliteSessionDriver.d.ts +0 -20
  138. package/SessionDriver/SqliteSessionDriver.js +0 -173
  139. package/SessionManager/BackupSessionManager.d.ts +0 -45
  140. package/SessionManager/BackupSessionManager.js +0 -218
  141. package/SessionManager/RestoreSessionManager.d.ts +0 -47
  142. package/SessionManager/RestoreSessionManager.js +0 -218
  143. package/SessionManager/SessionManagerAbstract.d.ts +0 -18
  144. package/SessionManager/SessionManagerAbstract.js +0 -36
  145. package/migrations/001-initial.sql +0 -98
  146. package/utils/entity.d.ts +0 -4
  147. package/utils/entity.js +0 -10
@@ -7,6 +7,7 @@ const fs_1 = require("../utils/fs");
7
7
  const math_1 = require("../utils/math");
8
8
  const process_1 = require("../utils/process");
9
9
  const tar_1 = require("../utils/tar");
10
+ const temp_1 = require("../utils/temp");
10
11
  const TaskAbstract_1 = require("./TaskAbstract");
11
12
  const assert_1 = require("assert");
12
13
  const fs_2 = require("fs");
@@ -105,19 +106,13 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
105
106
  get command() {
106
107
  return this.config.command ?? "mariabackup";
107
108
  }
108
- async onBeforeBackup() {
109
- return {
110
- targetPath: await this.mkTmpDir(MariadbTask.name),
111
- };
112
- }
113
- async onBackup(data) {
109
+ async backup(data) {
114
110
  this.verbose = data.options.verbose;
115
111
  const config = this.config;
116
112
  const command = this.command;
117
113
  const sourcePath = data.package.path;
118
- const targetPath = data.targetPath;
114
+ const snapshotPath = await (0, temp_1.mkTmpDir)(exports.mariadbTaskName, "task", "backup", "snapshot");
119
115
  (0, assert_1.ok)(typeof sourcePath === "string");
120
- (0, assert_1.ok)(typeof targetPath === "string");
121
116
  const { parallel, compress } = normalizeConfig(config);
122
117
  const args = [
123
118
  `--backup`,
@@ -135,7 +130,7 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
135
130
  args.push(`--stream=xbstream`);
136
131
  }
137
132
  else {
138
- args.push(`--target-dir=${targetPath}`);
133
+ args.push(`--target-dir=${snapshotPath}`);
139
134
  }
140
135
  if (config.includeDatabases)
141
136
  args.push(`--databases=${config.includeDatabases.join(" ")}`);
@@ -164,7 +159,7 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
164
159
  const matches = pathRegex.exec(text);
165
160
  if (matches)
166
161
  current++;
167
- await data.onProgress({
162
+ data.onProgress({
168
163
  relative: {
169
164
  payload: matches ? matches[1] : text,
170
165
  },
@@ -177,9 +172,9 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
177
172
  }
178
173
  };
179
174
  const stats = { xbFiles: total };
180
- await (0, promises_1.writeFile)((0, path_1.join)(targetPath, "stats.dtt.json"), JSON.stringify(stats));
175
+ await (0, promises_1.writeFile)((0, path_1.join)(snapshotPath, "stats.dtt.json"), JSON.stringify(stats));
181
176
  if (compress) {
182
- const p0 = (0, fs_2.createWriteStream)((0, path_1.join)(targetPath, "db.xb.gz"));
177
+ const p0 = (0, fs_2.createWriteStream)((0, path_1.join)(snapshotPath, "db.xb.gz"));
183
178
  p1 = (0, process_1.createProcess)(command, args, {
184
179
  $log: {
185
180
  exec: this.verbose,
@@ -210,23 +205,22 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
210
205
  $onExitCode: (code) => `Exit code: ${code} - ${lastLineText}`,
211
206
  });
212
207
  await p1;
213
- await (0, process_1.exec)(command, [`--prepare`, `--target-dir=${targetPath}`], undefined, {
208
+ await (0, process_1.exec)(command, [`--prepare`, `--target-dir=${snapshotPath}`], undefined, {
214
209
  log: this.verbose,
215
210
  stderr: { onData: () => { } },
216
211
  });
217
212
  }
213
+ return { snapshotPath };
218
214
  }
219
- async onRestore(data) {
215
+ async restore(data) {
220
216
  this.verbose = data.options.verbose;
221
- const restorePath = data.package.restorePath;
222
- (0, assert_1.ok)(typeof restorePath === "string");
223
- await (0, fs_1.mkdirIfNotExists)(restorePath);
217
+ const snapshotPath = data.snapshotPath;
224
218
  const removeFiles = [];
225
219
  let files = [];
226
220
  const reloadFiles = async (data = {}) => {
227
221
  if (data.removeFile)
228
222
  removeFiles.push(data.removeFile);
229
- return (files = (await (0, fs_1.readDir)(restorePath)).filter((v) => !removeFiles.includes(v)));
223
+ return (files = (await (0, fs_1.readDir)(snapshotPath)).filter((v) => !removeFiles.includes(v)));
230
224
  };
231
225
  await reloadFiles();
232
226
  const absolute = {
@@ -241,7 +235,7 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
241
235
  const statsFile = files.find((file) => file === "stats.dtt.json");
242
236
  let stats;
243
237
  if (statsFile) {
244
- const statsFilePath = (0, path_1.join)(restorePath, statsFile);
238
+ const statsFilePath = (0, path_1.join)(snapshotPath, statsFile);
245
239
  const statsBuffer = await (0, promises_1.readFile)(statsFilePath);
246
240
  stats = JSON.parse(statsBuffer.toString());
247
241
  await reloadFiles({ removeFile: statsFile });
@@ -253,16 +247,16 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
253
247
  if (files.length === 1 && zipFile) {
254
248
  absolute.description = "Extracting";
255
249
  absolute.payload = zipFile;
256
- await data.onProgress({
250
+ data.onProgress({
257
251
  absolute,
258
252
  });
259
253
  await (0, tar_1.extractTar)({
260
- input: (0, path_1.join)(restorePath, zipFile),
254
+ input: (0, path_1.join)(snapshotPath, zipFile),
261
255
  decompress: true,
262
- output: restorePath,
256
+ output: snapshotPath,
263
257
  verbose: this.verbose,
264
- async onEntry(item) {
265
- await data.onProgress({
258
+ onEntry(item) {
259
+ data.onProgress({
266
260
  absolute,
267
261
  relative: {
268
262
  payload: item.path,
@@ -279,23 +273,23 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
279
273
  absolute.current++;
280
274
  absolute.percent = (0, math_1.progressPercent)(absolute.total, absolute.current);
281
275
  if (files.length === 1 && xbFile) {
282
- const xbFilePath = (0, path_1.join)(restorePath, xbFile);
276
+ const xbFilePath = (0, path_1.join)(snapshotPath, xbFile);
283
277
  const xbStream = (0, fs_2.createReadStream)(xbFilePath);
284
278
  removeFiles.push(xbFile);
285
279
  absolute.description = "Extracting stream";
286
280
  absolute.payload = xbFile;
287
- await data.onProgress({
281
+ data.onProgress({
288
282
  absolute,
289
283
  });
290
284
  let currentXbFiles = 0;
291
285
  const { parallel } = normalizeConfig({ parallel: this.config.parallel });
292
- const p1 = (0, process_1.createProcess)("mbstream", ["-x", "-C", restorePath, "-v", "-p", parallel], {
286
+ const p1 = (0, process_1.createProcess)("mbstream", ["-x", "-C", snapshotPath, "-v", "-p", parallel], {
293
287
  $log: this.verbose,
294
288
  $stderr: {
295
289
  parseLines: true,
296
- async onData(line) {
290
+ onData(line) {
297
291
  const { text: path } = parseLine(line);
298
- await data.onProgress({
292
+ data.onProgress({
299
293
  absolute,
300
294
  relative: {
301
295
  payload: path,
@@ -318,10 +312,10 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
318
312
  absolute.percent = (0, math_1.progressPercent)(absolute.total, absolute.current);
319
313
  if (files.length === 1 && xbFile) {
320
314
  absolute.description = "Preparing";
321
- await data.onProgress({
315
+ data.onProgress({
322
316
  absolute,
323
317
  });
324
- await (0, process_1.exec)(this.command, [`--prepare`, `--target-dir=${restorePath}`], undefined, {
318
+ await (0, process_1.exec)(this.command, [`--prepare`, `--target-dir=${snapshotPath}`], undefined, {
325
319
  log: this.verbose,
326
320
  stderr: { onData: () => { } },
327
321
  });
@@ -330,7 +324,7 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
330
324
  removeFiles.push(...files.filter((file) => file.startsWith("ib_logfile")));
331
325
  // Remove files
332
326
  for (const file of removeFiles) {
333
- const filePath = (0, path_1.join)(restorePath, file);
327
+ const filePath = (0, path_1.join)(snapshotPath, file);
334
328
  if (this.verbose)
335
329
  (0, cli_1.logExec)("rm", [filePath]);
336
330
  await (0, promises_1.rm)(filePath);
@@ -1,4 +1,4 @@
1
- import { BackupDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
1
+ import { TaskBackupData, TaskRestoreData, TaskAbstract } from "./TaskAbstract";
2
2
  import { JSONSchema7 } from "json-schema";
3
3
  export type MssqlTaskConfigType = {
4
4
  command?: string;
@@ -17,6 +17,8 @@ export declare class MssqlTask extends TaskAbstract<MssqlTaskConfigType> {
17
17
  private get command();
18
18
  exec(query: string): Promise<string[][]>;
19
19
  fetchDatabaseNames(name?: string): Promise<string[]>;
20
- onBackup(data: BackupDataType): Promise<void>;
21
- onRestore(data: RestoreDataType): Promise<void>;
20
+ backup(data: TaskBackupData): Promise<{
21
+ snapshotPath: string;
22
+ }>;
23
+ restore(data: TaskRestoreData): Promise<void>;
22
24
  }
package/Task/MssqlTask.js CHANGED
@@ -6,8 +6,8 @@ const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
6
6
  const config_1 = require("../utils/datatruck/config");
7
7
  const fs_1 = require("../utils/fs");
8
8
  const process_1 = require("../utils/process");
9
+ const temp_1 = require("../utils/temp");
9
10
  const TaskAbstract_1 = require("./TaskAbstract");
10
- const assert_1 = require("assert");
11
11
  const promises_1 = require("fs/promises");
12
12
  const micromatch_1 = require("micromatch");
13
13
  const path_1 = require("path");
@@ -67,26 +67,25 @@ class MssqlTask extends TaskAbstract_1.TaskAbstract {
67
67
  .map(([database]) => database)
68
68
  .filter((database) => !privateDatabases.includes(database));
69
69
  }
70
- async onBackup(data) {
70
+ async backup(data) {
71
71
  this.verbose = data.options.verbose;
72
- const targetPath = data.package.path;
73
- (0, assert_1.ok)(typeof targetPath === "string");
72
+ if (data.package.path)
73
+ throw new Error(`Path is not required: ${data.package.path}`);
74
+ const snapshotPath = await (0, temp_1.mkTmpDir)(exports.mssqlTaskName, "task", "backup", "snapshot");
74
75
  const databaseNames = (await this.fetchDatabaseNames()).filter((databaseName) => (!this.config.includeDatabases ||
75
76
  (0, micromatch_1.isMatch)(databaseName, this.config.includeDatabases)) &&
76
77
  (!this.config.excludeDatabases ||
77
78
  !(0, micromatch_1.isMatch)(databaseName, this.config.excludeDatabases)));
78
- await (0, fs_1.mkdirIfNotExists)(targetPath);
79
79
  for (const databaseName of databaseNames) {
80
- const databasePath = (0, path_1.join)(targetPath, `${databaseName}${MssqlTask.SUFFIX}`);
80
+ const databasePath = (0, path_1.join)(snapshotPath, `${databaseName}${MssqlTask.SUFFIX}`);
81
81
  await this.exec(`BACKUP DATABASE [${databaseName}] TO DISK='${databasePath}' WITH FORMAT`);
82
82
  }
83
+ return { snapshotPath };
83
84
  }
84
- async onRestore(data) {
85
+ async restore(data) {
85
86
  this.verbose = data.options.verbose;
86
- const restorePath = data.package.restorePath;
87
- (0, assert_1.ok)(typeof restorePath === "string");
88
- await (0, fs_1.mkdirIfNotExists)(restorePath);
89
- const files = await (0, fs_1.readDir)(restorePath);
87
+ const snapshotPath = data.snapshotPath;
88
+ const files = await (0, fs_1.readDir)(snapshotPath);
90
89
  for (const file of files) {
91
90
  if (!file.endsWith(MssqlTask.SUFFIX))
92
91
  continue;
@@ -99,7 +98,7 @@ class MssqlTask extends TaskAbstract_1.TaskAbstract {
99
98
  snapshotId: data.options.snapshotId,
100
99
  snapshotDate: data.snapshot.date,
101
100
  });
102
- const databasePath = (0, path_1.join)(restorePath, file);
101
+ const databasePath = (0, path_1.join)(snapshotPath, file);
103
102
  const exists = await this.fetchDatabaseNames(databaseName);
104
103
  if (exists.length)
105
104
  throw new AppError_1.AppError(`Target database already exists: ${databaseName}`);
@@ -1,5 +1,6 @@
1
+ import { CompressOptions } from "../utils/tar";
1
2
  import { SqlDumpTaskConfigType } from "./SqlDumpTaskAbstract";
2
- import { BackupDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
3
+ import { TaskBackupData, TaskPrepareRestoreData, TaskRestoreData, TaskAbstract } from "./TaskAbstract";
3
4
  export declare const mysqlDumpTaskName = "mysql-dump";
4
5
  export type MysqlDumpTaskConfigType = {
5
6
  /**
@@ -11,9 +12,15 @@ export type MysqlDumpTaskConfigType = {
11
12
  * @default 1
12
13
  */
13
14
  concurrency?: number;
15
+ compress?: boolean | CompressOptions;
14
16
  } & SqlDumpTaskConfigType;
15
17
  export declare const mysqlDumpTaskDefinition: import("json-schema").JSONSchema7;
16
18
  export declare class MysqlDumpTask extends TaskAbstract<MysqlDumpTaskConfigType> {
17
- onBackup(data: BackupDataType): Promise<void>;
18
- onRestore(data: RestoreDataType): Promise<void>;
19
+ backup(data: TaskBackupData): Promise<{
20
+ snapshotPath: string;
21
+ }>;
22
+ prepareRestore(data: TaskPrepareRestoreData): Promise<{
23
+ snapshotPath: string;
24
+ }>;
25
+ restore(data: TaskRestoreData): Promise<void>;
19
26
  }
@@ -2,6 +2,7 @@
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 DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
5
6
  const async_1 = require("../utils/async");
6
7
  const cli_1 = require("../utils/cli");
7
8
  const config_1 = require("../utils/datatruck/config");
@@ -9,9 +10,10 @@ const fs_1 = require("../utils/fs");
9
10
  const math_1 = require("../utils/math");
10
11
  const mysql_1 = require("../utils/mysql");
11
12
  const string_1 = require("../utils/string");
13
+ const tar_1 = require("../utils/tar");
14
+ const temp_1 = require("../utils/temp");
12
15
  const SqlDumpTaskAbstract_1 = require("./SqlDumpTaskAbstract");
13
16
  const TaskAbstract_1 = require("./TaskAbstract");
14
- const assert_1 = require("assert");
15
17
  const promises_1 = require("fs/promises");
16
18
  const path_1 = require("path");
17
19
  exports.mysqlDumpTaskName = "mysql-dump";
@@ -19,6 +21,9 @@ exports.mysqlDumpTaskDefinition = (0, SqlDumpTaskAbstract_1.sqlDumpTaskDefinitio
19
21
  dataFormat: { enum: ["csv", "sql"] },
20
22
  concurrency: { type: "integer", minimum: 1 },
21
23
  csvSharedPath: { type: "string" },
24
+ compress: {
25
+ anyOf: [{ type: "boolean" }, (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.compressUtil)],
26
+ },
22
27
  });
23
28
  const suffix = {
24
29
  database: ".database.sql",
@@ -28,18 +33,37 @@ const suffix = {
28
33
  tableSchema: ".table-schema.sql",
29
34
  };
30
35
  class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
31
- async onBackup(data) {
36
+ async backup(data) {
37
+ const compressAndClean = this.config.compress
38
+ ? async (path) => {
39
+ data.onProgress({
40
+ relative: {
41
+ description: "Compressing",
42
+ payload: (0, path_1.basename)(path),
43
+ },
44
+ });
45
+ await (0, tar_1.createTar)({
46
+ include: [(0, path_1.relative)(snapshotPath, path)],
47
+ output: `${path}.tar.gz`,
48
+ path: (0, path_1.dirname)(path),
49
+ compress: this.config.compress,
50
+ verbose: data.options.verbose,
51
+ });
52
+ await (0, promises_1.rm)(path);
53
+ }
54
+ : undefined;
55
+ const snapshotPath = data.package.path ??
56
+ (await (0, temp_1.mkTmpDir)(exports.mysqlDumpTaskName, "task", "backup", "snapshot"));
57
+ await (0, fs_1.mkdirIfNotExists)(snapshotPath);
58
+ await (0, fs_1.ensureEmptyDir)(snapshotPath);
32
59
  const sql = await (0, mysql_1.createMysqlCli)({
33
60
  ...this.config,
34
61
  database: undefined,
35
62
  verbose: data.options.verbose,
36
63
  });
37
64
  const tableNames = await sql.fetchTableNames(this.config.database, this.config.includeTables, this.config.excludeTables);
38
- const outputPath = data.package.path;
39
- (0, assert_1.ok)(typeof outputPath === "string");
40
65
  const concurrency = this.config.concurrency ?? 4;
41
66
  const dataFormat = this.config.dataFormat ?? "sql";
42
- await (0, promises_1.mkdir)(outputPath, { recursive: true });
43
67
  const sharedDir = dataFormat === "csv"
44
68
  ? await sql.initSharedDir(this.config.csvSharedPath)
45
69
  : undefined;
@@ -47,7 +71,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
47
71
  await (0, async_1.runParallel)({
48
72
  items: tableNames,
49
73
  concurrency,
50
- onChange: async ({ processed: proccesed, buffer }) => await data.onProgress({
74
+ onChange: ({ processed: proccesed, buffer }) => data.onProgress({
51
75
  relative: {
52
76
  description: buffer.size > 1 ? `Exporting (${buffer.size})` : "Exporting",
53
77
  payload: [...buffer.keys()].join(", "),
@@ -81,15 +105,19 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
81
105
  files.every((file) => file === schemaFile || file === dataFile);
82
106
  if (!successCsvDump)
83
107
  throw new AppError_1.AppError(`Invalid csv dump files: ${files.join(", ")}`);
84
- await (0, fs_1.safeRename)((0, path_1.join)(tableSharedPath, schemaFile), (0, path_1.join)(outputPath, `${tableName}${suffix.tableSchema}`));
85
- await (0, fs_1.safeRename)((0, path_1.join)(tableSharedPath, dataFile), (0, path_1.join)(outputPath, `${tableName}${suffix.tableData}`));
108
+ const schemaPath = (0, path_1.join)(snapshotPath, `${tableName}${suffix.tableSchema}`);
109
+ await (0, fs_1.safeRename)((0, path_1.join)(tableSharedPath, schemaFile), schemaPath);
110
+ await compressAndClean?.(schemaPath);
111
+ const tablePath = (0, path_1.join)(snapshotPath, `${tableName}${suffix.tableData}`);
112
+ await (0, fs_1.safeRename)((0, path_1.join)(tableSharedPath, dataFile), tablePath);
113
+ await compressAndClean?.(tablePath);
86
114
  }
87
115
  finally {
88
116
  await (0, promises_1.rm)(tableSharedPath, { recursive: true });
89
117
  }
90
118
  }
91
119
  else {
92
- const outPath = (0, path_1.join)(outputPath, `${tableName}${suffix.table}`);
120
+ const outPath = (0, path_1.join)(snapshotPath, `${tableName}${suffix.table}`);
93
121
  await sql.dump({
94
122
  output: outPath,
95
123
  items: [tableName],
@@ -113,16 +141,19 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
113
141
  },
114
142
  }),
115
143
  });
144
+ await sql.assertDumpFile(outPath);
145
+ await compressAndClean?.(outPath);
116
146
  }
117
147
  },
118
148
  });
119
149
  }
120
150
  else {
121
- await data.onProgress({
151
+ data.onProgress({
122
152
  relative: { description: "Exporting" },
123
153
  });
154
+ const outPath = (0, path_1.join)(snapshotPath, `${this.config.database}${suffix.database}`);
124
155
  await sql.dump({
125
- output: (0, path_1.join)(outputPath, `${this.config.database}${suffix.database}`),
156
+ output: outPath,
126
157
  items: tableNames,
127
158
  database: this.config.database,
128
159
  onProgress: (progress) => data.onProgress({
@@ -133,26 +164,39 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
133
164
  },
134
165
  }),
135
166
  });
167
+ await sql.assertDumpFile(outPath);
168
+ await compressAndClean?.(outPath);
136
169
  }
137
170
  if (this.config.storedPrograms ?? true) {
138
- await data.onProgress({
171
+ data.onProgress({
139
172
  relative: { description: "Exporting stored programs" },
140
173
  });
174
+ const outPath = (0, path_1.join)(snapshotPath, `${this.config.database}${suffix.stored}`);
141
175
  await sql.dump({
142
176
  database: this.config.database,
143
- output: (0, path_1.join)(outputPath, `${this.config.database}${suffix.stored}`),
177
+ output: outPath,
144
178
  onlyStoredPrograms: true,
145
179
  });
180
+ await sql.assertDumpFile(outPath);
181
+ await compressAndClean?.(outPath);
146
182
  }
183
+ return {
184
+ snapshotPath,
185
+ };
147
186
  }
148
- async onRestore(data) {
187
+ async prepareRestore(data) {
188
+ return {
189
+ snapshotPath: data.package.restorePath ??
190
+ (await (0, temp_1.mkTmpDir)(exports.mysqlDumpTaskName, "task", "restore", "snapshot")),
191
+ };
192
+ }
193
+ async restore(data) {
149
194
  const sql = await (0, mysql_1.createMysqlCli)({
150
195
  ...this.config,
151
196
  database: undefined,
152
197
  verbose: data.options.verbose,
153
198
  });
154
- const restorePath = data.package.restorePath;
155
- (0, assert_1.ok)(typeof restorePath === "string");
199
+ const snapshotPath = data.snapshotPath;
156
200
  const params = {
157
201
  packageName: data.package.name,
158
202
  snapshotId: data.options.snapshotId,
@@ -168,8 +212,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
168
212
  ...params,
169
213
  database: database.name,
170
214
  });
171
- const suffixes = Object.values(suffix);
172
- const files = (await (0, fs_1.readDir)(restorePath)).filter((f) => (0, string_1.endsWith)(f, suffixes));
215
+ const [files, compressed] = (0, fs_1.groupFiles)(await (0, fs_1.readDir)(snapshotPath), Object.values(suffix));
173
216
  // Database check
174
217
  if (files.some((f) => f.endsWith(suffix.database)) &&
175
218
  !(await sql.isDatabaseEmpty(database.name)))
@@ -191,7 +234,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
191
234
  : undefined;
192
235
  await sql.createDatabase(database);
193
236
  if (data.options.verbose)
194
- (0, cli_1.logExec)("readdir", [restorePath]);
237
+ (0, cli_1.logExec)("readdir", [snapshotPath]);
195
238
  const concurrency = this.config.concurrency ?? 1;
196
239
  let processed = 0;
197
240
  await (0, async_1.runParallel)({
@@ -200,7 +243,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
200
243
  onFinished: () => {
201
244
  processed++;
202
245
  },
203
- onChange: async ({ buffer }) => await data.onProgress({
246
+ onChange: ({ buffer }) => data.onProgress({
204
247
  relative: {
205
248
  description: buffer.size > 1 ? `Importing (${buffer.size})` : "Importing",
206
249
  payload: [...buffer.keys()].join(", "),
@@ -212,11 +255,29 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
212
255
  },
213
256
  }),
214
257
  onItem: async ({ item: file, controller }) => {
215
- await sql.importFile({
216
- path: (0, path_1.join)(restorePath, file),
217
- database: database.name,
218
- onSpawn: (p) => (controller.stop = () => p.kill()),
219
- });
258
+ let path = (0, path_1.join)(snapshotPath, file);
259
+ const tempDir = compressed[file]
260
+ ? await (0, temp_1.useTempDir)(exports.mysqlDumpTaskName, "task", "restore", "decompress")
261
+ : undefined;
262
+ try {
263
+ if (tempDir) {
264
+ await (0, tar_1.extractTar)({
265
+ input: (0, path_1.join)(snapshotPath, compressed[file]),
266
+ output: tempDir.path,
267
+ decompress: true,
268
+ verbose: data.options.verbose,
269
+ });
270
+ path = await (0, fs_1.ensureSingleFile)(tempDir.path);
271
+ }
272
+ await sql.importFile({
273
+ path,
274
+ database: database.name,
275
+ onSpawn: (p) => (controller.stop = () => p.kill()),
276
+ });
277
+ }
278
+ finally {
279
+ await tempDir?.[Symbol.asyncDispose]();
280
+ }
220
281
  },
221
282
  });
222
283
  await (0, async_1.runParallel)({
@@ -225,7 +286,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
225
286
  onFinished: () => {
226
287
  processed++;
227
288
  },
228
- onChange: async ({ buffer }) => await data.onProgress({
289
+ onChange: ({ buffer }) => data.onProgress({
229
290
  relative: {
230
291
  description: buffer.size > 1 ? `Importing (${buffer.size})` : "Importing",
231
292
  payload: [...buffer.keys()].join(", "),
@@ -237,20 +298,35 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
237
298
  },
238
299
  }),
239
300
  onItem: async ({ item: file, controller }) => {
240
- const filePath = (0, path_1.join)(restorePath, file);
301
+ const id = data.snapshot.id.slice(0, 8);
241
302
  const tableName = file.slice(0, suffix.tableData.length * -1);
242
- const sharedFilePath = (0, path_1.join)(sharedDir, `tmp-dtt-restore-${data.snapshot.id.slice(0, 8)}-${tableName}.data.csv`);
303
+ const sharedName = `tmp-dtt-restore-${id}-${tableName}.data.csv`;
304
+ const temp = (0, temp_1.useTempFile)((0, path_1.join)(sharedDir, sharedName));
243
305
  try {
244
- await (0, fs_1.safeRename)(filePath, sharedFilePath);
306
+ let csvFile = temp.path;
307
+ if (compressed[file]) {
308
+ await (0, fs_1.mkdirIfNotExists)(temp.path);
309
+ await (0, tar_1.extractTar)({
310
+ input: (0, path_1.join)(snapshotPath, compressed[file]),
311
+ output: temp.path,
312
+ decompress: true,
313
+ verbose: data.options.verbose,
314
+ });
315
+ csvFile = await (0, fs_1.ensureSingleFile)(temp.path);
316
+ }
317
+ else {
318
+ const sourceFile = (0, path_1.join)(snapshotPath, file);
319
+ await (0, fs_1.safeRename)(sourceFile, temp.path);
320
+ }
245
321
  await sql.importCsvFile({
246
- path: sharedFilePath,
322
+ path: csvFile,
247
323
  database: database.name,
248
324
  table: tableName,
249
325
  onSpawn: (p) => (controller.stop = () => p.kill()),
250
326
  });
251
327
  }
252
328
  finally {
253
- await (0, promises_1.rm)(sharedFilePath);
329
+ await temp[Symbol.asyncDispose]();
254
330
  }
255
331
  },
256
332
  });
@@ -1,42 +1,47 @@
1
+ import { PackageConfigType } from "../Config/PackageConfig";
2
+ import { PreSnapshot } from "../Repository/RepositoryAbstract";
1
3
  import { Step } from "../utils/steps";
2
- import { BackupDataType, BeforeBackupDataType, BeforeRestoreDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
4
+ import { TaskBackupData, TaskPrepareRestoreData, TaskRestoreData, TaskAbstract } from "./TaskAbstract";
3
5
  import { JSONSchema7 } from "json-schema";
6
+ type NodeVars = {
7
+ dtt: {
8
+ snapshot: PreSnapshot;
9
+ package: PackageConfigType;
10
+ snapshotPath: string;
11
+ };
12
+ };
4
13
  export type ScriptTaskConfigType = {
5
14
  env?: Record<string, string | undefined>;
6
15
  backupSteps: Step[];
7
16
  restoreSteps: Step[];
8
17
  };
18
+ export declare function scriptTaskCode<V extends Record<string, any>>(cb: (vars: NodeVars & V) => void): string;
9
19
  export declare enum ScriptTaskDefinitionEnum {
10
20
  step = "step",
11
21
  processStepConfig = "processStepConfig",
12
- nodeStepConfig = "nodeStepConfig"
22
+ nodeStepConfig = "nodeStepConfig",
23
+ telegramMessageStepConfig = "telegramMessageStepConfig"
13
24
  }
14
25
  export declare const scriptTaskName = "script";
15
26
  export declare const scriptTaskDefinition: JSONSchema7;
16
27
  export declare class ScriptTask extends TaskAbstract<ScriptTaskConfigType> {
17
28
  protected verbose?: boolean;
18
- onBeforeBackup(data: BeforeBackupDataType): Promise<{
19
- targetPath: string;
20
- }>;
21
- protected getVars(data: BackupDataType | RestoreDataType): {
29
+ protected getVars(data: TaskBackupData | TaskRestoreData): {
22
30
  process: {
23
31
  DTT_SNAPSHOT_ID: string;
24
32
  DTT_SNAPSHOT_DATE: string;
25
33
  DTT_PACKAGE_NAME: string;
26
34
  DTT_PACKAGE_PATH: string | undefined;
27
- DTT_TARGET_PATH: string | undefined;
28
- };
29
- node: {
30
- dtt: {
31
- snapshot: import("../Repository/RepositoryAbstract").SnapshotType;
32
- package: import("../Config/PackageConfig").PackageConfigType;
33
- targetPath: string | undefined;
34
- };
35
+ DTT_SNAPSHOT_PATH: string | undefined;
35
36
  };
37
+ node: NodeVars;
36
38
  };
37
- onBackup(data: BackupDataType): Promise<void>;
38
- onBeforeRestore(data: BeforeRestoreDataType): Promise<{
39
- targetPath: string;
39
+ backup(data: TaskBackupData): Promise<{
40
+ snapshotPath: string;
41
+ }>;
42
+ prepareRestore(data: TaskPrepareRestoreData): Promise<{
43
+ snapshotPath: string;
40
44
  }>;
41
- onRestore(data: RestoreDataType): Promise<void>;
45
+ restore(data: TaskRestoreData): Promise<void>;
42
46
  }
47
+ export {};