@datatruck/cli 0.27.0 → 0.29.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 (151) hide show
  1. package/Action/BackupAction.d.ts +75 -34
  2. package/Action/BackupAction.js +302 -246
  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 +51 -0
  8. package/Action/CopyAction.js +165 -0
  9. package/Action/InitAction.d.ts +3 -3
  10. package/Action/InitAction.js +9 -9
  11. package/Action/PruneAction.d.ts +10 -16
  12. package/Action/PruneAction.js +37 -34
  13. package/Action/RestoreAction.d.ts +49 -24
  14. package/Action/RestoreAction.js +164 -195
  15. package/Action/SnapshotsAction.d.ts +8 -8
  16. package/Action/SnapshotsAction.js +9 -9
  17. package/CHANGELOG.md +513 -0
  18. package/Command/BackupCommand.d.ts +7 -4
  19. package/Command/BackupCommand.js +14 -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 +16 -0
  27. package/Command/CopyCommand.js +66 -0
  28. package/Command/InitCommand.d.ts +4 -4
  29. package/Command/InitCommand.js +13 -17
  30. package/Command/PruneCommand.d.ts +4 -10
  31. package/Command/PruneCommand.js +13 -12
  32. package/Command/RestoreCommand.d.ts +1 -1
  33. package/Command/RestoreCommand.js +13 -21
  34. package/Command/SnapshotsCommand.d.ts +4 -4
  35. package/Command/SnapshotsCommand.js +16 -15
  36. package/Command/StartServerCommand.d.ts +3 -3
  37. package/Config/Config.d.ts +11 -0
  38. package/Config/Config.js +18 -0
  39. package/Config/PrunePolicyConfig.d.ts +2 -2
  40. package/Factory/CommandFactory.d.ts +27 -34
  41. package/Factory/CommandFactory.js +27 -54
  42. package/Factory/RepositoryFactory.d.ts +1 -1
  43. package/Factory/RepositoryFactory.js +3 -3
  44. package/Factory/TaskFactory.d.ts +1 -1
  45. package/Factory/TaskFactory.js +3 -3
  46. package/Repository/DatatruckRepository.d.ts +10 -8
  47. package/Repository/DatatruckRepository.js +47 -25
  48. package/Repository/GitRepository.d.ts +9 -8
  49. package/Repository/GitRepository.js +22 -25
  50. package/Repository/RepositoryAbstract.d.ts +39 -37
  51. package/Repository/RepositoryAbstract.js +4 -5
  52. package/Repository/ResticRepository.d.ts +9 -8
  53. package/Repository/ResticRepository.js +30 -28
  54. package/Task/GitTask.d.ts +6 -7
  55. package/Task/GitTask.js +24 -30
  56. package/Task/MariadbTask.d.ts +4 -5
  57. package/Task/MariadbTask.js +26 -32
  58. package/Task/MssqlTask.d.ts +5 -3
  59. package/Task/MssqlTask.js +11 -12
  60. package/Task/MysqlDumpTask.d.ts +10 -3
  61. package/Task/MysqlDumpTask.js +102 -32
  62. package/Task/ScriptTask.d.ts +23 -18
  63. package/Task/ScriptTask.js +34 -24
  64. package/Task/SqlDumpTaskAbstract.d.ts +8 -3
  65. package/Task/SqlDumpTaskAbstract.js +32 -20
  66. package/Task/TaskAbstract.d.ts +24 -25
  67. package/Task/TaskAbstract.js +6 -10
  68. package/cli.js +13 -5
  69. package/config.schema.json +89 -1
  70. package/package.json +4 -5
  71. package/utils/DataFormat.d.ts +23 -12
  72. package/utils/DataFormat.js +36 -14
  73. package/utils/cli.d.ts +3 -9
  74. package/utils/cli.js +19 -55
  75. package/utils/crypto.d.ts +1 -0
  76. package/utils/crypto.js +15 -0
  77. package/utils/datatruck/client.d.ts +2 -0
  78. package/utils/datatruck/client.js +3 -0
  79. package/utils/datatruck/config.d.ts +2 -0
  80. package/utils/datatruck/config.js +18 -3
  81. package/utils/datatruck/paths.d.ts +5 -9
  82. package/utils/datatruck/paths.js +2 -2
  83. package/utils/datatruck/snapshot.d.ts +5 -2
  84. package/utils/datatruck/snapshot.js +12 -22
  85. package/utils/date.d.ts +21 -4
  86. package/utils/date.js +46 -24
  87. package/utils/fs.d.ts +16 -11
  88. package/utils/fs.js +81 -48
  89. package/utils/list.d.ts +64 -0
  90. package/utils/list.js +145 -0
  91. package/utils/mysql.d.ts +2 -0
  92. package/utils/mysql.js +21 -2
  93. package/utils/process.d.ts +1 -0
  94. package/utils/process.js +24 -31
  95. package/utils/progress.d.ts +33 -0
  96. package/utils/progress.js +113 -0
  97. package/utils/steps.d.ts +11 -0
  98. package/utils/steps.js +22 -10
  99. package/utils/stream.d.ts +7 -0
  100. package/utils/stream.js +10 -0
  101. package/utils/string.d.ts +0 -1
  102. package/utils/string.js +1 -13
  103. package/utils/tar.d.ts +10 -3
  104. package/utils/tar.js +73 -45
  105. package/utils/temp.d.ts +26 -0
  106. package/utils/temp.js +133 -0
  107. package/utils/virtual-fs.d.ts +6 -2
  108. package/utils/virtual-fs.js +6 -0
  109. package/Action/BackupSessionsAction.d.ts +0 -13
  110. package/Action/BackupSessionsAction.js +0 -18
  111. package/Action/RestoreSessionsAction.d.ts +0 -13
  112. package/Action/RestoreSessionsAction.js +0 -18
  113. package/Command/BackupSessionsCommand.d.ts +0 -12
  114. package/Command/BackupSessionsCommand.js +0 -92
  115. package/Command/RestoreSessionsCommand.d.ts +0 -12
  116. package/Command/RestoreSessionsCommand.js +0 -91
  117. package/Decorator/EntityDecorator.d.ts +0 -11
  118. package/Decorator/EntityDecorator.js +0 -17
  119. package/Entity/BackupSessionEntity.d.ts +0 -6
  120. package/Entity/BackupSessionEntity.js +0 -25
  121. package/Entity/BackupSessionRepositoryEntity.d.ts +0 -6
  122. package/Entity/BackupSessionRepositoryEntity.js +0 -25
  123. package/Entity/BackupSessionTaskEntity.d.ts +0 -5
  124. package/Entity/BackupSessionTaskEntity.js +0 -24
  125. package/Entity/CrudEntityAbstract.d.ts +0 -5
  126. package/Entity/CrudEntityAbstract.js +0 -9
  127. package/Entity/RestoreSessionEntity.d.ts +0 -5
  128. package/Entity/RestoreSessionEntity.js +0 -24
  129. package/Entity/RestoreSessionRepositoryEntity.d.ts +0 -6
  130. package/Entity/RestoreSessionRepositoryEntity.js +0 -25
  131. package/Entity/RestoreSessionTaskEntity.d.ts +0 -5
  132. package/Entity/RestoreSessionTaskEntity.js +0 -24
  133. package/Entity/StateEntityAbstract.d.ts +0 -9
  134. package/Entity/StateEntityAbstract.js +0 -12
  135. package/Factory/EntityFactory.d.ts +0 -6
  136. package/Factory/EntityFactory.js +0 -40
  137. package/SessionDriver/ConsoleSessionDriver.d.ts +0 -42
  138. package/SessionDriver/ConsoleSessionDriver.js +0 -208
  139. package/SessionDriver/SessionDriverAbstract.d.ts +0 -77
  140. package/SessionDriver/SessionDriverAbstract.js +0 -28
  141. package/SessionDriver/SqliteSessionDriver.d.ts +0 -20
  142. package/SessionDriver/SqliteSessionDriver.js +0 -173
  143. package/SessionManager/BackupSessionManager.d.ts +0 -45
  144. package/SessionManager/BackupSessionManager.js +0 -218
  145. package/SessionManager/RestoreSessionManager.d.ts +0 -47
  146. package/SessionManager/RestoreSessionManager.js +0 -218
  147. package/SessionManager/SessionManagerAbstract.d.ts +0 -18
  148. package/SessionManager/SessionManagerAbstract.js +0 -36
  149. package/migrations/001-initial.sql +0 -98
  150. package/utils/entity.d.ts +0 -4
  151. package/utils/entity.js +0 -10
@@ -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 MariadbTaskConfigType = {
4
4
  command?: string;
@@ -28,9 +28,8 @@ export declare const mariadbTaskDefinition: JSONSchema7;
28
28
  export declare class MariadbTask extends TaskAbstract<MariadbTaskConfigType> {
29
29
  protected verbose?: boolean;
30
30
  private get command();
31
- onBeforeBackup(): Promise<{
32
- targetPath: string;
31
+ backup(data: TaskBackupData): Promise<{
32
+ snapshotPath: string;
33
33
  }>;
34
- onBackup(data: BackupDataType): Promise<void>;
35
- onRestore(data: RestoreDataType): Promise<void>;
34
+ restore(data: TaskRestoreData): Promise<void>;
36
35
  }
@@ -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,31 @@ 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
+ await (0, tar_1.createTar)({
40
+ include: [(0, path_1.relative)(snapshotPath, path)],
41
+ output: `${path}.tar.gz`,
42
+ path: (0, path_1.dirname)(path),
43
+ compress: this.config.compress,
44
+ verbose: data.options.verbose,
45
+ });
46
+ await (0, promises_1.rm)(path);
47
+ }
48
+ : undefined;
49
+ const snapshotPath = data.package.path ??
50
+ (await (0, temp_1.mkTmpDir)(exports.mysqlDumpTaskName, "task", "backup", "snapshot"));
51
+ await (0, fs_1.mkdirIfNotExists)(snapshotPath);
52
+ await (0, fs_1.ensureEmptyDir)(snapshotPath);
32
53
  const sql = await (0, mysql_1.createMysqlCli)({
33
54
  ...this.config,
34
55
  database: undefined,
35
56
  verbose: data.options.verbose,
36
57
  });
37
58
  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
59
  const concurrency = this.config.concurrency ?? 4;
41
60
  const dataFormat = this.config.dataFormat ?? "sql";
42
- await (0, promises_1.mkdir)(outputPath, { recursive: true });
43
61
  const sharedDir = dataFormat === "csv"
44
62
  ? await sql.initSharedDir(this.config.csvSharedPath)
45
63
  : undefined;
@@ -47,7 +65,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
47
65
  await (0, async_1.runParallel)({
48
66
  items: tableNames,
49
67
  concurrency,
50
- onChange: async ({ processed: proccesed, buffer }) => await data.onProgress({
68
+ onChange: ({ processed: proccesed, buffer }) => data.onProgress({
51
69
  relative: {
52
70
  description: buffer.size > 1 ? `Exporting (${buffer.size})` : "Exporting",
53
71
  payload: [...buffer.keys()].join(", "),
@@ -81,15 +99,19 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
81
99
  files.every((file) => file === schemaFile || file === dataFile);
82
100
  if (!successCsvDump)
83
101
  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}`));
102
+ const schemaPath = (0, path_1.join)(snapshotPath, `${tableName}${suffix.tableSchema}`);
103
+ await (0, fs_1.safeRename)((0, path_1.join)(tableSharedPath, schemaFile), schemaPath);
104
+ await compressAndClean?.(schemaPath);
105
+ const tablePath = (0, path_1.join)(snapshotPath, `${tableName}${suffix.tableData}`);
106
+ await (0, fs_1.safeRename)((0, path_1.join)(tableSharedPath, dataFile), tablePath);
107
+ await compressAndClean?.(tablePath);
86
108
  }
87
109
  finally {
88
110
  await (0, promises_1.rm)(tableSharedPath, { recursive: true });
89
111
  }
90
112
  }
91
113
  else {
92
- const outPath = (0, path_1.join)(outputPath, `${tableName}${suffix.table}`);
114
+ const outPath = (0, path_1.join)(snapshotPath, `${tableName}${suffix.table}`);
93
115
  await sql.dump({
94
116
  output: outPath,
95
117
  items: [tableName],
@@ -113,16 +135,19 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
113
135
  },
114
136
  }),
115
137
  });
138
+ await sql.assertDumpFile(outPath);
139
+ await compressAndClean?.(outPath);
116
140
  }
117
141
  },
118
142
  });
119
143
  }
120
144
  else {
121
- await data.onProgress({
145
+ data.onProgress({
122
146
  relative: { description: "Exporting" },
123
147
  });
148
+ const outPath = (0, path_1.join)(snapshotPath, `${this.config.database}${suffix.database}`);
124
149
  await sql.dump({
125
- output: (0, path_1.join)(outputPath, `${this.config.database}${suffix.database}`),
150
+ output: outPath,
126
151
  items: tableNames,
127
152
  database: this.config.database,
128
153
  onProgress: (progress) => data.onProgress({
@@ -133,26 +158,39 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
133
158
  },
134
159
  }),
135
160
  });
161
+ await sql.assertDumpFile(outPath);
162
+ await compressAndClean?.(outPath);
136
163
  }
137
164
  if (this.config.storedPrograms ?? true) {
138
- await data.onProgress({
165
+ data.onProgress({
139
166
  relative: { description: "Exporting stored programs" },
140
167
  });
168
+ const outPath = (0, path_1.join)(snapshotPath, `${this.config.database}${suffix.stored}`);
141
169
  await sql.dump({
142
170
  database: this.config.database,
143
- output: (0, path_1.join)(outputPath, `${this.config.database}${suffix.stored}`),
171
+ output: outPath,
144
172
  onlyStoredPrograms: true,
145
173
  });
174
+ await sql.assertDumpFile(outPath);
175
+ await compressAndClean?.(outPath);
146
176
  }
177
+ return {
178
+ snapshotPath,
179
+ };
180
+ }
181
+ async prepareRestore(data) {
182
+ return {
183
+ snapshotPath: data.package.restorePath ??
184
+ (await (0, temp_1.mkTmpDir)(exports.mysqlDumpTaskName, "task", "restore", "snapshot")),
185
+ };
147
186
  }
148
- async onRestore(data) {
187
+ async restore(data) {
149
188
  const sql = await (0, mysql_1.createMysqlCli)({
150
189
  ...this.config,
151
190
  database: undefined,
152
191
  verbose: data.options.verbose,
153
192
  });
154
- const restorePath = data.package.restorePath;
155
- (0, assert_1.ok)(typeof restorePath === "string");
193
+ const snapshotPath = data.snapshotPath;
156
194
  const params = {
157
195
  packageName: data.package.name,
158
196
  snapshotId: data.options.snapshotId,
@@ -163,13 +201,12 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
163
201
  const database = {
164
202
  name: (0, config_1.resolveDatabaseName)(this.config.database, params),
165
203
  };
166
- if (this.config.targetDatabase && data.options.restorePath)
204
+ if (this.config.targetDatabase && !data.options.initial)
167
205
  database.name = (0, config_1.resolveDatabaseName)(this.config.targetDatabase.name, {
168
206
  ...params,
169
207
  database: database.name,
170
208
  });
171
- const suffixes = Object.values(suffix);
172
- const files = (await (0, fs_1.readDir)(restorePath)).filter((f) => (0, string_1.endsWith)(f, suffixes));
209
+ const [files, compressed] = (0, fs_1.groupFiles)(await (0, fs_1.readDir)(snapshotPath), Object.values(suffix));
173
210
  // Database check
174
211
  if (files.some((f) => f.endsWith(suffix.database)) &&
175
212
  !(await sql.isDatabaseEmpty(database.name)))
@@ -191,7 +228,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
191
228
  : undefined;
192
229
  await sql.createDatabase(database);
193
230
  if (data.options.verbose)
194
- (0, cli_1.logExec)("readdir", [restorePath]);
231
+ (0, cli_1.logExec)("readdir", [snapshotPath]);
195
232
  const concurrency = this.config.concurrency ?? 1;
196
233
  let processed = 0;
197
234
  await (0, async_1.runParallel)({
@@ -200,7 +237,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
200
237
  onFinished: () => {
201
238
  processed++;
202
239
  },
203
- onChange: async ({ buffer }) => await data.onProgress({
240
+ onChange: ({ buffer }) => data.onProgress({
204
241
  relative: {
205
242
  description: buffer.size > 1 ? `Importing (${buffer.size})` : "Importing",
206
243
  payload: [...buffer.keys()].join(", "),
@@ -212,11 +249,29 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
212
249
  },
213
250
  }),
214
251
  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
- });
252
+ let path = (0, path_1.join)(snapshotPath, file);
253
+ const tempDir = compressed[file]
254
+ ? await (0, temp_1.useTempDir)(exports.mysqlDumpTaskName, "task", "restore", "decompress")
255
+ : undefined;
256
+ try {
257
+ if (tempDir) {
258
+ await (0, tar_1.extractTar)({
259
+ input: (0, path_1.join)(snapshotPath, compressed[file]),
260
+ output: tempDir.path,
261
+ decompress: true,
262
+ verbose: data.options.verbose,
263
+ });
264
+ path = await (0, fs_1.ensureSingleFile)(tempDir.path);
265
+ }
266
+ await sql.importFile({
267
+ path,
268
+ database: database.name,
269
+ onSpawn: (p) => (controller.stop = () => p.kill()),
270
+ });
271
+ }
272
+ finally {
273
+ await tempDir?.[Symbol.asyncDispose]();
274
+ }
220
275
  },
221
276
  });
222
277
  await (0, async_1.runParallel)({
@@ -225,7 +280,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
225
280
  onFinished: () => {
226
281
  processed++;
227
282
  },
228
- onChange: async ({ buffer }) => await data.onProgress({
283
+ onChange: ({ buffer }) => data.onProgress({
229
284
  relative: {
230
285
  description: buffer.size > 1 ? `Importing (${buffer.size})` : "Importing",
231
286
  payload: [...buffer.keys()].join(", "),
@@ -237,20 +292,35 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
237
292
  },
238
293
  }),
239
294
  onItem: async ({ item: file, controller }) => {
240
- const filePath = (0, path_1.join)(restorePath, file);
295
+ const id = data.snapshot.id.slice(0, 8);
241
296
  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`);
297
+ const sharedName = `tmp-dtt-restore-${id}-${tableName}.data.csv`;
298
+ const temp = (0, temp_1.useTempFile)((0, path_1.join)(sharedDir, sharedName));
243
299
  try {
244
- await (0, fs_1.safeRename)(filePath, sharedFilePath);
300
+ let csvFile = temp.path;
301
+ if (compressed[file]) {
302
+ await (0, fs_1.mkdirIfNotExists)(temp.path);
303
+ await (0, tar_1.extractTar)({
304
+ input: (0, path_1.join)(snapshotPath, compressed[file]),
305
+ output: temp.path,
306
+ decompress: true,
307
+ verbose: data.options.verbose,
308
+ });
309
+ csvFile = await (0, fs_1.ensureSingleFile)(temp.path);
310
+ }
311
+ else {
312
+ const sourceFile = (0, path_1.join)(snapshotPath, file);
313
+ await (0, fs_1.safeRename)(sourceFile, temp.path);
314
+ }
245
315
  await sql.importCsvFile({
246
- path: sharedFilePath,
316
+ path: csvFile,
247
317
  database: database.name,
248
318
  table: tableName,
249
319
  onSpawn: (p) => (controller.stop = () => p.kill()),
250
320
  });
251
321
  }
252
322
  finally {
253
- await (0, promises_1.rm)(sharedFilePath);
323
+ await temp[Symbol.asyncDispose]();
254
324
  }
255
325
  },
256
326
  });
@@ -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 {};