@datatruck/cli 0.13.1 → 0.16.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 (48) hide show
  1. package/Action/BackupAction.js +7 -19
  2. package/Action/RestoreAction.js +4 -12
  3. package/Command/BackupCommand.js +2 -1
  4. package/Command/BackupSessionsCommand.js +1 -0
  5. package/Command/RestoreCommand.js +1 -1
  6. package/Command/RestoreSessionsCommand.js +1 -0
  7. package/Entity/StateEntityAbstract.d.ts +2 -5
  8. package/Error/AppError.d.ts +1 -0
  9. package/Error/AppError.js +4 -0
  10. package/Repository/DatatruckRepository.d.ts +2 -0
  11. package/Repository/DatatruckRepository.js +234 -123
  12. package/Repository/RepositoryAbstract.d.ts +4 -10
  13. package/Repository/ResticRepository.js +34 -17
  14. package/SessionDriver/ConsoleSessionDriver.d.ts +2 -7
  15. package/SessionDriver/ConsoleSessionDriver.js +51 -24
  16. package/SessionDriver/SqliteSessionDriver.js +5 -0
  17. package/SessionManager/BackupSessionManager.d.ts +12 -11
  18. package/SessionManager/BackupSessionManager.js +20 -5
  19. package/SessionManager/RestoreSessionManager.d.ts +14 -11
  20. package/SessionManager/RestoreSessionManager.js +20 -5
  21. package/SessionManager/SessionManagerAbstract.d.ts +18 -0
  22. package/SessionManager/SessionManagerAbstract.js +32 -0
  23. package/Task/GitTask.js +22 -14
  24. package/Task/MariadbTask.js +9 -4
  25. package/Task/MysqlDumpTask.d.ts +3 -1
  26. package/Task/MysqlDumpTask.js +5 -2
  27. package/Task/PostgresqlDumpTask.d.ts +3 -1
  28. package/Task/PostgresqlDumpTask.js +2 -2
  29. package/Task/SqlDumpTaskAbstract.d.ts +3 -1
  30. package/Task/SqlDumpTaskAbstract.js +55 -13
  31. package/Task/TaskAbstract.d.ts +3 -9
  32. package/cli.js +1 -1
  33. package/config.schema.json +3 -0
  34. package/migrations/001-initial.sql +6 -30
  35. package/package.json +1 -1
  36. package/util/cli-util.d.ts +1 -1
  37. package/util/cli-util.js +17 -2
  38. package/util/fs-util.d.ts +25 -21
  39. package/util/fs-util.js +60 -93
  40. package/util/math-util.js +2 -0
  41. package/util/process-util.d.ts +4 -0
  42. package/util/process-util.js +31 -4
  43. package/util/progress.d.ts +12 -0
  44. package/util/progress.js +2 -0
  45. package/util/string-util.d.ts +1 -0
  46. package/util/string-util.js +8 -1
  47. package/util/zip-util.d.ts +64 -20
  48. package/util/zip-util.js +153 -59
@@ -4,6 +4,7 @@ import type { RestoreActionOptionsType } from "../Action/RestoreAction";
4
4
  import type { SnapshotExtendedType, SnapshotsActionOptionsType } from "../Action/SnapshotsAction";
5
5
  import type { PackageConfigType } from "../Config/PackageConfig";
6
6
  import type { RepositoryConfigType } from "../Config/RepositoryConfig";
7
+ import { Progress } from "../util/progress";
7
8
  export declare type SnapshotType = {
8
9
  id: string;
9
10
  date: string;
@@ -15,13 +16,6 @@ export declare type SnapshotResultType = SnapshotType & {
15
16
  tags: string[];
16
17
  size: number;
17
18
  };
18
- export declare type ProgressDataType = {
19
- total?: number;
20
- current?: number;
21
- percent?: number;
22
- step?: string;
23
- stepPercent?: number | null;
24
- };
25
19
  export declare type InitDataType = {
26
20
  options: InitActionOptionsType;
27
21
  };
@@ -33,7 +27,7 @@ export declare type CopyBackupType<TRepositoryConfig> = {
33
27
  snapshot: SnapshotType;
34
28
  package: PackageConfigType;
35
29
  mirrorRepositoryConfig: TRepositoryConfig;
36
- onProgress: (data: ProgressDataType) => Promise<void>;
30
+ onProgress: (data: Progress) => Promise<void>;
37
31
  };
38
32
  export declare type BackupDataType<TPackageConfig> = {
39
33
  options: BackupActionOptionsType;
@@ -41,7 +35,7 @@ export declare type BackupDataType<TPackageConfig> = {
41
35
  package: PackageConfigType;
42
36
  targetPath: string | undefined;
43
37
  packageConfig: TPackageConfig | undefined;
44
- onProgress: (data: ProgressDataType) => Promise<void>;
38
+ onProgress: (data: Progress) => Promise<void>;
45
39
  };
46
40
  export declare type RestoreDataType<TPackageConfig> = {
47
41
  options: RestoreActionOptionsType;
@@ -49,7 +43,7 @@ export declare type RestoreDataType<TPackageConfig> = {
49
43
  package: PackageConfigType;
50
44
  targetPath: string | undefined;
51
45
  packageConfig: TPackageConfig;
52
- onProgress: (data: ProgressDataType) => Promise<void>;
46
+ onProgress: (data: Progress) => Promise<void>;
53
47
  };
54
48
  export declare type PruneDataType = {
55
49
  snapshot: SnapshotExtendedType;
@@ -195,7 +195,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
195
195
  verbose: data.options.verbose,
196
196
  });
197
197
  await data.onProgress({
198
- step: "Writing excluded paths list...",
198
+ relative: {
199
+ description: "Writing excluded paths list",
200
+ },
199
201
  });
200
202
  const tmpDir = await (0, fs_util_1.mkTmpDir)("restic-exclude");
201
203
  const ignoredContents = (0, fs_util_1.fastglobToGitIgnore)(exclude, sourcePath).join("\n");
@@ -223,7 +225,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
223
225
  if (data.options.verbose)
224
226
  (0, cli_util_1.logExec)(`Writing paths lists`);
225
227
  await data.onProgress({
226
- step: "Writing excluded paths list...",
228
+ relative: {
229
+ description: "Writing excluded paths list",
230
+ },
227
231
  });
228
232
  gitignorePath = await (0, fs_util_1.writeGitIgnoreList)({
229
233
  paths: stream,
@@ -233,7 +237,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
233
237
  throw new AppError_1.AppError(`Tag prefix is not allowed`);
234
238
  const packageTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.PACKAGE, data.package.name);
235
239
  await data.onProgress({
236
- step: "Fetching last snapshot...",
240
+ relative: {
241
+ description: "Fetching last snapshot",
242
+ },
237
243
  });
238
244
  const [lastSnapshot] = await restic.snapshots({
239
245
  json: true,
@@ -245,7 +251,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
245
251
  let totalFilesChanges = 0;
246
252
  const totalFilesChangesLimit = 10;
247
253
  await data.onProgress({
248
- step: "Executing backup action...",
254
+ relative: {
255
+ description: "Executing backup action",
256
+ },
249
257
  });
250
258
  let resticSnapshotId;
251
259
  let resticTotalBytes;
@@ -278,19 +286,24 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
278
286
  if (totalFilesChanges > totalFilesChangesLimit) {
279
287
  showProgressBar = true;
280
288
  }
281
- else if (lastProgress?.total !== streamData.total_files) {
289
+ else if (lastProgress?.absolute?.total !== streamData.total_files) {
282
290
  totalFilesChanges = 0;
283
291
  }
284
292
  else {
285
293
  totalFilesChanges++;
286
294
  }
287
295
  await data.onProgress((lastProgress = {
288
- total: Math.max(lastProgress?.total || 0, streamData.total_files || 0),
289
- current: Math.max(lastProgress?.current || 0, streamData.files_done ?? 0),
290
- percent: showProgressBar
291
- ? Number((streamData.percent_done * 100).toFixed(2))
292
- : 0,
293
- step: streamData.current_files?.join(", ") ?? "-",
296
+ relative: {
297
+ description: "Copying file",
298
+ payload: streamData.current_files?.join(", ") ?? "-",
299
+ },
300
+ absolute: {
301
+ total: Math.max(lastProgress?.absolute?.total || 0, streamData.total_files || 0),
302
+ current: Math.max(lastProgress?.absolute?.current || 0, streamData.files_done ?? 0),
303
+ percent: showProgressBar
304
+ ? Number((streamData.percent_done * 100).toFixed(2))
305
+ : 0,
306
+ },
294
307
  }));
295
308
  }
296
309
  else if (streamData.message_type === "summary") {
@@ -306,9 +319,11 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
306
319
  const sizeTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.SIZE, resticTotalBytes.toString());
307
320
  await restic.exec(["tag", "--add", sizeTag, resticSnapshotId]);
308
321
  await data.onProgress({
309
- total: lastProgress?.total || 0,
310
- current: lastProgress?.total || 0,
311
- percent: 100,
322
+ absolute: {
323
+ total: lastProgress?.absolute?.total || 0,
324
+ current: lastProgress?.absolute?.total || 0,
325
+ percent: 100,
326
+ },
312
327
  });
313
328
  }
314
329
  async onCopyBackup(data) {
@@ -357,9 +372,11 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
357
372
  if (streamData.message_type === "restore-status") {
358
373
  const current = Math.min(streamData.total_bytes, snapshot.size);
359
374
  await data.onProgress({
360
- total: snapshot.size,
361
- current,
362
- percent: (0, math_util_1.progressPercent)(snapshot.size, current),
375
+ absolute: {
376
+ total: snapshot.size,
377
+ current,
378
+ percent: (0, math_util_1.progressPercent)(snapshot.size, current),
379
+ },
363
380
  });
364
381
  }
365
382
  },
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ import { Progress } from "../util/progress";
2
3
  import { WriteDataType, ReadResultType, SessionDriverAbstract, SessionDriverOptions } from "./SessionDriverAbstract";
3
4
  declare type BadgeType = {
4
5
  name: string;
@@ -12,20 +13,14 @@ declare type MessageType = {
12
13
  text?: string;
13
14
  badges: BadgeType[];
14
15
  errorBadge?: BadgeType;
15
- progressCurrent?: number | null;
16
- progressTotal?: number | null;
17
- progressPercent?: number | null;
18
- progressStep?: string | null;
19
- progressStepPercent?: number | null;
16
+ progress?: Progress;
20
17
  };
21
18
  declare type ConsoleSessionDriverOptions = SessionDriverOptions & {
22
19
  progress?: "auto" | "tty" | "plain";
23
- progressInterval?: number;
24
20
  };
25
21
  export declare class ConsoleSessionDriver extends SessionDriverAbstract<ConsoleSessionDriverOptions> {
26
22
  protected lastMessage: MessageType | undefined;
27
23
  protected lastMessageText: string | undefined;
28
- protected lastProgressDate: number | undefined;
29
24
  protected prints: number;
30
25
  protected renderInterval: NodeJS.Timeout;
31
26
  protected rendering?: boolean;
@@ -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
  }