@datatruck/cli 0.13.0 → 0.15.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 (36) hide show
  1. package/Action/BackupAction.js +3 -15
  2. package/Action/RestoreAction.js +2 -10
  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 -1
  8. package/Repository/DatatruckRepository.d.ts +2 -0
  9. package/Repository/DatatruckRepository.js +239 -108
  10. package/Repository/RepositoryAbstract.d.ts +10 -5
  11. package/Repository/ResticRepository.js +34 -17
  12. package/SessionDriver/ConsoleSessionDriver.d.ts +2 -3
  13. package/SessionDriver/ConsoleSessionDriver.js +11 -10
  14. package/SessionManager/BackupSessionManager.d.ts +10 -11
  15. package/SessionManager/BackupSessionManager.js +24 -5
  16. package/SessionManager/RestoreSessionManager.d.ts +12 -11
  17. package/SessionManager/RestoreSessionManager.js +24 -5
  18. package/SessionManager/SessionManagerAbstract.d.ts +14 -0
  19. package/SessionManager/SessionManagerAbstract.js +21 -0
  20. package/Task/GitTask.js +23 -14
  21. package/Task/MariadbTask.js +9 -4
  22. package/Task/SqlDumpTaskAbstract.js +31 -10
  23. package/Task/TaskAbstract.d.ts +10 -5
  24. package/cli.js +1 -1
  25. package/config.schema.json +4 -0
  26. package/migrations/001-initial.sql +12 -6
  27. package/package.json +1 -1
  28. package/util/fs-util.d.ts +27 -21
  29. package/util/fs-util.js +89 -101
  30. package/util/math-util.js +2 -0
  31. package/util/process-util.d.ts +1 -0
  32. package/util/process-util.js +20 -4
  33. package/util/string-util.d.ts +1 -0
  34. package/util/string-util.js +8 -1
  35. package/util/zip-util.d.ts +64 -19
  36. package/util/zip-util.js +156 -59
@@ -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
+ step: {
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
+ step: {
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
+ step: {
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
+ step: {
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?.stats?.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
+ step: {
297
+ description: "Copying file",
298
+ item: streamData.current_files?.join(", ") ?? "-",
299
+ },
300
+ stats: {
301
+ total: Math.max(lastProgress?.stats?.total || 0, streamData.total_files || 0),
302
+ current: Math.max(lastProgress?.stats?.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
+ stats: {
323
+ total: lastProgress?.stats?.total || 0,
324
+ current: lastProgress?.stats?.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
+ stats: {
376
+ total: snapshot.size,
377
+ current,
378
+ percent: (0, math_util_1.progressPercent)(snapshot.size, current),
379
+ },
363
380
  });
364
381
  }
365
382
  },
@@ -15,17 +15,16 @@ declare type MessageType = {
15
15
  progressCurrent?: number | null;
16
16
  progressTotal?: number | null;
17
17
  progressPercent?: number | null;
18
- progressStep?: string | null;
18
+ progressStepDescription?: string | null;
19
+ progressStepItem?: string | null;
19
20
  progressStepPercent?: number | null;
20
21
  };
21
22
  declare type ConsoleSessionDriverOptions = SessionDriverOptions & {
22
23
  progress?: "auto" | "tty" | "plain";
23
- progressInterval?: number;
24
24
  };
25
25
  export declare class ConsoleSessionDriver extends SessionDriverAbstract<ConsoleSessionDriverOptions> {
26
26
  protected lastMessage: MessageType | undefined;
27
27
  protected lastMessageText: string | undefined;
28
- protected lastProgressDate: number | undefined;
29
28
  protected prints: number;
30
29
  protected renderInterval: NodeJS.Timeout;
31
30
  protected rendering?: boolean;
@@ -83,8 +83,15 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
83
83
  typeof message.progressTotal === "number") {
84
84
  parts.push(`${message.progressCurrent ?? "?"}/${message.progressTotal ?? "?"}`);
85
85
  }
86
- if (typeof message.progressStep === "string")
87
- parts.push(message.progressStep);
86
+ if (message.progressStepDescription && message.progressStepItem) {
87
+ parts.push(`${message.progressStepDescription}: ${message.progressStepItem}`);
88
+ }
89
+ else if (message.progressStepDescription) {
90
+ parts.push(message.progressStepDescription);
91
+ }
92
+ else if (message.progressStepItem) {
93
+ parts.push(message.progressStepItem);
94
+ }
88
95
  if (typeof message.progressStepPercent === "number") {
89
96
  parts.push((0, chalk_1.cyan)((0, cli_util_1.renderProgressBar)(message.progressStepPercent ?? 0, 10)));
90
97
  }
@@ -93,13 +100,6 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
93
100
  async onWrite(data) {
94
101
  if (data.action === SessionDriverAbstract_1.ActionEnum.Init)
95
102
  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
103
  const message = {
104
104
  sessionId: "sessionId" in data.data ? data.data.sessionId : data.data.id,
105
105
  badges: [],
@@ -135,7 +135,8 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
135
135
  message.progressPercent = data.data.progressPercent;
136
136
  message.progressCurrent = data.data.progressCurrent;
137
137
  message.progressTotal = data.data.progressTotal;
138
- message.progressStep = data.data.progressStep;
138
+ message.progressStepDescription = data.data.progressStepDescription;
139
+ message.progressStepItem = data.data.progressStepItem;
139
140
  message.progressStepPercent = data.data.progressStepPercent;
140
141
  }
141
142
  if (data.entity === SessionDriverAbstract_1.EntityEnum.BackupSession ||
@@ -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 { ProgressDataType } from "../Repository/RepositoryAbstract";
6
+ import { WriteDataType } from "../SessionDriver/SessionDriverAbstract";
6
7
  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;
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,13 @@ 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
+ } & ProgressDataType): Promise<number>;
40
37
  endTask(input: Pick<BackupSessionTaskEntity, "id" | "error">): Promise<number>;
41
38
  startRepository(input: Pick<BackupSessionRepositoryEntity, "id">): Promise<number>;
42
- progressRepository(input: Pick<BackupSessionTaskEntity, "id" | "progressTotal" | "progressCurrent" | "progressPercent" | "progressStep" | "progressStepPercent">): Promise<number>;
39
+ progressRepository(input: {
40
+ id: number;
41
+ } & ProgressDataType): Promise<number>;
43
42
  endRepository(input: Pick<BackupSessionRepositoryEntity, "id" | "error">): Promise<number>;
44
43
  }
@@ -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();
@@ -35,6 +39,9 @@ class BackupSessionManager {
35
39
  }
36
40
  async alter(data) {
37
41
  const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
42
+ if (data.action === SessionDriverAbstract_1.ActionEnum.Progress &&
43
+ !this.checkProgress(data.data.progressStepDescription))
44
+ return data.data.id;
38
45
  for (const driver of drivers) {
39
46
  await driver.onWrite(data);
40
47
  }
@@ -139,7 +146,13 @@ class BackupSessionManager {
139
146
  sessionData: this.sessionVault.get(object.sessionId),
140
147
  data: {
141
148
  ...object,
142
- ...input,
149
+ id: input.id,
150
+ progressCurrent: input.stats?.current,
151
+ progressTotal: input.stats?.total,
152
+ progressPercent: input.stats?.percent,
153
+ progressStepDescription: input.step?.description,
154
+ progressStepItem: input.step?.item,
155
+ progressStepPercent: input.step?.percent,
143
156
  updatingDate: new Date().toISOString(),
144
157
  },
145
158
  });
@@ -182,7 +195,13 @@ class BackupSessionManager {
182
195
  sessionData: this.sessionVault.get(object.sessionId),
183
196
  data: {
184
197
  ...object,
185
- ...input,
198
+ id: input.id,
199
+ progressCurrent: input.stats?.current,
200
+ progressTotal: input.stats?.total,
201
+ progressPercent: input.stats?.percent,
202
+ progressStepDescription: input.step?.description,
203
+ progressStepItem: input.step?.item,
204
+ progressStepPercent: input.step?.percent,
186
205
  updatingDate: new Date().toISOString(),
187
206
  },
188
207
  });
@@ -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 { ProgressDataType } from "../Repository/RepositoryAbstract";
6
+ import { WriteDataType } from "../SessionDriver/SessionDriverAbstract";
6
7
  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;
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 lastProgressStepDescription: string | null | undefined;
18
15
  findId(data: {
19
16
  packageName: string;
20
17
  }): number;
@@ -37,8 +34,12 @@ 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
+ } & ProgressDataType): Promise<number>;
41
40
  endTask(input: Pick<RestoreSessionTaskEntity, "id" | "error">): Promise<number>;
42
- progressRepository(input: Pick<RestoreSessionRepositoryEntity, "id" | "progressTotal" | "progressCurrent" | "progressPercent" | "progressStep" | "progressStepPercent">): Promise<number>;
41
+ progressRepository(input: {
42
+ id: number;
43
+ } & ProgressDataType): Promise<number>;
43
44
  endRepository(input: Pick<RestoreSessionRepositoryEntity, "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.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();
@@ -35,6 +39,9 @@ class RestoreSessionManager {
35
39
  }
36
40
  async alter(data) {
37
41
  const drivers = [this.options.driver, ...(this.options.altDrivers ?? [])];
42
+ if (data.action === SessionDriverAbstract_1.ActionEnum.Progress &&
43
+ !this.checkProgress(data.data.progressStepDescription))
44
+ return data.data.id;
38
45
  for (const driver of drivers) {
39
46
  await driver.onWrite(data);
40
47
  }
@@ -154,7 +161,13 @@ class RestoreSessionManager {
154
161
  sessionData: this.sessionVault.get(object.sessionId),
155
162
  data: {
156
163
  ...object,
157
- ...input,
164
+ id: input.id,
165
+ progressCurrent: input.stats?.current,
166
+ progressTotal: input.stats?.total,
167
+ progressPercent: input.stats?.percent,
168
+ progressStepDescription: input.step?.description,
169
+ progressStepItem: input.step?.item,
170
+ progressStepPercent: input.step?.percent,
158
171
  updatingDate: new Date().toISOString(),
159
172
  },
160
173
  });
@@ -182,7 +195,13 @@ class RestoreSessionManager {
182
195
  sessionData: this.sessionVault.get(object.sessionId),
183
196
  data: {
184
197
  ...object,
185
- ...input,
198
+ id: input.id,
199
+ progressCurrent: input.stats?.current,
200
+ progressTotal: input.stats?.total,
201
+ progressPercent: input.stats?.percent,
202
+ progressStepDescription: input.step?.description,
203
+ progressStepItem: input.step?.item,
204
+ progressStepPercent: input.step?.percent,
186
205
  updatingDate: new Date().toISOString(),
187
206
  },
188
207
  });
@@ -0,0 +1,14 @@
1
+ import { SessionDriverAbstract } from "../SessionDriver/SessionDriverAbstract";
2
+ export declare type OptionsType = {
3
+ driver: SessionDriverAbstract;
4
+ altDrivers?: SessionDriverAbstract[];
5
+ progressInterval?: number;
6
+ verbose?: boolean;
7
+ };
8
+ export default abstract class SessionManagerAbstract {
9
+ readonly options: OptionsType;
10
+ protected lastProgressDate: number | undefined;
11
+ protected lastProgressStepDescription: string | null | undefined;
12
+ constructor(options: OptionsType);
13
+ protected checkProgress(description: string | null | undefined): boolean;
14
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class SessionManagerAbstract {
4
+ constructor(options) {
5
+ this.options = options;
6
+ }
7
+ checkProgress(description) {
8
+ const progressInterval = this.options.progressInterval;
9
+ if (progressInterval) {
10
+ const skip = this.lastProgressDate &&
11
+ description === this.lastProgressStepDescription &&
12
+ Date.now() - this.lastProgressDate < progressInterval;
13
+ if (skip)
14
+ return false;
15
+ this.lastProgressDate = Date.now();
16
+ this.lastProgressStepDescription = description;
17
+ }
18
+ return true;
19
+ }
20
+ }
21
+ 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
+ step: {
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,
@@ -169,14 +171,20 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
169
171
  basePath: path,
170
172
  },
171
173
  targetPath: outPath,
174
+ skipNotFoundError: true,
172
175
  concurrency: this.config.fileCopyConcurrency,
173
176
  onPath: async ({ entryPath }) => {
174
177
  currentFiles++;
175
178
  await data.onProgress({
176
- total,
177
- current: currentFiles,
178
- percent: (0, math_util_1.progressPercent)(total, currentFiles),
179
- step: entryPath,
179
+ step: {
180
+ description: "Copying file",
181
+ item: entryPath,
182
+ },
183
+ stats: {
184
+ total,
185
+ current: currentFiles,
186
+ percent: (0, math_util_1.progressPercent)(total, currentFiles),
187
+ },
180
188
  });
181
189
  },
182
190
  });
@@ -200,14 +208,17 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
200
208
  let totalFiles = 0;
201
209
  let currentFiles = 0;
202
210
  await (0, fs_util_1.forEachFile)(targetPath, () => totalFiles++, true);
203
- const incrementProgress = async (step = "") => {
211
+ const incrementProgress = async (description, item, count = true) => {
204
212
  await data.onProgress({
205
- total: totalFiles,
206
- current: Math.max(currentFiles, 0),
207
- percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
208
- step,
213
+ stats: {
214
+ total: totalFiles,
215
+ current: Math.max(currentFiles, 0),
216
+ percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
217
+ },
218
+ step: { description, item },
209
219
  });
210
- currentFiles++;
220
+ if (count)
221
+ currentFiles++;
211
222
  };
212
223
  // Bundle
213
224
  const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
@@ -236,9 +247,7 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
236
247
  },
237
248
  targetPath: restorePath,
238
249
  concurrency: this.config.fileCopyConcurrency,
239
- onPath: async ({ entryPath }) => {
240
- await incrementProgress(entryPath);
241
- },
250
+ onProgress: async (progress) => await incrementProgress(progress.type === "end" ? "Files copied" : "Copying file", progress.path, !progress.type),
242
251
  });
243
252
  }
244
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
+ step: {
112
+ description: "Copying file",
113
+ item: path,
114
+ },
115
+ stats: {
116
+ current,
117
+ percent: (0, math_util_1.progressPercent)(total, current),
118
+ total,
119
+ },
115
120
  });
116
121
  }
117
122
  };
@@ -15,6 +15,7 @@ const path_1 = require("path");
15
15
  exports.sqlDumpTaskDefinition = {
16
16
  type: "object",
17
17
  required: ["password", "hostname", "username", "database"],
18
+ additionalProperties: false,
18
19
  properties: {
19
20
  password: {
20
21
  anyOf: [
@@ -117,24 +118,39 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
117
118
  await (0, promises_1.mkdir)(outputPath, { recursive: true });
118
119
  if (!this.config.oneFileByTable) {
119
120
  const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ database: this.config.database }));
121
+ data.onProgress({
122
+ step: {
123
+ description: "Exporting",
124
+ },
125
+ });
120
126
  await this.onExportTables(tableNames, outPath);
121
127
  }
122
128
  else {
123
129
  let current = 0;
124
130
  for (const tableName of tableNames) {
125
131
  data.onProgress({
126
- total: tableNames.length,
127
- current: current,
128
- percent: (0, math_util_1.progressPercent)(tableNames.length, current),
129
- step: tableName,
132
+ step: {
133
+ description: "Exporting",
134
+ item: tableName,
135
+ },
136
+ stats: {
137
+ total: tableNames.length,
138
+ current: current,
139
+ percent: (0, math_util_1.progressPercent)(tableNames.length, current),
140
+ },
130
141
  });
131
- current++;
132
142
  const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ table: tableName }));
133
143
  await this.onExportTables([tableName], outPath);
144
+ current++;
134
145
  }
135
146
  }
136
147
  if (this.config.storedPrograms) {
137
148
  const outPath = (0, path_1.join)(outputPath, "stored-programs.sql");
149
+ data.onProgress({
150
+ step: {
151
+ description: "Exporting storaged programs",
152
+ },
153
+ });
138
154
  await this.onExportStoredPrograms(outPath);
139
155
  }
140
156
  }
@@ -183,13 +199,18 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
183
199
  for (const item of items) {
184
200
  const path = (0, path_1.join)(restorePath, item.fileName);
185
201
  data.onProgress({
186
- total: items.length,
187
- current: current,
188
- percent: (0, math_util_1.progressPercent)(items.length, current),
189
- step: item.fileName,
202
+ step: {
203
+ description: "Importing",
204
+ item: item.fileName,
205
+ },
206
+ stats: {
207
+ total: items.length,
208
+ current: current,
209
+ percent: (0, math_util_1.progressPercent)(items.length, current),
210
+ },
190
211
  });
191
- current++;
192
212
  await this.onImport(path, database.name);
213
+ current++;
193
214
  }
194
215
  }
195
216
  }
@@ -3,11 +3,16 @@ import { RestoreActionOptionsType } from "../Action/RestoreAction";
3
3
  import { PackageConfigType } from "../Config/PackageConfig";
4
4
  import { SnapshotType } from "../Repository/RepositoryAbstract";
5
5
  export declare type ProgressDataType = {
6
- total?: number;
7
- current?: number;
8
- percent?: number;
9
- step?: string;
10
- stepPercent?: number;
6
+ stats?: {
7
+ total?: number;
8
+ current?: number;
9
+ percent?: number;
10
+ };
11
+ step?: {
12
+ description?: string;
13
+ item?: string;
14
+ percent?: number;
15
+ };
11
16
  };
12
17
  export declare type BackupDataType = {
13
18
  onProgress: (data: ProgressDataType) => Promise<void>;
package/cli.js CHANGED
@@ -81,7 +81,7 @@ program.usage("dtt");
81
81
  program.option("-v,--verbose", "Verbose", (_, previous) => previous + 1, 0);
82
82
  program.option("-c,--config <path>", "Config path", process.env["DATATRUCK_CONFIG"] ?? (cwd.endsWith(path_1.sep) ? cwd : `${cwd}${path_1.sep}`));
83
83
  program.option("--progress <value>", "Progress type (auto, plain, tty)", "auto");
84
- program.option("--progress-interval <ms>", "Progress interval");
84
+ program.option("--progress-interval <ms>", "Progress interval", Number, 1000);
85
85
  program.option("-o,--output-format <format>", "Output format (json, pjson, yaml, table, custom=$, tpl=name)", "table");
86
86
  makeCommand(CommandFactory_1.CommandEnum.config).alias("c");
87
87
  makeCommand(CommandFactory_1.CommandEnum.init).alias("i");
@@ -475,6 +475,9 @@
475
475
  "include"
476
476
  ],
477
477
  "properties": {
478
+ "name": {
479
+ "type": "string"
480
+ },
478
481
  "include": {
479
482
  "$ref": "#/definitions/stringlist-util"
480
483
  },
@@ -683,6 +686,7 @@
683
686
  "username",
684
687
  "database"
685
688
  ],
689
+ "additionalProperties": false,
686
690
  "properties": {
687
691
  "password": {
688
692
  "anyOf": [