@datatruck/cli 0.7.0 → 0.10.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 (44) hide show
  1. package/Action/BackupAction.d.ts +1 -0
  2. package/Action/BackupAction.js +68 -1
  3. package/Action/ConfigAction.js +16 -0
  4. package/Action/RestoreAction.js +1 -0
  5. package/Action/SnapshotsAction.d.ts +1 -0
  6. package/Command/BackupSessionsCommand.js +1 -1
  7. package/Command/ConfigCommand.js +1 -1
  8. package/Command/InitCommand.js +1 -1
  9. package/Command/PruneCommand.js +1 -1
  10. package/Command/RestoreSessionsCommand.js +1 -1
  11. package/Command/SnapshotsCommand.d.ts +1 -0
  12. package/Command/SnapshotsCommand.js +16 -2
  13. package/Config/RepositoryConfig.d.ts +1 -0
  14. package/Config/RepositoryConfig.js +1 -0
  15. package/Factory/CommandFactory.js +2 -2
  16. package/Repository/GitRepository.d.ts +2 -1
  17. package/Repository/GitRepository.js +8 -0
  18. package/Repository/LocalRepository.d.ts +3 -1
  19. package/Repository/LocalRepository.js +28 -1
  20. package/Repository/RepositoryAbstract.d.ts +12 -1
  21. package/Repository/RepositoryAbstract.js +1 -0
  22. package/Repository/ResticRepository.d.ts +4 -3
  23. package/Repository/ResticRepository.js +33 -0
  24. package/Task/MariadbTask.js +1 -1
  25. package/Task/MssqlTask.js +1 -1
  26. package/Task/MysqlDumpTask.d.ts +2 -1
  27. package/Task/MysqlDumpTask.js +31 -1
  28. package/Task/PostgresqlDumpTask.d.ts +2 -1
  29. package/Task/PostgresqlDumpTask.js +4 -1
  30. package/Task/SqlDumpTaskAbstract.d.ts +3 -1
  31. package/Task/SqlDumpTaskAbstract.js +8 -3
  32. package/cli.js +1 -1
  33. package/config.schema.json +6 -0
  34. package/package.json +11 -11
  35. package/util/GitUtil.js +1 -2
  36. package/util/ResticUtil.d.ts +4 -0
  37. package/util/ResticUtil.js +16 -0
  38. package/util/cli-util.js +2 -2
  39. package/util/date-util.d.ts +1 -1
  40. package/util/entity-util.d.ts +1 -1
  41. package/util/fs-util.d.ts +2 -0
  42. package/util/fs-util.js +21 -4
  43. package/util/process-util.d.ts +1 -0
  44. package/CHANGELOG.md +0 -139
@@ -25,6 +25,7 @@ export declare class BackupAction<TRequired extends boolean = true> {
25
25
  protected init(session: BackupSessionManager): Promise<[SnapshotType, PackageConfigType[]]>;
26
26
  protected execTask(session: BackupSessionManager, pkg: PackageConfigType, task: TaskConfigType, snapshot: SnapshotType, targetPath: string | undefined): Promise<boolean>;
27
27
  protected execRepository(session: BackupSessionManager, pkg: PackageConfigType, repo: RepositoryConfigType, snapshot: SnapshotType, targetPath: string | undefined): Promise<boolean>;
28
+ protected execCopyRepository(session: BackupSessionManager, pkg: PackageConfigType, repo: RepositoryConfigType, mirrorRepo: RepositoryConfigType, snapshot: SnapshotType): Promise<boolean>;
28
29
  protected getError(pkg: PackageConfigType): AppError | null;
29
30
  exec(session: BackupSessionManager): Promise<{
30
31
  total: number;
@@ -144,6 +144,50 @@ class BackupAction {
144
144
  });
145
145
  return error ? false : true;
146
146
  }
147
+ async execCopyRepository(session, pkg, repo, mirrorRepo, snapshot) {
148
+ const repositoryId = session.findRepositoryId({
149
+ packageName: pkg.name,
150
+ repositoryName: mirrorRepo.name,
151
+ });
152
+ await session.startRepository({
153
+ id: repositoryId,
154
+ });
155
+ let error;
156
+ if (this.taskErrors[pkg.name]?.length) {
157
+ error = new AppError_1.AppError("Task failed");
158
+ }
159
+ else {
160
+ try {
161
+ const repoInstance = (0, RepositoryFactory_1.RepositoryFactory)(repo);
162
+ await repoInstance.onCopyBackup({
163
+ options: this.options,
164
+ package: pkg,
165
+ snapshot,
166
+ mirrorRepositoryConfig: mirrorRepo.config,
167
+ onProgress: async (data) => {
168
+ await session.progressRepository({
169
+ id: repositoryId,
170
+ progressCurrent: data.current,
171
+ progressPercent: data.percent,
172
+ progressStep: data.step,
173
+ progressStepPercent: data.stepPercent,
174
+ progressTotal: data.total,
175
+ });
176
+ },
177
+ });
178
+ }
179
+ catch (_) {
180
+ if (!this.repoErrors[pkg.name])
181
+ this.repoErrors[pkg.name] = [];
182
+ this.repoErrors[pkg.name].push((error = _));
183
+ }
184
+ }
185
+ await session.endRepository({
186
+ id: repositoryId,
187
+ error: error?.stack,
188
+ });
189
+ return error ? false : true;
190
+ }
147
191
  getError(pkg) {
148
192
  const taskErrors = this.taskErrors[pkg.name]?.length;
149
193
  const repoErrors = this.repoErrors[pkg.name]?.length;
@@ -182,10 +226,33 @@ class BackupAction {
182
226
  });
183
227
  await this.execTask(session, pkg, pkg.task, snapshot, (targetPath = result?.targetPath));
184
228
  }
185
- for (const repoName of pkg.repositoryNames ?? []) {
229
+ const mirrorRepoMap = {};
230
+ const allMirrorRepoNames = [];
231
+ const repoNames = pkg.repositoryNames ?? [];
232
+ for (const repoName of repoNames) {
233
+ const repo = (0, config_util_1.findRepositoryOrFail)(this.config, repoName);
234
+ if (repo.mirrorRepoNames)
235
+ mirrorRepoMap[repoName] = repo.mirrorRepoNames.filter((mirrorRepoName) => {
236
+ allMirrorRepoNames.push(mirrorRepoName);
237
+ return repoNames.includes(mirrorRepoName);
238
+ });
239
+ }
240
+ for (const repoName of repoNames) {
241
+ if (allMirrorRepoNames.includes(repoName))
242
+ continue;
186
243
  const repo = (0, config_util_1.findRepositoryOrFail)(this.config, repoName);
187
244
  await this.execRepository(session, pkg, repo, snapshot, targetPath);
188
245
  }
246
+ for (const repoName of repoNames) {
247
+ const repo = (0, config_util_1.findRepositoryOrFail)(this.config, repoName);
248
+ const mirrorRepoNames = mirrorRepoMap[repoName];
249
+ if (mirrorRepoNames) {
250
+ for (const mirrorRepoName of mirrorRepoNames) {
251
+ const mirrorRepo = (0, config_util_1.findRepositoryOrFail)(this.config, mirrorRepoName);
252
+ await this.execCopyRepository(session, pkg, repo, mirrorRepo, snapshot);
253
+ }
254
+ }
255
+ }
189
256
  const error = this.getError(pkg);
190
257
  if (error)
191
258
  errors++;
@@ -22,11 +22,27 @@ class ConfigAction {
22
22
  }
23
23
  static check(config) {
24
24
  const repositoryNames = [];
25
+ const mirrorRepoNames = [];
26
+ const repos = {};
25
27
  for (const repo of config.repositories) {
28
+ repos[repo.name] = repo;
26
29
  if (repositoryNames.includes(repo.name))
27
30
  throw new AppError_1.AppError(`Duplicated repository name: ${repo.name}`);
28
31
  repositoryNames.push(repo.name);
29
32
  }
33
+ for (const repo of config.repositories) {
34
+ if (repo.mirrorRepoNames) {
35
+ for (const mirrorRepoName of repo.mirrorRepoNames) {
36
+ if (!repos[mirrorRepoName])
37
+ throw new AppError_1.AppError(`Mirror repository name not found: ${mirrorRepoName}`);
38
+ if (repos[mirrorRepoName].type !== repo.type)
39
+ throw new AppError_1.AppError(`Mirror repository type is incompatible: ${mirrorRepoName}`);
40
+ if (mirrorRepoNames.includes(mirrorRepoName))
41
+ throw new AppError_1.AppError(`Mirror repository is already used`);
42
+ mirrorRepoNames.push(mirrorRepoName);
43
+ }
44
+ }
45
+ }
30
46
  const packageNames = [];
31
47
  for (const pkg of config.packages) {
32
48
  if (packageNames.includes(pkg.name))
@@ -60,6 +60,7 @@ class RestoreAction {
60
60
  const snapshots = await repoInstance.onSnapshots({
61
61
  options: {
62
62
  packageNames: this.options.packageNames,
63
+ packageTaskNames: this.options.packageTaskNames,
63
64
  ids: [this.options.snapshotId],
64
65
  tags: this.options.tags,
65
66
  },
@@ -7,6 +7,7 @@ export declare type SnapshotsActionOptionsType = {
7
7
  ids?: string[];
8
8
  repositoryNames?: string[];
9
9
  packageNames?: string[];
10
+ packageTaskNames?: string[];
10
11
  repositoryTypes?: string[];
11
12
  verbose?: boolean;
12
13
  tags?: string[];
@@ -77,7 +77,7 @@ class BackupSessionsCommand extends CommandAbstract_1.CommandAbstract {
77
77
  },
78
78
  });
79
79
  if (this.globalOptions.outputFormat)
80
- console.log(dataFormat.format(this.globalOptions.outputFormat));
80
+ console.info(dataFormat.format(this.globalOptions.outputFormat));
81
81
  return 0;
82
82
  }
83
83
  }
@@ -56,7 +56,7 @@ class ConfigCommand extends CommandAbstract_1.CommandAbstract {
56
56
  },
57
57
  });
58
58
  if (this.globalOptions.outputFormat)
59
- console.log(dataFormat.format(this.globalOptions.outputFormat));
59
+ console.info(dataFormat.format(this.globalOptions.outputFormat));
60
60
  return 0;
61
61
  }
62
62
  }
@@ -56,7 +56,7 @@ class InitCommand extends CommandAbstract_1.CommandAbstract {
56
56
  },
57
57
  });
58
58
  if (this.globalOptions.outputFormat)
59
- console.log(dataFormat.format(this.globalOptions.outputFormat));
59
+ console.info(dataFormat.format(this.globalOptions.outputFormat));
60
60
  return 0;
61
61
  }
62
62
  }
@@ -144,7 +144,7 @@ class PruneCommand extends CommandAbstract_1.CommandAbstract {
144
144
  },
145
145
  });
146
146
  if (this.globalOptions.outputFormat)
147
- console.log(dataFormat.format(this.globalOptions.outputFormat));
147
+ console.info(dataFormat.format(this.globalOptions.outputFormat));
148
148
  if (!this.options.confirm && !this.options.dryRun) {
149
149
  const answer = await (0, cli_util_1.confirm)(`Delete ${pruneResult.prune}/${pruneResult.total} snapshots?`);
150
150
  if (answer)
@@ -76,7 +76,7 @@ class RestoreSessionsCommand extends CommandAbstract_1.CommandAbstract {
76
76
  },
77
77
  });
78
78
  if (this.globalOptions.outputFormat)
79
- console.log(dataFormat.format(this.globalOptions.outputFormat));
79
+ console.info(dataFormat.format(this.globalOptions.outputFormat));
80
80
  return 0;
81
81
  }
82
82
  }
@@ -5,6 +5,7 @@ import { CommandAbstract } from "./CommandAbstract";
5
5
  export declare type SnapshotsCommandOptionsType<TResolved = false> = {
6
6
  id?: If<TResolved, string[]>;
7
7
  package?: If<TResolved, string[]>;
8
+ packageTask?: If<TResolved, string[]>;
8
9
  repository?: If<TResolved, string[]>;
9
10
  repositoryType?: If<TResolved, RepositoryConfigType["type"][]>;
10
11
  longId?: boolean;
@@ -64,6 +64,11 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
64
64
  description: "Package names",
65
65
  parser: string_util_1.parseStringList,
66
66
  },
67
+ packageTask: {
68
+ description: "Package task names",
69
+ option: "-pt,--package-task <values>",
70
+ parser: string_util_1.parseStringList,
71
+ },
67
72
  repository: {
68
73
  option: "-r,--repository <names>",
69
74
  description: "Repository names",
@@ -87,6 +92,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
87
92
  const snapshots = new SnapshotsAction_1.SnapshotsAction(config, {
88
93
  ids: this.options.id,
89
94
  packageNames: this.options.package,
95
+ packageTaskNames: this.options.packageTask,
90
96
  repositoryNames: this.options.repository,
91
97
  repositoryTypes: this.options.repositoryType,
92
98
  last: this.options.last,
@@ -103,18 +109,26 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
103
109
  const dataFormat = new DataFormat_1.DataFormat({
104
110
  items: await snapshots.exec(),
105
111
  table: {
106
- labels: ["Id.", "Date", "Package", "Repository", "Repository type"],
112
+ labels: [
113
+ "Id.",
114
+ "Date",
115
+ "Package",
116
+ "Task",
117
+ "Repository",
118
+ "Repository type",
119
+ ],
107
120
  handler: (item) => [
108
121
  this.options.longId ? item.id : item.id.slice(0, 8),
109
122
  item.date.replace("T", " ").replace("Z", ""),
110
123
  item.packageName,
124
+ item.packageTaskName || "",
111
125
  item.repositoryName,
112
126
  item.repositoryType,
113
127
  ],
114
128
  },
115
129
  });
116
130
  if (this.globalOptions.outputFormat)
117
- console.log(dataFormat.format(this.globalOptions.outputFormat));
131
+ console.info(dataFormat.format(this.globalOptions.outputFormat));
118
132
  return 0;
119
133
  }
120
134
  }
@@ -7,6 +7,7 @@ export declare type RepositoryConfigTypeType = RepositoryConfigType["type"];
7
7
  export declare type RepositoryConfigEnabledActionType = "backup" | "init" | "prune" | "restore" | "snapshots";
8
8
  export declare type RepositoryConfigType = {
9
9
  name: string;
10
+ mirrorRepoNames?: string[];
10
11
  enabled?: boolean | {
11
12
  [K in "defaults" | RepositoryConfigEnabledActionType]?: boolean;
12
13
  };
@@ -17,6 +17,7 @@ exports.repositoryConfigDefinition = {
17
17
  properties: {
18
18
  type: { type: "string" },
19
19
  name: { type: "string" },
20
+ mirrorRepoNames: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
20
21
  enabled: {
21
22
  anyOf: [
22
23
  {
@@ -35,11 +35,11 @@ exports.exec = exec;
35
35
  function makeParseLog(type) {
36
36
  const data = [];
37
37
  const consoleLog = console.log;
38
- console.log = (...items) => {
38
+ console.log = console.info = (...items) => {
39
39
  data.push(...items);
40
40
  };
41
41
  return function parseLog() {
42
- console.log = consoleLog;
42
+ console.log = console.info = consoleLog;
43
43
  return JSON.parse(data.flat().join("\n"));
44
44
  };
45
45
  }
@@ -1,4 +1,4 @@
1
- import { RepositoryAbstract, BackupDataType, InitDataType, RestoreDataType, SnapshotsDataType, SnapshotResultType, SnapshotTagEnum, SnapshotTagObjectType, PruneDataType } from "./RepositoryAbstract";
1
+ import { RepositoryAbstract, BackupDataType, InitDataType, RestoreDataType, SnapshotsDataType, SnapshotResultType, SnapshotTagEnum, SnapshotTagObjectType, PruneDataType, CopyBackupType } from "./RepositoryAbstract";
2
2
  import { JSONSchema7 } from "json-schema";
3
3
  export declare type GitRepositoryConfigType = {
4
4
  repo: string;
@@ -25,5 +25,6 @@ export declare class GitRepository extends RepositoryAbstract<GitRepositoryConfi
25
25
  onPrune(data: PruneDataType): Promise<void>;
26
26
  onSnapshots(data: SnapshotsDataType): Promise<SnapshotResultType[]>;
27
27
  onBackup(data: BackupDataType<GitPackageRepositoryConfigType>): Promise<void>;
28
+ onCopyBackup(data: CopyBackupType<GitRepositoryConfigType>): Promise<void>;
28
29
  onRestore(data: RestoreDataType<GitPackageRepositoryConfigType>): Promise<void>;
29
30
  }
@@ -111,6 +111,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
111
111
  log: data.options.verbose,
112
112
  });
113
113
  const pkgPatterns = (0, string_util_1.makePathPatterns)(data.options.packageNames);
114
+ const pkgTaskPatterns = (0, string_util_1.makePathPatterns)(data.options.packageTaskNames);
114
115
  await git.clone({ repo: this.config.repo });
115
116
  const tagNames = data.options.ids?.map((id) => `${GitRepository.refPrefix}/*/${id}*`) || [`${GitRepository.refPrefix}/*`];
116
117
  const tags = await git.getTags(tagNames);
@@ -123,6 +124,8 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
123
124
  return result;
124
125
  if (pkgPatterns && !(0, micromatch_1.isMatch)(parsedTag.package, pkgPatterns))
125
126
  return result;
127
+ if (pkgTaskPatterns && !(0, micromatch_1.isMatch)(parsedTag.task || "", pkgTaskPatterns))
128
+ return result;
126
129
  if (data.options.tags &&
127
130
  !parsedTag.tags.some((value) => data.options.tags?.includes(value)))
128
131
  return result;
@@ -131,6 +134,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
131
134
  id: parsedTag.id,
132
135
  date: parsedTag.date,
133
136
  packageName: parsedTag.package,
137
+ packageTaskName: parsedTag.task,
134
138
  tags: parsedTag.tags,
135
139
  });
136
140
  return result;
@@ -201,6 +205,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
201
205
  tags: data.options.tags ?? [],
202
206
  date: data.snapshot.date,
203
207
  package: data.package.name,
208
+ task: data.package.task?.name,
204
209
  version: nodePkg.version,
205
210
  });
206
211
  await git.addTag(meta.name, meta.message);
@@ -210,6 +215,9 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
210
215
  recursive: true,
211
216
  });
212
217
  }
218
+ onCopyBackup(data) {
219
+ throw new Error("Method not implemented.");
220
+ }
213
221
  async onRestore(data) {
214
222
  const restorePath = data.targetPath ?? data.package.restorePath;
215
223
  (0, assert_1.ok)(restorePath);
@@ -1,9 +1,10 @@
1
- import { RepositoryAbstract, BackupDataType, InitDataType, RestoreDataType, SnapshotsDataType, SnapshotResultType, PruneDataType } from "./RepositoryAbstract";
1
+ import { RepositoryAbstract, BackupDataType, InitDataType, RestoreDataType, SnapshotsDataType, SnapshotResultType, PruneDataType, CopyBackupType } from "./RepositoryAbstract";
2
2
  import type { JSONSchema7 } from "json-schema";
3
3
  export declare type MetaDataType = {
4
4
  id: string;
5
5
  date: string;
6
6
  package: string;
7
+ task: string | undefined;
7
8
  tags: string[];
8
9
  version: string;
9
10
  };
@@ -50,6 +51,7 @@ export declare class LocalRepository extends RepositoryAbstract<LocalRepositoryC
50
51
  onSnapshots(data: SnapshotsDataType): Promise<SnapshotResultType[]>;
51
52
  private normalizeCompressConfig;
52
53
  onBackup(data: BackupDataType<LocalPackageRepositoryConfigType>): Promise<void>;
54
+ onCopyBackup(data: CopyBackupType<LocalRepositoryConfigType>): Promise<void>;
53
55
  onRestore(data: RestoreDataType<LocalPackageRepositoryConfigType>): Promise<void>;
54
56
  }
55
57
  export {};
@@ -122,9 +122,10 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
122
122
  async onSnapshots(data) {
123
123
  if (!(await (0, fs_util_1.checkDir)(this.config.outPath)))
124
124
  throw new Error(`Repository (${this.repository.name}) out path does not exist: ${this.config.outPath}`);
125
- const snapshotNames = await (0, promises_1.readdir)(this.config.outPath);
125
+ const snapshotNames = await (0, fs_util_1.readDir)(this.config.outPath);
126
126
  const snapshots = [];
127
127
  const packagePatterns = (0, string_util_1.makePathPatterns)(data.options.packageNames);
128
+ const taskPatterns = (0, string_util_1.makePathPatterns)(data.options.packageTaskNames);
128
129
  for (const snapshotName of snapshotNames) {
129
130
  const snapshotNameData = LocalRepository.parseSnapshotName(snapshotName);
130
131
  if (!snapshotNameData)
@@ -137,6 +138,8 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
137
138
  continue;
138
139
  const metaPath = (0, path_1.join)(this.config.outPath, snapshotName);
139
140
  const meta = await LocalRepository.parseMetaData(metaPath);
141
+ if (taskPatterns && !(0, micromatch_1.isMatch)(meta.task || "", taskPatterns))
142
+ continue;
140
143
  if (data.options.ids &&
141
144
  !data.options.ids.some((id) => meta.id.startsWith(id)))
142
145
  continue;
@@ -148,6 +151,7 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
148
151
  id: meta.id,
149
152
  date: meta.date,
150
153
  packageName: meta.package,
154
+ packageTaskName: meta.task,
151
155
  tags: meta.tags,
152
156
  });
153
157
  }
@@ -288,12 +292,35 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
288
292
  date: data.snapshot.date,
289
293
  tags: data.options.tags ?? [],
290
294
  package: data.package.name,
295
+ task: data.package.task?.name,
291
296
  version: nodePkg.version,
292
297
  };
293
298
  if (data.options.verbose)
294
299
  (0, cli_util_1.logExec)(`Writing metadata into ${metaPath}`);
295
300
  await (0, promises_1.writeFile)(metaPath, LocalRepository.stringifyMetaData(meta));
296
301
  }
302
+ async onCopyBackup(data) {
303
+ const snapshotName = LocalRepository.buildSnapshotName({
304
+ snapshotId: data.snapshot.id,
305
+ snapshotDate: data.snapshot.date,
306
+ packageName: data.package.name,
307
+ });
308
+ const sourcePath = (0, path_1.resolve)((0, path_1.join)(this.config.outPath, snapshotName));
309
+ const targetPath = (0, path_1.resolve)((0, path_1.join)(data.mirrorRepositoryConfig.outPath, snapshotName));
310
+ const sourceMetaPath = `${sourcePath}.json`;
311
+ const targetMetaPath = `${targetPath}.json`;
312
+ if (data.options.verbose)
313
+ (0, cli_util_1.logExec)(`Copying files to ${targetPath}`);
314
+ await (0, promises_1.mkdir)(targetPath);
315
+ await (0, fs_util_1.cpy)({
316
+ input: {
317
+ type: "glob",
318
+ sourcePath,
319
+ },
320
+ targetPath,
321
+ });
322
+ await (0, promises_1.copyFile)(sourceMetaPath, targetMetaPath);
323
+ }
297
324
  async onRestore(data) {
298
325
  const relRestorePath = data.targetPath ?? data.package.restorePath;
299
326
  (0, assert_1.ok)(relRestorePath);
@@ -11,6 +11,7 @@ export declare type SnapshotType = {
11
11
  export declare type SnapshotResultType = SnapshotType & {
12
12
  originalId: string;
13
13
  packageName: string;
14
+ packageTaskName: string | undefined;
14
15
  tags: string[];
15
16
  };
16
17
  export declare type ProgressDataType = {
@@ -24,7 +25,14 @@ export declare type InitDataType = {
24
25
  options: InitActionOptionsType;
25
26
  };
26
27
  export declare type SnapshotsDataType = {
27
- options: Pick<SnapshotsActionOptionsType, "ids" | "packageNames" | "verbose" | "tags">;
28
+ options: Pick<SnapshotsActionOptionsType, "ids" | "packageNames" | "packageTaskNames" | "verbose" | "tags">;
29
+ };
30
+ export declare type CopyBackupType<TRepositoryConfig> = {
31
+ options: BackupActionOptionsType;
32
+ snapshot: SnapshotType;
33
+ package: PackageConfigType;
34
+ mirrorRepositoryConfig: TRepositoryConfig;
35
+ onProgress: (data: ProgressDataType) => Promise<void>;
28
36
  };
29
37
  export declare type BackupDataType<TPackageConfig> = {
30
38
  options: BackupActionOptionsType;
@@ -53,6 +61,7 @@ export declare enum SnapshotTagEnum {
53
61
  SHORT_ID = "shortId",
54
62
  DATE = "date",
55
63
  PACKAGE = "package",
64
+ TASK = "task",
56
65
  TAGS = "tags",
57
66
  VERSION = "version"
58
67
  }
@@ -61,6 +70,7 @@ export declare type SnapshotTagObjectType = {
61
70
  [SnapshotTagEnum.SHORT_ID]: string;
62
71
  [SnapshotTagEnum.DATE]: string;
63
72
  [SnapshotTagEnum.PACKAGE]: string;
73
+ [SnapshotTagEnum.TASK]: string | undefined;
64
74
  [SnapshotTagEnum.TAGS]: string[];
65
75
  [SnapshotTagEnum.VERSION]: string;
66
76
  };
@@ -72,6 +82,7 @@ export declare abstract class RepositoryAbstract<TConfig> {
72
82
  abstract onInit(data: InitDataType): Promise<void>;
73
83
  abstract onPrune(data: PruneDataType): Promise<void>;
74
84
  abstract onSnapshots(data: SnapshotsDataType): Promise<SnapshotResultType[]>;
85
+ abstract onCopyBackup(data: CopyBackupType<TConfig>): Promise<void>;
75
86
  abstract onBackup(data: BackupDataType<unknown>): Promise<void>;
76
87
  abstract onRestore(data: RestoreDataType<unknown>): Promise<void>;
77
88
  }
@@ -7,6 +7,7 @@ var SnapshotTagEnum;
7
7
  SnapshotTagEnum["SHORT_ID"] = "shortId";
8
8
  SnapshotTagEnum["DATE"] = "date";
9
9
  SnapshotTagEnum["PACKAGE"] = "package";
10
+ SnapshotTagEnum["TASK"] = "task";
10
11
  SnapshotTagEnum["TAGS"] = "tags";
11
12
  SnapshotTagEnum["VERSION"] = "version";
12
13
  })(SnapshotTagEnum = exports.SnapshotTagEnum || (exports.SnapshotTagEnum = {}));
@@ -1,5 +1,5 @@
1
1
  import { RepositoryType } from "../util/ResticUtil";
2
- import { RepositoryAbstract, BackupDataType, InitDataType, RestoreDataType, SnapshotsDataType, SnapshotResultType, SnapshotTagObjectType, SnapshotTagEnum, PruneDataType } from "./RepositoryAbstract";
2
+ import { RepositoryAbstract, BackupDataType, InitDataType, RestoreDataType, SnapshotsDataType, SnapshotResultType, SnapshotTagObjectType, SnapshotTagEnum, PruneDataType, CopyBackupType } from "./RepositoryAbstract";
3
3
  import { JSONSchema7 } from "json-schema";
4
4
  export declare type ResticRepositoryConfigType = {
5
5
  password: string | {
@@ -28,13 +28,14 @@ export declare class ResticRepository extends RepositoryAbstract<ResticRepositor
28
28
  name: SnapshotTagEnum;
29
29
  value: string;
30
30
  } | null;
31
- static parseSnapshotTags(tags: string[]): Required<Partial<SnapshotTagObjectType> & {
31
+ static parseSnapshotTags(tags: string[]): SnapshotTagObjectType & {
32
32
  tags: string[];
33
- }>;
33
+ };
34
34
  onGetSource(): string;
35
35
  onInit(data: InitDataType): Promise<void>;
36
36
  onSnapshots(data: SnapshotsDataType): Promise<SnapshotResultType[]>;
37
37
  onPrune(data: PruneDataType): Promise<void>;
38
38
  onBackup(data: BackupDataType<ResticPackageRepositoryConfigType>): Promise<void>;
39
+ onCopyBackup(data: CopyBackupType<ResticRepositoryConfigType>): Promise<void>;
39
40
  onRestore(data: RestoreDataType<ResticPackageRepositoryConfigType>): Promise<void>;
40
41
  }
@@ -126,6 +126,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
126
126
  log: data.options.verbose,
127
127
  });
128
128
  const packagePatterns = (0, string_util_1.makePathPatterns)(data.options.packageNames);
129
+ const taskNamePatterns = (0, string_util_1.makePathPatterns)(data.options.packageTaskNames);
129
130
  const result = await restic.snapshots({
130
131
  json: true,
131
132
  tags: [
@@ -138,12 +139,15 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
138
139
  return items;
139
140
  if (packagePatterns && !(0, micromatch_1.isMatch)(tag.package, packagePatterns))
140
141
  return items;
142
+ if (taskNamePatterns && !(0, micromatch_1.isMatch)(tag.task || "", taskNamePatterns))
143
+ return items;
141
144
  const itemTags = tag.tags ?? [];
142
145
  if (data.options.tags && !itemTags.some((t) => itemTags.includes(t)))
143
146
  return items;
144
147
  items.push({
145
148
  originalId: item.id,
146
149
  packageName: tag.package,
150
+ packageTaskName: tag.task,
147
151
  date: tag.date,
148
152
  id: tag.id,
149
153
  tags: itemTags,
@@ -231,6 +235,11 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
231
235
  ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.DATE, data.snapshot.date),
232
236
  ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.VERSION, nodePkg.version),
233
237
  packageTag,
238
+ ...(data.package.task?.name
239
+ ? [
240
+ ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.TASK, data.package.task?.name),
241
+ ]
242
+ : []),
234
243
  ...(data.options.tags ?? []),
235
244
  ],
236
245
  onStream: async (streamData) => {
@@ -262,6 +271,30 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
262
271
  percent: 100,
263
272
  });
264
273
  }
274
+ async onCopyBackup(data) {
275
+ const config = data.mirrorRepositoryConfig;
276
+ const [snapshot] = await this.onSnapshots({
277
+ options: {
278
+ ids: [data.snapshot.id],
279
+ packageNames: [data.package.name],
280
+ },
281
+ });
282
+ if (!snapshot)
283
+ throw new AppError_1.AppError(`Snapshot not found`);
284
+ const restic = new ResticUtil_1.ResticUtil({
285
+ env: {
286
+ ...(await this.buildEnv()),
287
+ ...(typeof config.password === "string"
288
+ ? { RESTIC_PASSWORD2: config.password }
289
+ : { RESTIC_PASSWORD_FILE2: (0, path_1.resolve)(config.password.path) }),
290
+ RESTIC_REPOSITORY2: await ResticUtil_1.ResticUtil.formatRepository(config.repository),
291
+ },
292
+ log: data.options.verbose,
293
+ });
294
+ await restic.copy({
295
+ id: snapshot.originalId,
296
+ });
297
+ }
265
298
  async onRestore(data) {
266
299
  const restorePath = data.targetPath ?? data.package.restorePath;
267
300
  (0, assert_1.ok)(restorePath);
@@ -137,7 +137,7 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
137
137
  const restorePath = data.package.restorePath;
138
138
  (0, assert_1.ok)(typeof restorePath === "string");
139
139
  await (0, fs_util_1.mkdirIfNotExists)(restorePath);
140
- const files = await (0, promises_1.readdir)(restorePath);
140
+ const files = await (0, fs_util_1.readDir)(restorePath);
141
141
  for (const file of files) {
142
142
  if (file.startsWith("ib_logfile")) {
143
143
  const filePath = (0, path_1.join)(restorePath, file);
package/Task/MssqlTask.js CHANGED
@@ -84,7 +84,7 @@ class MssqlTask extends TaskAbstract_1.TaskAbstract {
84
84
  const restorePath = data.package.restorePath;
85
85
  (0, assert_1.ok)(typeof restorePath === "string");
86
86
  await (0, fs_util_1.mkdirIfNotExists)(restorePath);
87
- const files = await (0, promises_1.readdir)(restorePath);
87
+ const files = await (0, fs_util_1.readDir)(restorePath);
88
88
  for (const file of files) {
89
89
  if (!file.endsWith(MssqlTask.SUFFIX))
90
90
  continue;
@@ -9,6 +9,7 @@ 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
- onExport(tableNames: string[], output: string): Promise<void>;
12
+ onExportTables(tableNames: string[], output: string): Promise<void>;
13
+ onExportStoredPrograms(output: string): Promise<void>;
13
14
  onImport(path: string, database: string): Promise<void>;
14
15
  }
@@ -68,7 +68,7 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
68
68
  table_schema = '${database}'
69
69
  `);
70
70
  }
71
- async onExport(tableNames, output) {
71
+ async onExportTables(tableNames, output) {
72
72
  const stream = (0, fs_1.createWriteStream)(output);
73
73
  await Promise.all([
74
74
  new Promise((resolve, reject) => {
@@ -107,6 +107,36 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
107
107
  if (!successFooter)
108
108
  throw new AppError_1.AppError("No end line found (incomplete backup)");
109
109
  }
110
+ async onExportStoredPrograms(output) {
111
+ const stream = (0, fs_1.createWriteStream)(output);
112
+ await Promise.all([
113
+ new Promise((resolve, reject) => {
114
+ stream.on("close", resolve);
115
+ stream.on("error", reject);
116
+ }),
117
+ await (0, process_util_1.exec)("mysqldump", [
118
+ ...(await this.buildConnectionArgs()),
119
+ "--lock-tables=false",
120
+ "--routines",
121
+ "--events",
122
+ "--skip-triggers",
123
+ "--no-create-info",
124
+ "--no-data",
125
+ "--no-create-db",
126
+ "--skip-opt",
127
+ ], null, {
128
+ pipe: { stream: stream },
129
+ log: {
130
+ exec: this.verbose,
131
+ stderr: this.verbose,
132
+ allToStderr: true,
133
+ },
134
+ stderr: {
135
+ toExitCode: true,
136
+ },
137
+ }),
138
+ ]);
139
+ }
110
140
  async onImport(path, database) {
111
141
  await (0, process_util_1.exec)("mysql", [...(await this.buildConnectionArgs(false)), database], null, {
112
142
  pipe: {
@@ -9,6 +9,7 @@ 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
- onExport(tableNames: string[], output: string): Promise<void>;
12
+ onExportTables(tableNames: string[], output: string): Promise<void>;
13
+ onExportStoredPrograms(): Promise<void>;
13
14
  onImport(path: string, database: string): Promise<void>;
14
15
  }
@@ -71,7 +71,7 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
71
71
  table_schema NOT IN ('pg_catalog', 'information_schema')
72
72
  `);
73
73
  }
74
- async onExport(tableNames, output) {
74
+ async onExportTables(tableNames, output) {
75
75
  const stream = (0, fs_1.createWriteStream)(output);
76
76
  await Promise.all([
77
77
  new Promise((resolve, reject) => {
@@ -90,6 +90,9 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
90
90
  }),
91
91
  ]);
92
92
  }
93
+ async onExportStoredPrograms() {
94
+ throw new Error(`Method not implemented: onExportStoredPrograms`);
95
+ }
93
96
  async onImport(path, database) {
94
97
  await (0, process_util_1.exec)("psql", [...(await this.buildConnectionArgs(database)), "-f", (0, path_1.normalize)(path)], undefined, {
95
98
  log: this.verbose,
@@ -14,6 +14,7 @@ export declare type SqlDumpTaskConfigType = {
14
14
  port?: number;
15
15
  database: string;
16
16
  username: string;
17
+ storedPrograms?: boolean;
17
18
  targetDatabase?: TargetDatabaseType;
18
19
  includeTables?: string[];
19
20
  excludeTables?: string[];
@@ -28,7 +29,8 @@ export declare abstract class SqlDumpTaskAbstract<TConfig extends SqlDumpTaskCon
28
29
  abstract onDatabaseIsEmpty(databaseName: string): Promise<boolean>;
29
30
  abstract onFetchTableNames(database: string): Promise<string[]>;
30
31
  abstract onExecQuery(query: string): ReturnType<typeof exec>;
31
- abstract onExport(tableNames: string[], output: string): Promise<void>;
32
+ abstract onExportTables(tableNames: string[], output: string): Promise<void>;
33
+ abstract onExportStoredPrograms(output: string): Promise<void>;
32
34
  abstract onImport(path: string, database: string): Promise<void>;
33
35
  onBackup(data: BackupDataType): Promise<void>;
34
36
  onRestore(data: RestoreDataType): Promise<void>;
@@ -44,6 +44,7 @@ exports.sqlDumpTaskDefinition = {
44
44
  collate: { type: "string" },
45
45
  },
46
46
  },
47
+ storedPrograms: { type: "boolean" },
47
48
  includeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
48
49
  excludeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
49
50
  oneFileByTable: { type: "boolean" },
@@ -116,7 +117,7 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
116
117
  await (0, promises_1.mkdir)(outputPath, { recursive: true });
117
118
  if (!this.config.oneFileByTable) {
118
119
  const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ database: this.config.database }));
119
- await this.onExport(tableNames, outPath);
120
+ await this.onExportTables(tableNames, outPath);
120
121
  }
121
122
  else {
122
123
  let current = 0;
@@ -129,9 +130,13 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
129
130
  });
130
131
  current++;
131
132
  const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ table: tableName }));
132
- await this.onExport([tableName], outPath);
133
+ await this.onExportTables([tableName], outPath);
133
134
  }
134
135
  }
136
+ if (this.config.storedPrograms) {
137
+ const outPath = (0, path_1.join)(outputPath, "stored-programs.sql");
138
+ await this.onExportStoredPrograms(outPath);
139
+ }
135
140
  }
136
141
  async onRestore(data) {
137
142
  const restorePath = data.package.restorePath;
@@ -155,7 +160,7 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
155
160
  database: database.name,
156
161
  });
157
162
  }
158
- const items = (await (0, promises_1.readdir)(restorePath))
163
+ const items = (await (0, fs_util_1.readDir)(restorePath))
159
164
  .map(parseSqlFile)
160
165
  .filter((v) => !!v);
161
166
  // Database check
package/cli.js CHANGED
@@ -104,7 +104,7 @@ function parseArgs(args) {
104
104
  (0, process_util_1.onExit)((eventName, error) => {
105
105
  if (eventName !== "exit") {
106
106
  process.stdout.write(cli_util_1.showCursorCommand);
107
- console.log(`\nClosing... (reason: ${eventName})`);
107
+ console.info(`\nClosing... (reason: ${eventName})`);
108
108
  if (error instanceof Error)
109
109
  console.error((0, chalk_1.red)(error.stack));
110
110
  }
@@ -20,6 +20,9 @@
20
20
  "name": {
21
21
  "type": "string"
22
22
  },
23
+ "mirrorRepoNames": {
24
+ "$ref": "#/definitions/stringlist-util"
25
+ },
23
26
  "enabled": {
24
27
  "anyOf": [
25
28
  {
@@ -713,6 +716,9 @@
713
716
  }
714
717
  }
715
718
  },
719
+ "storedPrograms": {
720
+ "type": "boolean"
721
+ },
716
722
  "includeTables": {
717
723
  "$ref": "#/definitions/stringlist-util"
718
724
  },
package/package.json CHANGED
@@ -1,29 +1,25 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.7.0",
3
+ "version": "0.10.0",
4
4
  "dependencies": {
5
5
  "ajv": "^8.11.0",
6
6
  "async": "^3.2.4",
7
7
  "chalk": "^4.1.2",
8
8
  "cli-table3": "^0.6.2",
9
- "commander": "^9.2.0",
10
- "dayjs": "^1.11.2",
9
+ "commander": "^9.4.0",
10
+ "dayjs": "^1.11.5",
11
11
  "fast-glob": "^3.2.11",
12
12
  "micromatch": "^4.0.5",
13
- "sqlite": "^4.1.1",
14
- "sqlite3": "^5.0.8"
13
+ "sqlite": "^4.1.2",
14
+ "sqlite3": "^5.0.11"
15
15
  },
16
16
  "optionalDependencies": {
17
- "ts-node": "^10.7.0",
18
- "yaml": "^2.1.0"
17
+ "ts-node": "^10.9.1",
18
+ "yaml": "^2.1.1"
19
19
  },
20
20
  "engine": {
21
21
  "node": ">=16.0.0"
22
22
  },
23
- "bin": {
24
- "datatruck": "bin.js",
25
- "dtt": "bin.js"
26
- },
27
23
  "description": "Tool for creating and managing backups",
28
24
  "homepage": "https://github.com/swordev/datatruck#readme",
29
25
  "bugs": {
@@ -38,5 +34,9 @@
38
34
  "name": "Juanra GM",
39
35
  "email": "juanrgm724@gmail.com",
40
36
  "url": "https://github.com/juanrgm"
37
+ },
38
+ "bin": {
39
+ "datatruck": "bin.js",
40
+ "dtt": "bin.js"
41
41
  }
42
42
  }
package/util/GitUtil.js CHANGED
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GitUtil = void 0;
4
4
  const fs_util_1 = require("./fs-util");
5
5
  const process_util_1 = require("./process-util");
6
- const promises_1 = require("fs/promises");
7
6
  class GitUtil {
8
7
  constructor(options) {
9
8
  this.options = options;
@@ -16,7 +15,7 @@ class GitUtil {
16
15
  }
17
16
  async canBeInit(repo) {
18
17
  return ((0, fs_util_1.isLocalDir)(repo) &&
19
- (!(await (0, fs_util_1.checkDir)(repo)) || !(await (0, promises_1.readdir)(repo)).length));
18
+ (!(await (0, fs_util_1.checkDir)(repo)) || !(await (0, fs_util_1.readDir)(repo)).length));
20
19
  }
21
20
  async clone(options) {
22
21
  return await this.exec([
@@ -86,6 +86,10 @@ export declare class ResticUtil {
86
86
  allowEmptySnapshot?: boolean;
87
87
  onStream?: (data: BackupStreamType) => void;
88
88
  }): Promise<ExecResultType>;
89
+ copy(options: {
90
+ id: string;
91
+ onStream?: (data: BackupStreamType) => Promise<void>;
92
+ }): Promise<ExecResultType>;
89
93
  restore(options: {
90
94
  id: string;
91
95
  target: string;
@@ -154,6 +154,22 @@ class ResticUtil {
154
154
  throw error;
155
155
  }
156
156
  }
157
+ async copy(options) {
158
+ return await this.exec(["copy", "--json", options.id], {
159
+ stderr: {
160
+ toExitCode: true,
161
+ },
162
+ stdout: {
163
+ ...(options.onStream && {
164
+ onData: async (data) => {
165
+ if (data.startsWith("{") && data.endsWith("}")) {
166
+ await options.onStream?.(JSON.parse(data));
167
+ }
168
+ },
169
+ }),
170
+ },
171
+ });
172
+ }
157
173
  async restore(options) {
158
174
  return await this.exec(["restore", "--json", options.id, "--target", options.target], {
159
175
  stderr: {
package/util/cli-util.js CHANGED
@@ -32,11 +32,11 @@ function logVars(data) {
32
32
  let first = true;
33
33
  for (const key in data) {
34
34
  if (first) {
35
- console.log();
35
+ console.info();
36
36
  first = false;
37
37
  }
38
38
  const value = data[key];
39
- console.log(`${chalk_1.default.cyan(key)}${chalk_1.default.grey(":")} ${chalk_1.default.white(value ?? "")}`);
39
+ console.info(`${chalk_1.default.cyan(key)}${chalk_1.default.grey(":")} ${chalk_1.default.white(value ?? "")}`);
40
40
  }
41
41
  }
42
42
  exports.logVars = logVars;
@@ -12,5 +12,5 @@ export declare function filterByLast<TItem extends {
12
12
  }>(items: TItem[], options: FilterByLastOptionsType, reasons?: Record<number, string[]>): TItem[];
13
13
  export declare function createChron(): {
14
14
  start: () => number;
15
- elapsed: (formatted?: boolean | undefined) => string | number;
15
+ elapsed: (formatted?: boolean) => string | number;
16
16
  };
@@ -1,4 +1,4 @@
1
1
  export declare function makeTableSelector<T>(tableName: string): {
2
- (name?: keyof T | undefined): string;
2
+ (name?: keyof T): string;
3
3
  toString: any;
4
4
  };
package/util/fs-util.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { Interface } from "readline";
3
4
  export declare function isLocalDir(path: string): boolean;
4
5
  export declare function isDirEmpty(path: string): Promise<boolean>;
@@ -23,6 +24,7 @@ export declare function mkTmpDir(prefix: string, id?: string): Promise<string>;
23
24
  export declare function readPartialFile(path: string, positions: [number, number?]): Promise<string>;
24
25
  export declare function checkFile(path: string): Promise<boolean>;
25
26
  export declare function checkDir(path: string): Promise<boolean>;
27
+ export declare function readDir(path: string): Promise<string[]>;
26
28
  export declare function forEachFile(dirPath: string, cb: (path: string, dir: boolean) => void, includeDir?: boolean): Promise<void>;
27
29
  export declare function writeGitIgnoreList(options: {
28
30
  paths: NodeJS.ReadableStream | string[];
package/util/fs-util.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.cpy = exports.writePathLists = exports.writeGitIgnoreList = exports.forEachFile = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.tmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.existsFile = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.readdirIfExists = exports.writeJSONFile = exports.existsDir = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isDirEmpty = exports.isLocalDir = void 0;
6
+ exports.cpy = exports.writePathLists = exports.writeGitIgnoreList = exports.forEachFile = exports.readDir = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.tmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.existsFile = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.readdirIfExists = exports.writeJSONFile = exports.existsDir = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isDirEmpty = exports.isLocalDir = void 0;
7
7
  const globalData_1 = __importDefault(require("../globalData"));
8
8
  const path_util_1 = require("./path-util");
9
9
  const async_1 = require("async");
@@ -21,7 +21,7 @@ function isLocalDir(path) {
21
21
  }
22
22
  exports.isLocalDir = isLocalDir;
23
23
  async function isDirEmpty(path) {
24
- const files = await (0, promises_1.readdir)(path);
24
+ const files = await readDir(path);
25
25
  return !files.length;
26
26
  }
27
27
  exports.isDirEmpty = isDirEmpty;
@@ -57,7 +57,7 @@ exports.writeJSONFile = writeJSONFile;
57
57
  async function readdirIfExists(path) {
58
58
  if (!(await existsDir(path)))
59
59
  return [];
60
- return await (0, promises_1.readdir)(path);
60
+ return await readDir(path);
61
61
  }
62
62
  exports.readdirIfExists = readdirIfExists;
63
63
  exports.parseFileExtensions = ["json", "js", "ts", "yaml", "yml"];
@@ -179,8 +179,25 @@ async function checkDir(path) {
179
179
  }
180
180
  }
181
181
  exports.checkDir = checkDir;
182
+ async function readDir(path) {
183
+ try {
184
+ return await (0, promises_1.readdir)(path);
185
+ }
186
+ catch (anyError) {
187
+ const nodeError = anyError;
188
+ if (nodeError.code === "ENOENT") {
189
+ const error = new Error(nodeError.message);
190
+ error.code = nodeError.code;
191
+ error.errno = nodeError.errno;
192
+ error.path = nodeError.path;
193
+ throw error;
194
+ }
195
+ throw anyError;
196
+ }
197
+ }
198
+ exports.readDir = readDir;
182
199
  async function forEachFile(dirPath, cb, includeDir) {
183
- const files = await (0, promises_1.readdir)(dirPath);
200
+ const files = await readDir(dirPath);
184
201
  for (const file of files) {
185
202
  const filePath = (0, path_1.join)(dirPath, file);
186
203
  if ((await (0, promises_1.stat)(filePath)).isDirectory()) {
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { SpawnOptions, ChildProcess } from "child_process";
3
4
  import { ReadStream, WriteStream } from "fs";
4
5
  export declare type ExecLogSettingsType = {
package/CHANGELOG.md DELETED
@@ -1,139 +0,0 @@
1
- # @datatruck/cli
2
-
3
- ## 0.7.0
4
-
5
- ### Minor Changes
6
-
7
- - [`3b8d6da`](https://github.com/swordev/datatruck/commit/3b8d6da01495799aceb848a63b35b8c46a7d1b0e) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `--package-task` cli option
8
-
9
- * [`69b34a0`](https://github.com/swordev/datatruck/commit/69b34a02b9cade48df2b071a92a8f79d5cfec23e) Thanks [@juanrgm](https://github.com/juanrgm)! - Allow restore multiple backups over the same database
10
-
11
- - [`69caf26`](https://github.com/swordev/datatruck/commit/69caf26881272331bd4c8d7d345b3b85d33e33ac) Thanks [@juanrgm](https://github.com/juanrgm)! - Add cli short option to `--tag`
12
-
13
- * [`377f0de`](https://github.com/swordev/datatruck/commit/377f0de345c9c8f45c772ac47e4ded81e91725d7) Thanks [@juanrgm](https://github.com/juanrgm)! - Rename cli short option to `-rt`
14
-
15
- ### Patch Changes
16
-
17
- - [`c03200a`](https://github.com/swordev/datatruck/commit/c03200a6347d1e9f9fdad86dcb22df30bbefcab4) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix `sql-dump` tasks
18
-
19
- * [`f56a4bc`](https://github.com/swordev/datatruck/commit/f56a4bcb429a674c13f32de73985cd67eb1acc23) Thanks [@juanrgm](https://github.com/juanrgm)! - Show full error message
20
-
21
- - [`4324422`](https://github.com/swordev/datatruck/commit/4324422550474619811a8d455af55bc6e3b08aeb) Thanks [@juanrgm](https://github.com/juanrgm)! - Use connection port in `mysql-dump` task
22
-
23
- ## 0.6.1
24
-
25
- ### Patch Changes
26
-
27
- - [`0ba6229`](https://github.com/swordev/datatruck/commit/0ba6229348c109a59783e72242ab7c0e61f25e36) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix progress bar in restic repository
28
-
29
- ## 0.6.0
30
-
31
- ### Minor Changes
32
-
33
- - [`0c6877d`](https://github.com/swordev/datatruck/commit/0c6877d189761e75dd434b0a8d72b71621d024de) Thanks [@juanrgm](https://github.com/juanrgm)! - Show more progress stats
34
-
35
- * [`751e1f6`](https://github.com/swordev/datatruck/commit/751e1f6d6b33d3fa96eb40d998fdd140ce0e3875) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `fileCopyConcurrency` option
36
-
37
- - [`05487e6`](https://github.com/swordev/datatruck/commit/05487e6a33f875a3afb7ff0815b16da6f2a41301) Thanks [@juanrgm](https://github.com/juanrgm)! - Parse InnoDB error in `MariadbTask` to avoid infinite wait
38
-
39
- ### Patch Changes
40
-
41
- - [`b62a6f8`](https://github.com/swordev/datatruck/commit/b62a6f8a82409339afd65d4f96476eb57bbfb5a2) Thanks [@juanrgm](https://github.com/juanrgm)! - Resolve target/restore path in local repository
42
-
43
- ## 0.5.0
44
-
45
- ### Minor Changes
46
-
47
- - [`5aeb2af`](https://github.com/swordev/datatruck/commit/5aeb2afb96692e00bdba501b58df9cc0e02dceaa) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `enabled` option to repository config
48
-
49
- * [`75de836`](https://github.com/swordev/datatruck/commit/75de8369356cf02ed3fd5c58b1f9bea66432cda8) Thanks [@juanrgm](https://github.com/juanrgm)! - Allow restic password without file
50
-
51
- ## 0.4.0
52
-
53
- ### Minor Changes
54
-
55
- - [`eeb00a6`](https://github.com/swordev/datatruck/commit/eeb00a69d75c91da40711ae79475612b1d5193b6) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `tempDir` config option
56
-
57
- ## 0.3.2
58
-
59
- ### Patch Changes
60
-
61
- - [`8957c3b`](https://github.com/swordev/datatruck/commit/8957c3b5846606db8b825fef357445210f2a3ac3) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix restic progress parser
62
-
63
- * [`2989718`](https://github.com/swordev/datatruck/commit/29897185e3d6659359d51ab2212351005137f86c) Thanks [@juanrgm](https://github.com/juanrgm)! - Show closing reason
64
-
65
- - [`b9e0843`](https://github.com/swordev/datatruck/commit/b9e0843c7970944cfd30a7d2a543f515adfa60e4) Thanks [@juanrgm](https://github.com/juanrgm)! - Show restic progress in megabytes
66
-
67
- ## 0.3.1
68
-
69
- ### Patch Changes
70
-
71
- - [`c3bb4c6`](https://github.com/swordev/datatruck/commit/c3bb4c609887c5525cf35487ea237750addb6e75) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix restic stdout parser
72
-
73
- ## 0.3.0
74
-
75
- ### Minor Changes
76
-
77
- - [`d63fd25`](https://github.com/swordev/datatruck/commit/d63fd25ffa8d2e539d2125dfd6a3f55020086804) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `snapshotDate` param
78
-
79
- * [`486ef4a`](https://github.com/swordev/datatruck/commit/486ef4add27ae1dbfd166b16c257522f43537ecd) Thanks [@juanrgm](https://github.com/juanrgm)! - Resolve params in `include` and `exclude`
80
-
81
- - [`617dae2`](https://github.com/swordev/datatruck/commit/617dae2c8ed90e6e65e8109f03cfad0e64bd7c02) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `script` task
82
-
83
- ### Patch Changes
84
-
85
- - [`d1b3ea9`](https://github.com/swordev/datatruck/commit/d1b3ea9c9540d30898c00490963523a4fbc68193) Thanks [@juanrgm](https://github.com/juanrgm)! - Avoid use gitignore if is not necessary in restic repository
86
-
87
- ## 0.2.0
88
-
89
- ### Minor Changes
90
-
91
- - [`120460c`](https://github.com/swordev/datatruck/commit/120460c8824cef4184e43f571a4cc0798b899b66) Thanks [@juanrgm](https://github.com/juanrgm)! - Enable `include` option in restic repository
92
-
93
- ### Patch Changes
94
-
95
- - [`e30ede3`](https://github.com/swordev/datatruck/commit/e30ede371bc7ab3fc1cd47758fdac7a28e8e2705) Thanks [@juanrgm](https://github.com/juanrgm)! - Resolve `RESTIC_PASSWORD_FILE` path
96
-
97
- * [`8539d28`](https://github.com/swordev/datatruck/commit/8539d285b2c51d700aa811cd772d573fa0d613eb) Thanks [@juanrgm](https://github.com/juanrgm)! - Allow empty backup in restic repository
98
-
99
- ## 0.1.0
100
-
101
- ### Minor Changes
102
-
103
- - [`88d46cd`](https://github.com/swordev/datatruck/commit/88d46cd56293df4c6fc21a9ad61d6236ac91f325) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `custom` output format
104
-
105
- ### Patch Changes
106
-
107
- - [`24a1e5e`](https://github.com/swordev/datatruck/commit/24a1e5e86336e7a92556287e49548dc542f0e579) Thanks [@juanrgm](https://github.com/juanrgm)! - Update dependencies
108
-
109
- ## 0.0.6
110
-
111
- ### Patch Changes
112
-
113
- - [`8de6e6c`](https://github.com/swordev/datatruck/commit/8de6e6ceddb59635cb4634d884e7690eeaf59bac) Thanks [@juanrgm](https://github.com/juanrgm)! - Publish migrations
114
-
115
- ## 0.0.5
116
-
117
- ### Patch Changes
118
-
119
- - [`78cb0c1`](https://github.com/swordev/datatruck/commit/78cb0c17558543841cd7080dc4c672e6cbfd5634) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix docker image
120
-
121
- ## 0.0.4
122
-
123
- ### Patch Changes
124
-
125
- - [`d9e534b`](https://github.com/swordev/datatruck/commit/d9e534bd968acf9cd1c93f20e6152c004cb1f23b) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix package file read
126
-
127
- * [`b882c58`](https://github.com/swordev/datatruck/commit/b882c58183e9a75abc876645e18d7b67186dd662) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix read of migrations
128
-
129
- ## 0.0.3
130
-
131
- ### Patch Changes
132
-
133
- - [`051a7da`](https://github.com/swordev/datatruck/commit/051a7da225fcfea1c30a4fbfa8aea1b8f5538367) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix dist files
134
-
135
- ## 0.0.2
136
-
137
- ### Patch Changes
138
-
139
- - [`0911351`](https://github.com/swordev/datatruck/commit/09113517e1a77f2d2a1e19e4c3d9af7da1e28415) Thanks [@juanrgm](https://github.com/juanrgm)! - Publish docker image