@datatruck/cli 0.14.0 → 0.16.1

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 (46) hide show
  1. package/Action/BackupAction.d.ts +10 -3
  2. package/Action/BackupAction.js +41 -49
  3. package/Action/RestoreAction.d.ts +2 -2
  4. package/Action/RestoreAction.js +8 -16
  5. package/Command/BackupCommand.js +2 -1
  6. package/Command/BackupSessionsCommand.js +1 -0
  7. package/Command/RestoreCommand.js +1 -1
  8. package/Command/RestoreSessionsCommand.js +1 -0
  9. package/Entity/StateEntityAbstract.d.ts +2 -5
  10. package/Error/AppError.d.ts +1 -0
  11. package/Error/AppError.js +4 -0
  12. package/Repository/DatatruckRepository.d.ts +1 -0
  13. package/Repository/DatatruckRepository.js +162 -158
  14. package/Repository/RepositoryAbstract.d.ts +4 -10
  15. package/Repository/ResticRepository.js +34 -17
  16. package/SessionDriver/ConsoleSessionDriver.d.ts +2 -7
  17. package/SessionDriver/ConsoleSessionDriver.js +51 -24
  18. package/SessionDriver/SqliteSessionDriver.js +5 -0
  19. package/SessionManager/BackupSessionManager.d.ts +12 -11
  20. package/SessionManager/BackupSessionManager.js +20 -5
  21. package/SessionManager/RestoreSessionManager.d.ts +14 -11
  22. package/SessionManager/RestoreSessionManager.js +20 -5
  23. package/SessionManager/SessionManagerAbstract.d.ts +18 -0
  24. package/SessionManager/SessionManagerAbstract.js +32 -0
  25. package/Task/GitTask.js +22 -14
  26. package/Task/MariadbTask.js +9 -4
  27. package/Task/MysqlDumpTask.d.ts +3 -1
  28. package/Task/MysqlDumpTask.js +5 -2
  29. package/Task/PostgresqlDumpTask.d.ts +3 -1
  30. package/Task/PostgresqlDumpTask.js +2 -2
  31. package/Task/SqlDumpTaskAbstract.d.ts +3 -1
  32. package/Task/SqlDumpTaskAbstract.js +55 -13
  33. package/Task/TaskAbstract.d.ts +3 -9
  34. package/cli.js +1 -1
  35. package/migrations/001-initial.sql +6 -30
  36. package/package.json +1 -1
  37. package/util/cli-util.d.ts +1 -1
  38. package/util/cli-util.js +17 -2
  39. package/util/fs-util.d.ts +10 -1
  40. package/util/fs-util.js +10 -1
  41. package/util/process-util.d.ts +3 -0
  42. package/util/process-util.js +11 -0
  43. package/util/progress.d.ts +12 -0
  44. package/util/progress.js +2 -0
  45. package/util/zip-util.d.ts +23 -5
  46. package/util/zip-util.js +82 -25
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.ConsoleSessionDriver = void 0;
4
7
  const AppError_1 = require("../Error/AppError");
@@ -6,6 +9,7 @@ const cli_util_1 = require("../util/cli-util");
6
9
  const date_util_1 = require("../util/date-util");
7
10
  const SessionDriverAbstract_1 = require("./SessionDriverAbstract");
8
11
  const chalk_1 = require("chalk");
12
+ const pretty_bytes_1 = __importDefault(require("pretty-bytes"));
9
13
  const sep = (0, chalk_1.grey)(`|`);
10
14
  const renderBadge = (badge) => `${badge.color(badge.name)}${(0, chalk_1.grey)(`:`)} ${(0, chalk_1.white)(badge.value)}`;
11
15
  const renderBadges = (badges) => badges.map(renderBadge).join(` ${sep} `);
@@ -72,34 +76,59 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
72
76
  ]);
73
77
  const padding = " ".repeat(message.level ?? 0);
74
78
  const sessionId = message.sessionId.toString().padStart(2, "0");
75
- const parts = [
79
+ let parts = [
76
80
  `${padding}${message.textPrefix} [${(0, chalk_1.grey)(sessionId)}] ${message.text}`,
77
81
  badges,
78
82
  ];
79
- if (typeof message.progressPercent === "number") {
80
- parts.push((0, chalk_1.cyan)((0, cli_util_1.renderProgressBar)(message.progressPercent ?? 0, 10)), `${message.progressPercent?.toFixed(2)}%`);
83
+ const progress = message.progress;
84
+ const absolute = progress?.absolute || {};
85
+ const relative = progress?.relative || {};
86
+ if (typeof absolute.percent === "number" ||
87
+ typeof relative.percent === "number") {
88
+ parts.push((0, cli_util_1.renderProgressBar)(absolute.percent ?? 0, 10, relative.percent ?? undefined));
81
89
  }
82
- if (typeof message.progressCurrent === "number" ||
83
- typeof message.progressTotal === "number") {
84
- parts.push(`${message.progressCurrent ?? "?"}/${message.progressTotal ?? "?"}`);
85
- }
86
- if (typeof message.progressStep === "string")
87
- parts.push(message.progressStep);
88
- if (typeof message.progressStepPercent === "number") {
89
- parts.push((0, chalk_1.cyan)((0, cli_util_1.renderProgressBar)(message.progressStepPercent ?? 0, 10)));
90
+ const createProgressParts = (p) => {
91
+ const result = [];
92
+ if (typeof p.percent === "number")
93
+ result.push(`${p.percent.toFixed(2)}%`);
94
+ if (typeof p.current === "number" || typeof p.total === "number") {
95
+ const format = (value) => p.format === "size" ? (0, pretty_bytes_1.default)(value) : value;
96
+ if (typeof p.current === "number" && typeof p.total === "number") {
97
+ result.push(`${format(p.current)}/${format(p.total)}`);
98
+ }
99
+ else if (typeof p.current === "number") {
100
+ result.push(`${format(p.current)}`);
101
+ }
102
+ else if (typeof p.total === "number") {
103
+ result.push(`?/${format(p.total)}`);
104
+ }
105
+ }
106
+ if (p.description && p.payload) {
107
+ result.push(`${p.description}: ${p.payload}`);
108
+ }
109
+ else if (p.description) {
110
+ result.push(p.description);
111
+ }
112
+ else if (p.payload) {
113
+ result.push(p.payload);
114
+ }
115
+ return result;
116
+ };
117
+ if (progress?.absolute)
118
+ parts.push(...createProgressParts(progress?.absolute));
119
+ if (progress?.relative) {
120
+ const relativeParts = createProgressParts(progress?.relative);
121
+ if (relativeParts.length) {
122
+ return (parts.join(` ${sep} `) +
123
+ ` ${(0, chalk_1.cyan)("▷")} ` +
124
+ relativeParts.join(` ${sep} `));
125
+ }
90
126
  }
91
127
  return parts.join(` ${sep} `);
92
128
  }
93
129
  async onWrite(data) {
94
130
  if (data.action === SessionDriverAbstract_1.ActionEnum.Init)
95
131
  return;
96
- if (data.action === SessionDriverAbstract_1.ActionEnum.Progress && this.options.progressInterval) {
97
- const skip = this.lastProgressDate &&
98
- Date.now() - this.lastProgressDate < this.options.progressInterval;
99
- if (skip)
100
- return;
101
- this.lastProgressDate = Date.now();
102
- }
103
132
  const message = {
104
133
  sessionId: "sessionId" in data.data ? data.data.sessionId : data.data.id,
105
134
  badges: [],
@@ -124,7 +153,9 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
124
153
  if (data.data.error)
125
154
  message.errorBadge = {
126
155
  name: "error",
127
- value: this.tty ? data.data.error.split("\n")[0] : data.data.error,
156
+ value: this.tty && data.data.error.startsWith(`${AppError_1.AppError.name} :`)
157
+ ? data.data.error.split("\n")[0]
158
+ : data.data.error,
128
159
  color: chalk_1.red,
129
160
  };
130
161
  }
@@ -132,11 +163,7 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
132
163
  message.textPrefix = "{spinner}";
133
164
  }
134
165
  if (hasProgress) {
135
- message.progressPercent = data.data.progressPercent;
136
- message.progressCurrent = data.data.progressCurrent;
137
- message.progressTotal = data.data.progressTotal;
138
- message.progressStep = data.data.progressStep;
139
- message.progressStepPercent = data.data.progressStepPercent;
166
+ message.progress = data.data.progress;
140
167
  }
141
168
  if (data.entity === SessionDriverAbstract_1.EntityEnum.BackupSession ||
142
169
  data.entity === SessionDriverAbstract_1.EntityEnum.RestoreSession) {
@@ -134,6 +134,11 @@ class SqliteSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
134
134
  let stm;
135
135
  let object = data.data;
136
136
  const id = object.id;
137
+ object = {
138
+ ...object,
139
+ // @ts-expect-error
140
+ progress: data.data.progress ? JSON.stringify(data.data.progress) : null,
141
+ };
137
142
  if (data.action === SessionDriverAbstract_1.ActionEnum.Init) {
138
143
  // @ts-expect-error
139
144
  object = { ...object, id: null };
@@ -2,19 +2,14 @@ import { BackupSessionsActionOptionsType } from "../Action/BackupSessionsAction"
2
2
  import { BackupSessionEntity } from "../Entity/BackupSessionEntity";
3
3
  import { BackupSessionRepositoryEntity } from "../Entity/BackupSessionRepositoryEntity";
4
4
  import { BackupSessionTaskEntity } from "../Entity/BackupSessionTaskEntity";
5
- import { WriteDataType, SessionDriverAbstract } from "../SessionDriver/SessionDriverAbstract";
5
+ import { WriteDataType } from "../SessionDriver/SessionDriverAbstract";
6
6
  import { ObjectVault } from "../util/ObjectVault";
7
- export declare type OptionsType = {
8
- driver: SessionDriverAbstract;
9
- altDrivers?: SessionDriverAbstract[];
10
- verbose?: boolean;
11
- };
12
- export declare class BackupSessionManager {
13
- readonly options: OptionsType;
7
+ import { Progress } from "../util/progress";
8
+ import SessionManagerAbstract from "./SessionManagerAbstract";
9
+ export declare class BackupSessionManager extends SessionManagerAbstract {
14
10
  sessionVault: ObjectVault<BackupSessionEntity>;
15
11
  taskVault: ObjectVault<BackupSessionTaskEntity>;
16
12
  repositoryVault: ObjectVault<BackupSessionRepositoryEntity>;
17
- constructor(options: OptionsType);
18
13
  findId(data: {
19
14
  packageName: string;
20
15
  }): number;
@@ -36,9 +31,15 @@ export declare class BackupSessionManager {
36
31
  start(input: Pick<BackupSessionEntity, "id">): Promise<number>;
37
32
  end(input: Pick<BackupSessionEntity, "id" | "error">): Promise<number>;
38
33
  startTask(input: Pick<BackupSessionTaskEntity, "id">): Promise<number>;
39
- progressTask(input: Pick<BackupSessionTaskEntity, "id" | "progressTotal" | "progressCurrent" | "progressPercent" | "progressStep" | "progressStepPercent">): Promise<number>;
34
+ progressTask(input: {
35
+ id: number;
36
+ progress: Progress;
37
+ }): Promise<number>;
40
38
  endTask(input: Pick<BackupSessionTaskEntity, "id" | "error">): Promise<number>;
41
39
  startRepository(input: Pick<BackupSessionRepositoryEntity, "id">): Promise<number>;
42
- progressRepository(input: Pick<BackupSessionTaskEntity, "id" | "progressTotal" | "progressCurrent" | "progressPercent" | "progressStep" | "progressStepPercent">): Promise<number>;
40
+ progressRepository(input: {
41
+ id: number;
42
+ progress: Progress;
43
+ }): Promise<number>;
43
44
  endRepository(input: Pick<BackupSessionRepositoryEntity, "id" | "error">): Promise<number>;
44
45
  }
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.BackupSessionManager = void 0;
4
7
  const SessionDriverAbstract_1 = require("../SessionDriver/SessionDriverAbstract");
5
8
  const ObjectVault_1 = require("../util/ObjectVault");
6
- class BackupSessionManager {
7
- constructor(options) {
8
- this.options = options;
9
+ const SessionManagerAbstract_1 = __importDefault(require("./SessionManagerAbstract"));
10
+ class BackupSessionManager extends SessionManagerAbstract_1.default {
11
+ constructor() {
12
+ super(...arguments);
9
13
  this.sessionVault = new ObjectVault_1.ObjectVault();
10
14
  this.taskVault = new ObjectVault_1.ObjectVault();
11
15
  this.repositoryVault = new ObjectVault_1.ObjectVault();
@@ -29,14 +33,25 @@ class BackupSessionManager {
29
33
  }
30
34
  async endDrivers(data) {
31
35
  const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
36
+ this.stopDelayedProgress();
32
37
  for (const driver of drivers) {
33
38
  await driver.onEnd(data);
34
39
  }
35
40
  }
36
41
  async alter(data) {
37
42
  const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
38
- for (const driver of drivers) {
39
- await driver.onWrite(data);
43
+ const write = async () => {
44
+ for (const driver of drivers) {
45
+ await driver.onWrite(data);
46
+ }
47
+ };
48
+ if (data.action === SessionDriverAbstract_1.ActionEnum.Progress &&
49
+ !this.checkProgress(data.data.progress?.relative?.description)) {
50
+ this.delayProgress(write);
51
+ }
52
+ else {
53
+ this.stopDelayedProgress();
54
+ await write();
40
55
  }
41
56
  return data.data.id;
42
57
  }
@@ -2,19 +2,16 @@ import { BackupSessionsActionOptionsType } from "../Action/BackupSessionsAction"
2
2
  import { RestoreSessionEntity } from "../Entity/RestoreSessionEntity";
3
3
  import { RestoreSessionRepositoryEntity } from "../Entity/RestoreSessionRepositoryEntity";
4
4
  import { RestoreSessionTaskEntity } from "../Entity/RestoreSessionTaskEntity";
5
- import { WriteDataType, SessionDriverAbstract } from "../SessionDriver/SessionDriverAbstract";
5
+ import { WriteDataType } from "../SessionDriver/SessionDriverAbstract";
6
6
  import { ObjectVault } from "../util/ObjectVault";
7
- export declare type OptionsType = {
8
- driver: SessionDriverAbstract;
9
- altDrivers?: SessionDriverAbstract[];
10
- verbose?: boolean;
11
- };
12
- export declare class RestoreSessionManager {
13
- readonly options: OptionsType;
7
+ import { Progress } from "../util/progress";
8
+ import SessionManagerAbstract from "./SessionManagerAbstract";
9
+ export declare class RestoreSessionManager extends SessionManagerAbstract {
14
10
  sessionVault: ObjectVault<RestoreSessionEntity>;
15
11
  repositoryVault: ObjectVault<RestoreSessionRepositoryEntity>;
16
12
  taskVault: ObjectVault<RestoreSessionTaskEntity>;
17
- constructor(options: OptionsType);
13
+ protected lastProgressDate: number | undefined;
14
+ protected lastRelativeProgressDescription: string | null | undefined;
18
15
  findId(data: {
19
16
  packageName: string;
20
17
  }): number;
@@ -37,8 +34,14 @@ export declare class RestoreSessionManager {
37
34
  end(input: Pick<RestoreSessionEntity, "id" | "error">): Promise<number>;
38
35
  startTask(input: Pick<RestoreSessionTaskEntity, "id">): Promise<number>;
39
36
  startRepository(input: Pick<RestoreSessionRepositoryEntity, "id">): Promise<number>;
40
- progressTask(input: Pick<RestoreSessionTaskEntity, "id" | "progressTotal" | "progressCurrent" | "progressPercent" | "progressStep" | "progressStepPercent">): Promise<number>;
37
+ progressTask(input: {
38
+ id: number;
39
+ progress: Progress;
40
+ }): Promise<number>;
41
41
  endTask(input: Pick<RestoreSessionTaskEntity, "id" | "error">): Promise<number>;
42
- progressRepository(input: Pick<RestoreSessionRepositoryEntity, "id" | "progressTotal" | "progressCurrent" | "progressPercent" | "progressStep" | "progressStepPercent">): Promise<number>;
42
+ progressRepository(input: {
43
+ id: number;
44
+ progress: Progress;
45
+ }): Promise<number>;
43
46
  endRepository(input: Pick<RestoreSessionRepositoryEntity, "id" | "error">): Promise<number>;
44
47
  }
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.RestoreSessionManager = void 0;
4
7
  const SessionDriverAbstract_1 = require("../SessionDriver/SessionDriverAbstract");
5
8
  const ObjectVault_1 = require("../util/ObjectVault");
6
- class RestoreSessionManager {
7
- constructor(options) {
8
- this.options = options;
9
+ const SessionManagerAbstract_1 = __importDefault(require("./SessionManagerAbstract"));
10
+ class RestoreSessionManager extends SessionManagerAbstract_1.default {
11
+ constructor() {
12
+ super(...arguments);
9
13
  this.sessionVault = new ObjectVault_1.ObjectVault();
10
14
  this.repositoryVault = new ObjectVault_1.ObjectVault();
11
15
  this.taskVault = new ObjectVault_1.ObjectVault();
@@ -29,14 +33,25 @@ class RestoreSessionManager {
29
33
  }
30
34
  async endDrivers() {
31
35
  const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
36
+ this.stopDelayedProgress();
32
37
  for (const driver of drivers) {
33
38
  await driver.onEnd();
34
39
  }
35
40
  }
36
41
  async alter(data) {
37
42
  const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
38
- for (const driver of drivers) {
39
- await driver.onWrite(data);
43
+ const write = async () => {
44
+ for (const driver of drivers) {
45
+ await driver.onWrite(data);
46
+ }
47
+ };
48
+ if (data.action === SessionDriverAbstract_1.ActionEnum.Progress &&
49
+ !this.checkProgress(data.data.progress?.relative?.description)) {
50
+ this.delayProgress(write);
51
+ }
52
+ else {
53
+ this.stopDelayedProgress();
54
+ await write();
40
55
  }
41
56
  return data.data.id;
42
57
  }
@@ -0,0 +1,18 @@
1
+ /// <reference types="node" />
2
+ import { SessionDriverAbstract } from "../SessionDriver/SessionDriverAbstract";
3
+ export declare type OptionsType = {
4
+ driver: SessionDriverAbstract;
5
+ altDrivers?: SessionDriverAbstract[];
6
+ progressInterval?: number;
7
+ verbose?: boolean;
8
+ };
9
+ export default abstract class SessionManagerAbstract {
10
+ readonly options: OptionsType;
11
+ protected lastProgressDate: number | undefined;
12
+ protected lastRelativeProgressDescription: string | null | undefined;
13
+ protected progressTimeout: ReturnType<typeof setTimeout> | undefined;
14
+ constructor(options: OptionsType);
15
+ protected stopDelayedProgress(): void;
16
+ protected delayProgress(cb: () => Promise<any>): void;
17
+ protected checkProgress(description: string | null | undefined): boolean;
18
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class SessionManagerAbstract {
4
+ constructor(options) {
5
+ this.options = options;
6
+ }
7
+ stopDelayedProgress() {
8
+ clearTimeout(this.progressTimeout);
9
+ this.progressTimeout = undefined;
10
+ }
11
+ delayProgress(cb) {
12
+ clearTimeout(this.progressTimeout);
13
+ this.progressTimeout = setTimeout(async () => {
14
+ this.progressTimeout = undefined;
15
+ await cb();
16
+ }, 1500);
17
+ }
18
+ checkProgress(description) {
19
+ const progressInterval = this.options.progressInterval;
20
+ if (progressInterval) {
21
+ const skip = this.lastProgressDate &&
22
+ description === this.lastRelativeProgressDescription &&
23
+ Date.now() - this.lastProgressDate < progressInterval;
24
+ if (skip)
25
+ return false;
26
+ this.lastProgressDate = Date.now();
27
+ this.lastRelativeProgressDescription = description;
28
+ }
29
+ return true;
30
+ }
31
+ }
32
+ exports.default = SessionManagerAbstract;
package/Task/GitTask.js CHANGED
@@ -73,7 +73,9 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
73
73
  // Bundle
74
74
  const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
75
75
  await data.onProgress({
76
- step: "Creating bundle...",
76
+ relative: {
77
+ description: "Creating bundle",
78
+ },
77
79
  });
78
80
  await (0, process_util_1.exec)(this.command, ["bundle", "create", bundlePath, "--all"], {
79
81
  cwd: path,
@@ -174,10 +176,15 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
174
176
  onPath: async ({ entryPath }) => {
175
177
  currentFiles++;
176
178
  await data.onProgress({
177
- total,
178
- current: currentFiles,
179
- percent: (0, math_util_1.progressPercent)(total, currentFiles),
180
- step: entryPath,
179
+ relative: {
180
+ description: "Copying file",
181
+ payload: entryPath,
182
+ },
183
+ absolute: {
184
+ total,
185
+ current: currentFiles,
186
+ percent: (0, math_util_1.progressPercent)(total, currentFiles),
187
+ },
181
188
  });
182
189
  },
183
190
  });
@@ -201,14 +208,17 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
201
208
  let totalFiles = 0;
202
209
  let currentFiles = 0;
203
210
  await (0, fs_util_1.forEachFile)(targetPath, () => totalFiles++, true);
204
- const incrementProgress = async (step = "") => {
211
+ const incrementProgress = async (description, item, count = true) => {
205
212
  await data.onProgress({
206
- total: totalFiles,
207
- current: Math.max(currentFiles, 0),
208
- percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
209
- step,
213
+ absolute: {
214
+ total: totalFiles,
215
+ current: Math.max(currentFiles, 0),
216
+ percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
217
+ },
218
+ relative: { description, payload: item },
210
219
  });
211
- currentFiles++;
220
+ if (count)
221
+ currentFiles++;
212
222
  };
213
223
  // Bundle
214
224
  const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
@@ -237,9 +247,7 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
237
247
  },
238
248
  targetPath: restorePath,
239
249
  concurrency: this.config.fileCopyConcurrency,
240
- onPath: async ({ entryPath }) => {
241
- await incrementProgress(entryPath);
242
- },
250
+ onProgress: async (progress) => await incrementProgress(progress.type === "end" ? "Files copied" : "Copying file", progress.path, !progress.type),
243
251
  });
244
252
  }
245
253
  }
@@ -108,10 +108,15 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
108
108
  else if (paths.length) {
109
109
  const path = (0, posix_1.normalize)(paths[0]);
110
110
  await data.onProgress({
111
- current,
112
- percent: (0, math_util_1.progressPercent)(total, current),
113
- total,
114
- step: `Copying ${path}`,
111
+ relative: {
112
+ description: "Copying file",
113
+ payload: path,
114
+ },
115
+ absolute: {
116
+ current,
117
+ percent: (0, math_util_1.progressPercent)(total, current),
118
+ total,
119
+ },
115
120
  });
116
121
  }
117
122
  };
@@ -9,7 +9,9 @@ export declare class MysqlDumpTask extends SqlDumpTaskAbstract<MysqlDumpTaskConf
9
9
  onCreateDatabase(database: TargetDatabaseType): Promise<void>;
10
10
  onExecQuery(query: string): Promise<import("../util/process-util").ExecResultType>;
11
11
  onFetchTableNames(database: string): Promise<string[]>;
12
- onExportTables(tableNames: string[], output: string): Promise<void>;
12
+ onExportTables(tableNames: string[], output: string, onProgress: (progress: {
13
+ totalBytes: number;
14
+ }) => void): Promise<void>;
13
15
  onExportStoredPrograms(output: string): Promise<void>;
14
16
  onImport(path: string, database: string): Promise<void>;
15
17
  }
@@ -70,7 +70,7 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
70
70
  table_name
71
71
  `);
72
72
  }
73
- async onExportTables(tableNames, output) {
73
+ async onExportTables(tableNames, output, onProgress) {
74
74
  const stream = (0, fs_1.createWriteStream)(output);
75
75
  await Promise.all([
76
76
  new Promise((resolve, reject) => {
@@ -83,7 +83,10 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
83
83
  "--skip-add-drop-table=false",
84
84
  ...tableNames,
85
85
  ], null, {
86
- pipe: { stream: stream },
86
+ pipe: {
87
+ stream,
88
+ onWriteProgress: onProgress,
89
+ },
87
90
  log: {
88
91
  exec: this.verbose,
89
92
  stderr: this.verbose,
@@ -9,7 +9,9 @@ export declare class PostgresqlDumpTask extends SqlDumpTaskAbstract<PostgresqlDu
9
9
  onCreateDatabase(database: TargetDatabaseType): Promise<void>;
10
10
  onExecQuery(query: string): Promise<import("../util/process-util").ExecResultType>;
11
11
  onFetchTableNames(database: string): Promise<string[]>;
12
- onExportTables(tableNames: string[], output: string): Promise<void>;
12
+ onExportTables(tableNames: string[], output: string, onProgress: (progress: {
13
+ totalBytes: number;
14
+ }) => void): Promise<void>;
13
15
  onExportStoredPrograms(): Promise<void>;
14
16
  onImport(path: string, database: string): Promise<void>;
15
17
  }
@@ -73,7 +73,7 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
73
73
  CONCAT(table_schema, '.', table_name)
74
74
  `);
75
75
  }
76
- async onExportTables(tableNames, output) {
76
+ async onExportTables(tableNames, output, onProgress) {
77
77
  const stream = (0, fs_1.createWriteStream)(output);
78
78
  await Promise.all([
79
79
  new Promise((resolve, reject) => {
@@ -84,7 +84,7 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
84
84
  ...(await this.buildConnectionArgs()),
85
85
  ...(tableNames?.flatMap((v) => ["-t", v]) ?? []),
86
86
  ], null, {
87
- pipe: { stream: stream },
87
+ pipe: { stream, onWriteProgress: onProgress },
88
88
  stderr: {
89
89
  toExitCode: true,
90
90
  },
@@ -29,7 +29,9 @@ export declare abstract class SqlDumpTaskAbstract<TConfig extends SqlDumpTaskCon
29
29
  abstract onDatabaseIsEmpty(databaseName: string): Promise<boolean>;
30
30
  abstract onFetchTableNames(database: string): Promise<string[]>;
31
31
  abstract onExecQuery(query: string): ReturnType<typeof exec>;
32
- abstract onExportTables(tableNames: string[], output: string): Promise<void>;
32
+ abstract onExportTables(tableNames: string[], output: string, onProgress: (data: {
33
+ totalBytes: number;
34
+ }) => void): Promise<void>;
33
35
  abstract onExportStoredPrograms(output: string): Promise<void>;
34
36
  abstract onImport(path: string, database: string): Promise<void>;
35
37
  onBackup(data: BackupDataType): Promise<void>;
@@ -118,24 +118,61 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
118
118
  await (0, promises_1.mkdir)(outputPath, { recursive: true });
119
119
  if (!this.config.oneFileByTable) {
120
120
  const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ database: this.config.database }));
121
- await this.onExportTables(tableNames, outPath);
121
+ data.onProgress({
122
+ relative: {
123
+ description: "Exporting",
124
+ },
125
+ });
126
+ await this.onExportTables(tableNames, outPath, async (progress) => {
127
+ await data.onProgress({
128
+ absolute: {
129
+ description: "Exporting in single file",
130
+ current: progress.totalBytes,
131
+ format: "size",
132
+ },
133
+ });
134
+ });
122
135
  }
123
136
  else {
124
137
  let current = 0;
125
138
  for (const tableName of tableNames) {
126
- data.onProgress({
127
- total: tableNames.length,
128
- current: current,
129
- percent: (0, math_util_1.progressPercent)(tableNames.length, current),
130
- step: tableName,
139
+ await data.onProgress({
140
+ relative: {
141
+ description: "Exporting",
142
+ payload: tableName,
143
+ },
144
+ absolute: {
145
+ total: tableNames.length,
146
+ current: current,
147
+ percent: (0, math_util_1.progressPercent)(tableNames.length, current),
148
+ },
131
149
  });
132
- current++;
133
150
  const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ table: tableName }));
134
- await this.onExportTables([tableName], outPath);
151
+ await this.onExportTables([tableName], outPath, async (progress) => {
152
+ await data.onProgress({
153
+ relative: {
154
+ description: "Exporting",
155
+ payload: tableName,
156
+ current: progress.totalBytes,
157
+ format: "size",
158
+ },
159
+ absolute: {
160
+ total: tableNames.length,
161
+ current: current,
162
+ percent: (0, math_util_1.progressPercent)(tableNames.length, current),
163
+ },
164
+ });
165
+ });
166
+ current++;
135
167
  }
136
168
  }
137
169
  if (this.config.storedPrograms) {
138
170
  const outPath = (0, path_1.join)(outputPath, "stored-programs.sql");
171
+ data.onProgress({
172
+ relative: {
173
+ description: "Exporting storaged programs",
174
+ },
175
+ });
139
176
  await this.onExportStoredPrograms(outPath);
140
177
  }
141
178
  }
@@ -184,13 +221,18 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
184
221
  for (const item of items) {
185
222
  const path = (0, path_1.join)(restorePath, item.fileName);
186
223
  data.onProgress({
187
- total: items.length,
188
- current: current,
189
- percent: (0, math_util_1.progressPercent)(items.length, current),
190
- step: item.fileName,
224
+ relative: {
225
+ description: "Importing",
226
+ payload: item.fileName,
227
+ },
228
+ absolute: {
229
+ total: items.length,
230
+ current: current,
231
+ percent: (0, math_util_1.progressPercent)(items.length, current),
232
+ },
191
233
  });
192
- current++;
193
234
  await this.onImport(path, database.name);
235
+ current++;
194
236
  }
195
237
  }
196
238
  }
@@ -2,22 +2,16 @@ import { BackupActionOptionsType } from "../Action/BackupAction";
2
2
  import { RestoreActionOptionsType } from "../Action/RestoreAction";
3
3
  import { PackageConfigType } from "../Config/PackageConfig";
4
4
  import { SnapshotType } from "../Repository/RepositoryAbstract";
5
- export declare type ProgressDataType = {
6
- total?: number;
7
- current?: number;
8
- percent?: number;
9
- step?: string;
10
- stepPercent?: number;
11
- };
5
+ import { Progress } from "../util/progress";
12
6
  export declare type BackupDataType = {
13
- onProgress: (data: ProgressDataType) => Promise<void>;
7
+ onProgress: (data: Progress) => Promise<void>;
14
8
  options: BackupActionOptionsType;
15
9
  package: PackageConfigType;
16
10
  targetPath: string | undefined;
17
11
  snapshot: SnapshotType;
18
12
  };
19
13
  export declare type RestoreDataType = {
20
- onProgress: (data: ProgressDataType) => Promise<void>;
14
+ onProgress: (data: Progress) => Promise<void>;
21
15
  options: RestoreActionOptionsType;
22
16
  package: PackageConfigType;
23
17
  targetPath: string | undefined;