@datatruck/cli 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/Action/BackupAction.d.ts +69 -34
  2. package/Action/BackupAction.js +284 -244
  3. package/Action/CleanCacheAction.d.ts +8 -4
  4. package/Action/CleanCacheAction.js +8 -5
  5. package/Action/ConfigAction.d.ts +12 -5
  6. package/Action/ConfigAction.js +14 -18
  7. package/Action/CopyAction.d.ts +49 -0
  8. package/Action/CopyAction.js +144 -0
  9. package/Action/InitAction.d.ts +3 -3
  10. package/Action/InitAction.js +9 -9
  11. package/Action/PruneAction.d.ts +9 -9
  12. package/Action/PruneAction.js +39 -23
  13. package/Action/RestoreAction.d.ts +48 -23
  14. package/Action/RestoreAction.js +158 -195
  15. package/Action/SnapshotsAction.d.ts +8 -8
  16. package/Action/SnapshotsAction.js +8 -8
  17. package/CHANGELOG.md +495 -0
  18. package/Command/BackupCommand.d.ts +6 -4
  19. package/Command/BackupCommand.js +9 -26
  20. package/Command/CleanCacheCommand.d.ts +4 -4
  21. package/Command/CleanCacheCommand.js +26 -5
  22. package/Command/CommandAbstract.d.ts +10 -7
  23. package/Command/CommandAbstract.js +4 -1
  24. package/Command/ConfigCommand.d.ts +6 -9
  25. package/Command/ConfigCommand.js +13 -8
  26. package/Command/CopyCommand.d.ts +15 -0
  27. package/Command/CopyCommand.js +61 -0
  28. package/Command/InitCommand.d.ts +4 -4
  29. package/Command/InitCommand.js +11 -15
  30. package/Command/PruneCommand.d.ts +3 -3
  31. package/Command/PruneCommand.js +13 -12
  32. package/Command/RestoreCommand.js +9 -17
  33. package/Command/SnapshotsCommand.d.ts +4 -4
  34. package/Command/SnapshotsCommand.js +16 -15
  35. package/Command/StartServerCommand.d.ts +3 -3
  36. package/Config/Config.d.ts +9 -0
  37. package/Config/Config.js +17 -0
  38. package/Config/PrunePolicyConfig.d.ts +2 -2
  39. package/Factory/CommandFactory.d.ts +27 -34
  40. package/Factory/CommandFactory.js +27 -54
  41. package/Factory/RepositoryFactory.d.ts +1 -1
  42. package/Factory/RepositoryFactory.js +3 -3
  43. package/Factory/TaskFactory.d.ts +1 -1
  44. package/Factory/TaskFactory.js +3 -3
  45. package/Repository/DatatruckRepository.d.ts +9 -8
  46. package/Repository/DatatruckRepository.js +42 -25
  47. package/Repository/GitRepository.d.ts +9 -8
  48. package/Repository/GitRepository.js +22 -25
  49. package/Repository/RepositoryAbstract.d.ts +39 -37
  50. package/Repository/RepositoryAbstract.js +4 -5
  51. package/Repository/ResticRepository.d.ts +9 -8
  52. package/Repository/ResticRepository.js +30 -28
  53. package/Task/GitTask.d.ts +6 -7
  54. package/Task/GitTask.js +24 -30
  55. package/Task/MariadbTask.d.ts +4 -5
  56. package/Task/MariadbTask.js +26 -32
  57. package/Task/MssqlTask.d.ts +5 -3
  58. package/Task/MssqlTask.js +11 -12
  59. package/Task/MysqlDumpTask.d.ts +10 -3
  60. package/Task/MysqlDumpTask.js +107 -31
  61. package/Task/ScriptTask.d.ts +23 -18
  62. package/Task/ScriptTask.js +34 -24
  63. package/Task/SqlDumpTaskAbstract.d.ts +8 -3
  64. package/Task/SqlDumpTaskAbstract.js +31 -19
  65. package/Task/TaskAbstract.d.ts +24 -25
  66. package/Task/TaskAbstract.js +6 -10
  67. package/cli.js +13 -5
  68. package/config.schema.json +86 -1
  69. package/package.json +4 -5
  70. package/utils/DataFormat.d.ts +23 -12
  71. package/utils/DataFormat.js +36 -14
  72. package/utils/cli.d.ts +2 -9
  73. package/utils/cli.js +9 -52
  74. package/utils/datatruck/client.d.ts +2 -0
  75. package/utils/datatruck/client.js +3 -0
  76. package/utils/datatruck/config.d.ts +2 -0
  77. package/utils/datatruck/config.js +18 -3
  78. package/utils/datatruck/paths.d.ts +5 -9
  79. package/utils/datatruck/paths.js +2 -2
  80. package/utils/datatruck/snapshot.d.ts +2 -2
  81. package/utils/date.d.ts +7 -3
  82. package/utils/date.js +22 -14
  83. package/utils/fs.d.ts +16 -11
  84. package/utils/fs.js +81 -48
  85. package/utils/list.d.ts +64 -0
  86. package/utils/list.js +145 -0
  87. package/utils/mysql.d.ts +2 -0
  88. package/utils/mysql.js +21 -2
  89. package/utils/process.d.ts +1 -0
  90. package/utils/process.js +24 -31
  91. package/utils/progress.d.ts +33 -0
  92. package/utils/progress.js +113 -0
  93. package/utils/steps.d.ts +11 -0
  94. package/utils/steps.js +22 -10
  95. package/utils/stream.d.ts +7 -0
  96. package/utils/stream.js +10 -0
  97. package/utils/string.d.ts +0 -1
  98. package/utils/string.js +1 -13
  99. package/utils/tar.d.ts +10 -3
  100. package/utils/tar.js +70 -44
  101. package/utils/temp.d.ts +26 -0
  102. package/utils/temp.js +133 -0
  103. package/utils/virtual-fs.d.ts +6 -2
  104. package/utils/virtual-fs.js +6 -0
  105. package/Action/BackupSessionsAction.d.ts +0 -13
  106. package/Action/BackupSessionsAction.js +0 -18
  107. package/Action/RestoreSessionsAction.d.ts +0 -13
  108. package/Action/RestoreSessionsAction.js +0 -18
  109. package/Command/BackupSessionsCommand.d.ts +0 -12
  110. package/Command/BackupSessionsCommand.js +0 -92
  111. package/Command/RestoreSessionsCommand.d.ts +0 -12
  112. package/Command/RestoreSessionsCommand.js +0 -91
  113. package/Decorator/EntityDecorator.d.ts +0 -11
  114. package/Decorator/EntityDecorator.js +0 -17
  115. package/Entity/BackupSessionEntity.d.ts +0 -6
  116. package/Entity/BackupSessionEntity.js +0 -25
  117. package/Entity/BackupSessionRepositoryEntity.d.ts +0 -6
  118. package/Entity/BackupSessionRepositoryEntity.js +0 -25
  119. package/Entity/BackupSessionTaskEntity.d.ts +0 -5
  120. package/Entity/BackupSessionTaskEntity.js +0 -24
  121. package/Entity/CrudEntityAbstract.d.ts +0 -5
  122. package/Entity/CrudEntityAbstract.js +0 -9
  123. package/Entity/RestoreSessionEntity.d.ts +0 -5
  124. package/Entity/RestoreSessionEntity.js +0 -24
  125. package/Entity/RestoreSessionRepositoryEntity.d.ts +0 -6
  126. package/Entity/RestoreSessionRepositoryEntity.js +0 -25
  127. package/Entity/RestoreSessionTaskEntity.d.ts +0 -5
  128. package/Entity/RestoreSessionTaskEntity.js +0 -24
  129. package/Entity/StateEntityAbstract.d.ts +0 -9
  130. package/Entity/StateEntityAbstract.js +0 -12
  131. package/Factory/EntityFactory.d.ts +0 -6
  132. package/Factory/EntityFactory.js +0 -40
  133. package/SessionDriver/ConsoleSessionDriver.d.ts +0 -42
  134. package/SessionDriver/ConsoleSessionDriver.js +0 -208
  135. package/SessionDriver/SessionDriverAbstract.d.ts +0 -77
  136. package/SessionDriver/SessionDriverAbstract.js +0 -28
  137. package/SessionDriver/SqliteSessionDriver.d.ts +0 -20
  138. package/SessionDriver/SqliteSessionDriver.js +0 -173
  139. package/SessionManager/BackupSessionManager.d.ts +0 -45
  140. package/SessionManager/BackupSessionManager.js +0 -218
  141. package/SessionManager/RestoreSessionManager.d.ts +0 -47
  142. package/SessionManager/RestoreSessionManager.js +0 -218
  143. package/SessionManager/SessionManagerAbstract.d.ts +0 -18
  144. package/SessionManager/SessionManagerAbstract.js +0 -36
  145. package/migrations/001-initial.sql +0 -98
  146. package/utils/entity.d.ts +0 -4
  147. package/utils/entity.js +0 -10
@@ -1,286 +1,326 @@
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.BackupAction = void 0;
4
- const AppError_1 = require("../Error/AppError");
5
7
  const RepositoryFactory_1 = require("../Factory/RepositoryFactory");
6
8
  const TaskFactory_1 = require("../Factory/TaskFactory");
9
+ const DataFormat_1 = require("../utils/DataFormat");
10
+ const cli_1 = require("../utils/cli");
7
11
  const config_1 = require("../utils/datatruck/config");
12
+ const date_1 = require("../utils/date");
8
13
  const fs_1 = require("../utils/fs");
14
+ const list_1 = require("../utils/list");
15
+ const progress_1 = require("../utils/progress");
16
+ const steps_1 = require("../utils/steps");
17
+ const temp_1 = require("../utils/temp");
18
+ const assert_1 = require("assert");
19
+ const chalk_1 = __importDefault(require("chalk"));
9
20
  const crypto_1 = require("crypto");
10
21
  class BackupAction {
11
22
  config;
12
23
  options;
13
- taskErrors = {};
14
- repoErrors = {};
24
+ pm;
15
25
  constructor(config, options = {}) {
16
26
  this.config = config;
17
27
  this.options = options;
28
+ this.pm = new progress_1.ProgressManager({
29
+ verbose: options.verbose,
30
+ tty: options.tty,
31
+ enabled: options.progress,
32
+ interval: options.progressInterval,
33
+ });
18
34
  }
19
- async init(session) {
20
- const snapshot = {
35
+ prepareSnapshot() {
36
+ return {
21
37
  id: (0, crypto_1.randomUUID)().replaceAll("-", ""),
22
38
  date: this.options.date ?? new Date().toISOString(),
23
39
  };
24
- await session.initDrivers();
25
- let packages = (0, config_1.filterPackages)(this.config, {
40
+ }
41
+ getPackages(snapshot) {
42
+ const packages = (0, config_1.filterPackages)(this.config, {
26
43
  packageNames: this.options.packageNames,
27
44
  packageTaskNames: this.options.packageTaskNames,
28
45
  repositoryNames: this.options.repositoryNames,
29
46
  repositoryTypes: this.options.repositoryTypes,
30
47
  sourceAction: "backup",
31
48
  });
32
- packages = (0, config_1.resolvePackages)(packages, {
49
+ return (0, config_1.resolvePackages)(packages, {
33
50
  snapshotId: snapshot.id,
34
51
  snapshotDate: snapshot.date,
35
52
  action: "backup",
36
53
  });
37
- for (const pkg of packages) {
38
- const sessionId = await session.init({
39
- snapshotId: snapshot.id,
40
- packageName: pkg.name,
41
- tags: this.options.tags?.join(",") ?? "",
42
- });
43
- if (pkg.task)
44
- await session.initTask({
45
- sessionId: sessionId,
46
- taskName: pkg.task.name,
47
- });
48
- for (const repositoryName of pkg.repositoryNames ?? []) {
49
- const repo = (0, config_1.findRepositoryOrFail)(this.config, repositoryName);
50
- await session.initRepository({
51
- sessionId: sessionId,
52
- repositoryName: repositoryName,
53
- repositoryType: repo.type,
54
- });
55
- }
56
- }
57
- return [snapshot, packages];
58
54
  }
59
- async task(session, pkg, task, snapshot, targetPath) {
60
- const taskId = session.findTaskId({
61
- packageName: pkg.name,
62
- taskName: pkg.task.name,
63
- });
64
- await session.startTask({
65
- id: taskId,
66
- });
67
- const key = `${pkg.name}`;
68
- let error;
69
- if (this.taskErrors[key]?.length) {
70
- error = AppError_1.AppError.create("Previous task failed", this.taskErrors[key]);
71
- }
72
- else {
73
- try {
74
- await task.onBackup({
75
- package: pkg,
76
- options: this.options,
77
- snapshot,
78
- targetPath,
79
- onProgress: async (progress) => {
80
- await session.progressTask({
81
- id: taskId,
82
- progress,
83
- });
84
- },
85
- });
86
- }
87
- catch (_) {
88
- if (!this.taskErrors[key])
89
- this.taskErrors[key] = [];
90
- this.taskErrors[key].push((error = _));
91
- }
55
+ getRepositoryNames(repositoryNames) {
56
+ const items = [];
57
+ const exclude = new Set();
58
+ for (const name of repositoryNames) {
59
+ const repo = (0, config_1.findRepositoryOrFail)(this.config, name);
60
+ const mirrors = (repo.mirrorRepoNames || []).filter((mirror) => !exclude.has(mirror));
61
+ for (const mirror of mirrors)
62
+ exclude.add(mirror);
63
+ items.push({ name, mirrors });
92
64
  }
93
- await session.endTask({
94
- id: taskId,
95
- error: error?.stack,
96
- });
97
- return {
98
- error: error ? false : true,
99
- tmpDirs: task.tmpDirs,
100
- };
65
+ return items.filter((item) => !exclude.has(item.name));
101
66
  }
102
- async backup(session, pkg, repo, snapshot, targetPath) {
103
- const repositoryId = session.findRepositoryId({
104
- packageName: pkg.name,
105
- repositoryName: repo.name,
67
+ async backup(data) {
68
+ const repoConfig = (0, config_1.findRepositoryOrFail)(this.config, data.repositoryName);
69
+ const pkg = { ...data.pkg, path: data.snapshotPath ?? data.pkg.path };
70
+ (0, assert_1.ok)(pkg.path);
71
+ await (0, fs_1.ensureExistsDir)(pkg.path);
72
+ const repo = (0, RepositoryFactory_1.createRepo)(repoConfig);
73
+ if (this.config.minFreeDiskSpace)
74
+ await repo.ensureFreeDiskSpace(repoConfig.config, this.config.minFreeDiskSpace);
75
+ const packageConfig = pkg.repositoryConfigs?.find((config) => config.type === repoConfig.type &&
76
+ (!config.names || config.names.includes(repoConfig.name)))?.config;
77
+ await repo.backup({
78
+ options: this.options,
79
+ snapshot: data.snapshot,
80
+ package: pkg,
81
+ packageConfig,
82
+ onProgress: data.onProgress,
106
83
  });
107
- await session.startRepository({
108
- id: repositoryId,
109
- });
110
- let error;
111
- let repoInstance;
112
- if (this.taskErrors[pkg.name]?.length) {
113
- error = AppError_1.AppError.create("Task failed", this.taskErrors[pkg.name]);
114
- }
115
- else {
116
- try {
117
- repoInstance = (0, RepositoryFactory_1.RepositoryFactory)(repo);
118
- await repoInstance.onBackup({
119
- package: pkg,
120
- targetPath,
121
- packageConfig: pkg.repositoryConfigs?.find((config) => config.type === repo.type &&
122
- (!config.names || config.names.includes(repo.name)))?.config,
123
- options: this.options,
124
- snapshot: snapshot,
125
- onProgress: async (progress) => {
126
- await session.progressRepository({
127
- id: repositoryId,
128
- progress,
129
- });
130
- },
131
- });
132
- }
133
- catch (_) {
134
- if (!this.repoErrors[pkg.name])
135
- this.repoErrors[pkg.name] = [];
136
- this.repoErrors[pkg.name].push((error = _));
137
- }
138
- }
139
- await session.endRepository({
140
- id: repositoryId,
141
- error: error?.stack,
84
+ }
85
+ async copy(data) {
86
+ const repoConfig = (0, config_1.findRepositoryOrFail)(this.config, data.repositoryName);
87
+ const mirrorRepoConfig = (0, config_1.findRepositoryOrFail)(this.config, data.mirrorRepositoryName);
88
+ const repo = (0, RepositoryFactory_1.createRepo)(repoConfig);
89
+ const mirrorRepo = (0, RepositoryFactory_1.createRepo)(mirrorRepoConfig);
90
+ if (this.config.minFreeDiskSpace)
91
+ await mirrorRepo.ensureFreeDiskSpace(mirrorRepoConfig.config, this.config.minFreeDiskSpace);
92
+ await repo.copy({
93
+ options: this.options,
94
+ package: data.pkg,
95
+ snapshot: data.snapshot,
96
+ mirrorRepositoryConfig: mirrorRepoConfig.config,
97
+ onProgress: data.onProgress,
142
98
  });
143
- return {
144
- error: error ? false : true,
145
- tmpDirs: repoInstance?.tmpDirs ?? [],
99
+ }
100
+ dataFormat(result, options = {}) {
101
+ const renderTitle = (item, color) => {
102
+ let title = item.key.slice(0, 1).toUpperCase() + item.key.slice(1);
103
+ return item.key === "backup" && color ? chalk_1.default.cyan(title) : title;
146
104
  };
105
+ const renderData = (item, color) => {
106
+ const g = (v) => (color ? `${chalk_1.default.gray(`(${v})`)}` : `(${v})`);
107
+ return item.key === "snapshot"
108
+ ? item.data.id
109
+ : item.key === "task"
110
+ ? `${item.data.packageName} ${g(item.data.taskName)}`
111
+ : item.key === "backup"
112
+ ? `${item.data.packageName} ${g(item.data.repositoryName)}`
113
+ : item.key === "copy"
114
+ ? `${item.data.packageName} ${g(item.data.mirrorRepositoryName)}`
115
+ : item.key === "summary"
116
+ ? `Errors: ${item.data.errors}`
117
+ : item.key === "report"
118
+ ? item.data.type
119
+ : "";
120
+ };
121
+ return new DataFormat_1.DataFormat({
122
+ streams: options.streams,
123
+ json: result,
124
+ list: () => result
125
+ .filter((item) => item.key !== "cleanup")
126
+ .map((item) => {
127
+ const icon = (0, cli_1.resultColumn)(item.error, false);
128
+ const title = renderTitle(item);
129
+ const data = renderData(item, false);
130
+ return `${icon} ${title}: ${data}`;
131
+ }),
132
+ table: {
133
+ headers: [
134
+ { value: "", width: 3 },
135
+ { value: "Title", width: 15 },
136
+ { value: "Data", align: "left" },
137
+ { value: "Duration", width: 10 },
138
+ { value: "Error", width: 50 },
139
+ ],
140
+ rows: () => result
141
+ .filter((item) => item.key !== "cleanup")
142
+ .map((item) => [
143
+ (0, cli_1.resultColumn)(item.error),
144
+ renderTitle(item, true),
145
+ renderData(item, true),
146
+ (0, date_1.duration)(item.elapsed),
147
+ (0, cli_1.errorColumn)(item.error, options.verbose),
148
+ ]),
149
+ },
150
+ });
147
151
  }
148
- async copyBackup(session, pkg, repo, mirrorRepo, snapshot) {
149
- const repositoryId = session.findRepositoryId({
150
- packageName: pkg.name,
151
- repositoryName: mirrorRepo.name,
152
+ async exec() {
153
+ const { options } = this;
154
+ const pm = new progress_1.ProgressManager({
155
+ verbose: options.verbose,
156
+ tty: options.tty,
157
+ enabled: options.progress,
158
+ interval: options.progressInterval,
152
159
  });
153
- await session.startRepository({
154
- id: repositoryId,
160
+ const l = new list_1.Listr3({
161
+ streams: this.options.streams,
162
+ progressManager: pm,
155
163
  });
156
- let error;
157
- let repoInstance;
158
- if (this.taskErrors[pkg.name]?.length) {
159
- error = AppError_1.AppError.create("Task failed", this.taskErrors[pkg.name]);
160
- }
161
- else {
162
- try {
163
- repoInstance = (0, RepositoryFactory_1.RepositoryFactory)(repo);
164
- await repoInstance.onCopyBackup({
165
- options: this.options,
166
- package: pkg,
167
- snapshot,
168
- mirrorRepositoryConfig: mirrorRepo.config,
169
- onProgress: async (progress) => {
170
- await session.progressRepository({
171
- id: repositoryId,
172
- progress,
164
+ return l
165
+ .add(l.$tasks({
166
+ key: "snapshot",
167
+ data: { id: "" },
168
+ exitOnError: false,
169
+ title: {
170
+ initial: "Prepare snapshots",
171
+ started: "Preparing snapshots",
172
+ failed: "Snapshots prepare failed",
173
+ },
174
+ run: async (task, data) => {
175
+ const { minFreeDiskSpace } = this.config;
176
+ if (minFreeDiskSpace)
177
+ await (0, temp_1.ensureFreeDiskTempSpace)(minFreeDiskSpace);
178
+ const snapshot = this.prepareSnapshot();
179
+ const packages = this.getPackages(snapshot);
180
+ const snapshotId = (data.id = snapshot.id.slice(0, 8));
181
+ task.title = `Snapshots prepared: ${snapshotId} (${packages.length} packages)`;
182
+ return packages.flatMap((pkg) => {
183
+ let taskResult = {};
184
+ const gc = new temp_1.GargabeCollector();
185
+ const repositories = this.getRepositoryNames(pkg.repositoryNames ?? []);
186
+ const mirrorRepositories = repositories
187
+ .filter((r) => r.mirrors.length)
188
+ .flatMap(({ name, mirrors }) => mirrors.map((mirror) => ({ name, mirror })));
189
+ return l.$tasks(!!pkg.task &&
190
+ l.$task({
191
+ key: "task",
192
+ keyIndex: pkg.name,
193
+ data: { taskName: pkg.task.name, packageName: pkg.name },
194
+ title: {
195
+ initial: `Execute task: ${pkg.task?.name}`,
196
+ started: `Executing task: ${pkg.task?.name}`,
197
+ failed: `Task execute failed: ${pkg.task?.name}`,
198
+ completed: `Task executed: ${pkg.task?.name}`,
199
+ },
200
+ exitOnError: false,
201
+ runWrapper: gc.cleanupIfFail.bind(gc),
202
+ run: async (task) => {
203
+ taskResult = await (0, TaskFactory_1.createTask)(pkg.task).backup({
204
+ options,
205
+ package: pkg,
206
+ snapshot,
207
+ onProgress: (p) => pm.update(p, (t) => (task.output = t)),
208
+ });
209
+ },
210
+ }), ...repositories.map(({ name: repositoryName }) => l.$task({
211
+ key: "backup",
212
+ keyIndex: [pkg.name, repositoryName],
213
+ data: {
214
+ packageName: pkg.name,
215
+ repositoryName: repositoryName,
216
+ },
217
+ title: {
218
+ initial: `Create backup: ${repositoryName}`,
219
+ started: `Creating backup: ${repositoryName}`,
220
+ completed: `Backup created: ${repositoryName}`,
221
+ failed: `Backup create failed: ${repositoryName}`,
222
+ },
223
+ exitOnError: false,
224
+ runWrapper: gc.cleanupOnFinish.bind(gc),
225
+ run: async (task) => {
226
+ const taskSummary = pkg.task
227
+ ? l.result("task", pkg.name)
228
+ : undefined;
229
+ if (taskSummary?.error)
230
+ throw new Error(`Task failed`);
231
+ await this.backup({
232
+ pkg,
233
+ repositoryName,
234
+ snapshot,
235
+ snapshotPath: taskResult?.snapshotPath,
236
+ onProgress: (p) => this.pm.update(p, (t) => (task.output = t)),
237
+ });
238
+ },
239
+ })), l.$task({
240
+ key: "cleanup",
241
+ keyIndex: pkg.name,
242
+ data: {},
243
+ title: {
244
+ initial: "Clean task files",
245
+ started: "Cleaning task files",
246
+ completed: "Task files cleaned",
247
+ failed: "Task files clean failed",
248
+ },
249
+ exitOnError: false,
250
+ enabled: gc.pending,
251
+ run: () => gc.cleanup(),
252
+ }), ...mirrorRepositories.map(({ name, mirror }) => l.$task({
253
+ key: "copy",
254
+ keyIndex: [pkg.name, mirror],
255
+ data: {
256
+ packageName: pkg.name,
257
+ repositoryName: name,
258
+ mirrorRepositoryName: mirror,
259
+ },
260
+ title: {
261
+ initial: `Copy snapshot: ${mirror}`,
262
+ started: `Copying snapshot: ${mirror}`,
263
+ completed: `Snapshot copied: ${mirror}`,
264
+ failed: `Snapshot copy failed: ${mirror}`,
265
+ },
266
+ exitOnError: false,
267
+ runWrapper: gc.cleanup.bind(gc),
268
+ run: async (task) => {
269
+ const backupSummary = l.result("backup", [
270
+ pkg.name,
271
+ name,
272
+ ]);
273
+ if (backupSummary.error)
274
+ throw new Error(`Backup failed`);
275
+ await this.copy({
276
+ repositoryName: name,
277
+ mirrorRepositoryName: mirror,
278
+ pkg,
279
+ snapshot,
280
+ onProgress: (p) => pm.update(p, (t) => (task.output = t)),
281
+ });
282
+ },
283
+ })), ...(this.config.reports || []).map((report, index) => {
284
+ const reportIndex = index + 1;
285
+ return l.$task({
286
+ title: {
287
+ initial: `Send report ${reportIndex}`,
288
+ started: `Sending report ${reportIndex}`,
289
+ completed: `Report sent: ${reportIndex}`,
290
+ failed: `Report send failed: ${reportIndex}`,
291
+ },
292
+ key: "report",
293
+ keyIndex: index,
294
+ data: { type: report.run.type },
295
+ exitOnError: false,
296
+ run: async (task) => {
297
+ const result = l
298
+ .getResult()
299
+ .filter((r) => r.key !== "report");
300
+ const success = result.every((r) => !r.error);
301
+ const enabled = !report.when ||
302
+ (report.when === "success" && success) ||
303
+ (report.when === "error" && !success);
304
+ if (!enabled)
305
+ return task.skip(`Report send skipped: ${reportIndex}`);
306
+ const text = this.dataFormat(result).format(report.format ?? "list");
307
+ await (0, steps_1.runSteps)(report.run, {
308
+ verbose: this.options.verbose,
309
+ process: { vars: { DTT_REPORT: text } },
310
+ telegram: { vars: { TEXT: text } },
311
+ node: {
312
+ vars: {
313
+ dtt: { report: text, result },
314
+ },
315
+ },
316
+ });
317
+ },
173
318
  });
174
- },
175
- });
176
- }
177
- catch (_) {
178
- if (!this.repoErrors[pkg.name])
179
- this.repoErrors[pkg.name] = [];
180
- this.repoErrors[pkg.name].push((error = _));
181
- }
182
- }
183
- await session.endRepository({
184
- id: repositoryId,
185
- error: error?.stack,
186
- });
187
- return {
188
- error: error ? false : true,
189
- tmpDirs: repoInstance?.tmpDirs ?? [],
190
- };
191
- }
192
- getError(pkg) {
193
- const taskErrors = this.taskErrors[pkg.name] || [];
194
- const repoErrors = this.repoErrors[pkg.name] || [];
195
- const errors = [...taskErrors, ...repoErrors];
196
- if (!errors.length)
197
- return;
198
- return AppError_1.AppError.create(taskErrors.length && repoErrors.length
199
- ? "Task and repository failed"
200
- : taskErrors.length && !repoErrors.length
201
- ? "Task failed"
202
- : "Repository failed", errors);
203
- }
204
- splitRepositories(repositoryNames) {
205
- const mirrorRepoMap = {};
206
- const allMirrorRepoNames = [];
207
- const repoNames = repositoryNames ?? [];
208
- for (const repoName of repoNames) {
209
- const repo = (0, config_1.findRepositoryOrFail)(this.config, repoName);
210
- if (repo.mirrorRepoNames)
211
- mirrorRepoMap[repoName] = repo.mirrorRepoNames.filter((mirrorRepoName) => {
212
- allMirrorRepoNames.push(mirrorRepoName);
213
- return repoNames.includes(mirrorRepoName);
319
+ }));
214
320
  });
215
- }
216
- return {
217
- repoNames: repoNames.filter((v) => !allMirrorRepoNames.includes(v)),
218
- mirrors: repoNames.flatMap((sourceName) => {
219
- const mirrorNames = mirrorRepoMap[sourceName] || [];
220
- return mirrorNames.map((name) => ({
221
- sourceName,
222
- name,
223
- }));
224
- }),
225
- };
226
- }
227
- async exec(session) {
228
- const [snapshot, packages] = await this.init(session);
229
- const errors = [];
230
- for (const pkg of packages) {
231
- const id = session.findId({
232
- packageName: pkg.name,
233
- });
234
- await session.start({
235
- id,
236
- });
237
- let targetPath;
238
- let taskTmpDirs = [];
239
- if (pkg.task) {
240
- const taskInstance = (0, TaskFactory_1.TaskFactory)(pkg.task);
241
- const result = await taskInstance.onBeforeBackup({
242
- options: this.options,
243
- package: pkg,
244
- snapshot,
245
- });
246
- const taskResult = await this.task(session, pkg, taskInstance, snapshot, (targetPath = result?.targetPath));
247
- taskTmpDirs.push(...taskResult.tmpDirs);
248
- }
249
- const { repoNames, mirrors } = this.splitRepositories(pkg.repositoryNames ?? []);
250
- for (const repoName of repoNames) {
251
- const repo = (0, config_1.findRepositoryOrFail)(this.config, repoName);
252
- const { tmpDirs } = await this.backup(session, pkg, repo, snapshot, targetPath);
253
- if (!this.options.verbose)
254
- await (0, fs_1.rmTmpDir)(tmpDirs);
255
- }
256
- if (!this.options.verbose) {
257
- await (0, fs_1.rmTmpDir)(taskTmpDirs);
258
- if (pkg.path && (0, fs_1.isTmpDir)(pkg.path)) {
259
- await (0, fs_1.rmTmpDir)(pkg.path);
260
- }
261
- }
262
- for (const mirror of mirrors) {
263
- const repo = (0, config_1.findRepositoryOrFail)(this.config, mirror.sourceName);
264
- const mirrorRepo = (0, config_1.findRepositoryOrFail)(this.config, mirror.name);
265
- const { tmpDirs } = await this.copyBackup(session, pkg, repo, mirrorRepo, snapshot);
266
- if (!this.options.verbose)
267
- await (0, fs_1.rmTmpDir)(tmpDirs);
268
- }
269
- const error = this.getError(pkg);
270
- if (error)
271
- errors.push(error);
272
- await session.end({
273
- id: id,
274
- error: error?.message,
275
- });
276
- }
277
- await session.endDrivers({
278
- snapshotId: snapshot.id.slice(0, 8),
279
- });
280
- return {
281
- total: packages.length,
282
- errors,
283
- };
321
+ },
322
+ }))
323
+ .exec();
284
324
  }
285
325
  }
286
326
  exports.BackupAction = BackupAction;
@@ -1,9 +1,13 @@
1
1
  import { IfRequireKeys } from "../utils/ts";
2
- export type CleanCacheActionOptionsType = {
2
+ export type CleanCacheActionOptions = {
3
3
  verbose?: boolean;
4
4
  };
5
5
  export declare class CleanCacheAction<TRequired extends boolean = true> {
6
- readonly options: IfRequireKeys<TRequired, CleanCacheActionOptionsType>;
7
- constructor(options: IfRequireKeys<TRequired, CleanCacheActionOptionsType>);
8
- exec(): Promise<void>;
6
+ readonly options: IfRequireKeys<TRequired, CleanCacheActionOptions>;
7
+ constructor(options: IfRequireKeys<TRequired, CleanCacheActionOptions>);
8
+ exec(): Promise<{
9
+ errors: never[];
10
+ path: string;
11
+ freedSize: number;
12
+ }>;
9
13
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CleanCacheAction = void 0;
4
4
  const fs_1 = require("../utils/fs");
5
+ const temp_1 = require("../utils/temp");
5
6
  const promises_1 = require("fs/promises");
6
7
  class CleanCacheAction {
7
8
  options;
@@ -9,11 +10,13 @@ class CleanCacheAction {
9
10
  this.options = options;
10
11
  }
11
12
  async exec() {
12
- const path = (0, fs_1.parentTmpDir)();
13
- if (await (0, fs_1.existsDir)(path))
14
- await (0, promises_1.rm)(path, {
15
- recursive: true,
16
- });
13
+ const path = (0, temp_1.parentTmpDir)();
14
+ let freedSize = 0;
15
+ if (await (0, fs_1.existsDir)(path)) {
16
+ freedSize = await (0, fs_1.fastFolderSizeAsync)(path);
17
+ await (0, promises_1.rm)(path, { recursive: true });
18
+ }
19
+ return { errors: [], path, freedSize };
17
20
  }
18
21
  }
19
22
  exports.CleanCacheAction = CleanCacheAction;
@@ -1,17 +1,24 @@
1
- import { GlobalOptionsType } from "../Command/CommandAbstract";
1
+ import { GlobalOptions } from "../Command/CommandAbstract";
2
2
  import type { ConfigType } from "../Config/Config";
3
3
  import { IfRequireKeys } from "../utils/ts";
4
- export type ConfigActionOptionsType = {
4
+ export type ConfigActionOptions = {
5
5
  path: string;
6
6
  verbose?: boolean;
7
7
  };
8
8
  export declare class ConfigAction<TRequired extends boolean = true> {
9
- readonly options: IfRequireKeys<TRequired, ConfigActionOptionsType>;
10
- constructor(options: IfRequireKeys<TRequired, ConfigActionOptionsType>);
9
+ readonly options: IfRequireKeys<TRequired, ConfigActionOptions>;
10
+ constructor(options: IfRequireKeys<TRequired, ConfigActionOptions>);
11
11
  static validate(config: ConfigType): void;
12
12
  static check(config: ConfigType): void;
13
13
  static normalize(config: ConfigType): ConfigType;
14
- static fromGlobalOptions(globalOptions: GlobalOptionsType<true>): Promise<ConfigType>;
14
+ static fromGlobalOptionsWithPath(globalOptions: GlobalOptions<true>): Promise<{
15
+ path: string;
16
+ data: ConfigType;
17
+ } | {
18
+ path: null;
19
+ data: ConfigType;
20
+ }>;
21
+ static fromGlobalOptions(globalOptions: GlobalOptions<true>): Promise<ConfigType>;
15
22
  exec(): Promise<{
16
23
  path: string;
17
24
  data: ConfigType;