@datatruck/cli 0.4.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,7 @@ class BackupAction {
23
23
  packageNames: this.options.packageNames,
24
24
  repositoryNames: this.options.repositoryNames,
25
25
  repositoryTypes: this.options.repositoryTypes,
26
+ sourceAction: "backup",
26
27
  });
27
28
  packages = (0, config_util_1.resolvePackages)(packages, {
28
29
  snapshotId: snapshot.id,
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InitAction = void 0;
4
4
  const RepositoryFactory_1 = require("../Factory/RepositoryFactory");
5
+ const config_util_1 = require("../util/datatruck/config-util");
5
6
  class InitAction {
6
7
  constructor(config, options) {
7
8
  this.config = config;
@@ -10,6 +11,8 @@ class InitAction {
10
11
  async exec() {
11
12
  const result = [];
12
13
  for (const repo of this.config.repositories) {
14
+ if (!(0, config_util_1.filterRepository)(repo, "init"))
15
+ continue;
13
16
  if (this.options.repositoryNames &&
14
17
  !this.options.repositoryNames.includes(repo.name))
15
18
  continue;
@@ -24,7 +24,7 @@ class PruneAction {
24
24
  }
25
25
  async exec() {
26
26
  const snapshotsAction = new SnapshotsAction_1.SnapshotsAction(this.config, this.options);
27
- const snapshots = await snapshotsAction.exec();
27
+ const snapshots = await snapshotsAction.exec("prune");
28
28
  const snapshotsDeleted = [];
29
29
  const reasons = {};
30
30
  const inputFilter = {
@@ -203,7 +203,10 @@ class RestoreAction {
203
203
  const snapshots = this.groupSnapshots(await this.findSnapshots());
204
204
  if (!snapshots.length)
205
205
  throw new AppError_1.AppError("None snapshot found");
206
- let packages = (0, config_util_1.filterPackages)(this.config, this.options);
206
+ let packages = (0, config_util_1.filterPackages)(this.config, {
207
+ ...this.options,
208
+ sourceAction: "restore",
209
+ });
207
210
  packages = (0, config_util_1.resolvePackages)(packages, {
208
211
  snapshotId: this.options.snapshotId,
209
212
  snapshotDate: snapshots[0].date,
@@ -1,4 +1,5 @@
1
1
  import type { ConfigType } from "../Config/Config";
2
+ import { RepositoryConfigEnabledActionType } from "../Config/RepositoryConfig";
2
3
  import { SnapshotResultType } from "../Repository/RepositoryAbstract";
3
4
  import { IfRequireKeys } from "../util/ts-util";
4
5
  export declare type SnapshotGroupByType = keyof Pick<SnapshotExtendedType, "packageName" | "repositoryName" | "repositoryType">;
@@ -27,5 +28,5 @@ export declare class SnapshotsAction<TRequired extends boolean = true> {
27
28
  readonly config: ConfigType;
28
29
  readonly options: IfRequireKeys<TRequired, SnapshotsActionOptionsType>;
29
30
  constructor(config: ConfigType, options: IfRequireKeys<TRequired, SnapshotsActionOptionsType>);
30
- exec(): Promise<SnapshotExtendedType[]>;
31
+ exec(sourceAction?: RepositoryConfigEnabledActionType): Promise<SnapshotExtendedType[]>;
31
32
  }
@@ -2,15 +2,20 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SnapshotsAction = void 0;
4
4
  const RepositoryFactory_1 = require("../Factory/RepositoryFactory");
5
+ const config_util_1 = require("../util/datatruck/config-util");
5
6
  const snapshot_util_1 = require("../util/datatruck/snapshot-util");
6
7
  class SnapshotsAction {
7
8
  constructor(config, options) {
8
9
  this.config = config;
9
10
  this.options = options;
10
11
  }
11
- async exec() {
12
+ async exec(sourceAction) {
13
+ if (!sourceAction)
14
+ sourceAction = "snapshots";
12
15
  let result = [];
13
16
  for (const repo of this.config.repositories) {
17
+ if (!(0, config_util_1.filterRepository)(repo, sourceAction))
18
+ continue;
14
19
  if (this.options.repositoryNames &&
15
20
  !this.options.repositoryNames.includes(repo.name))
16
21
  continue;
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @datatruck/cli
2
2
 
3
+ ## 0.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`0ba6229`](https://github.com/swordev/datatruck/commit/0ba6229348c109a59783e72242ab7c0e61f25e36) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix progress bar in restic repository
8
+
9
+ ## 0.6.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`0c6877d`](https://github.com/swordev/datatruck/commit/0c6877d189761e75dd434b0a8d72b71621d024de) Thanks [@juanrgm](https://github.com/juanrgm)! - Show more progress stats
14
+
15
+ * [`751e1f6`](https://github.com/swordev/datatruck/commit/751e1f6d6b33d3fa96eb40d998fdd140ce0e3875) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `fileCopyConcurrency` option
16
+
17
+ - [`05487e6`](https://github.com/swordev/datatruck/commit/05487e6a33f875a3afb7ff0815b16da6f2a41301) Thanks [@juanrgm](https://github.com/juanrgm)! - Parse InnoDB error in `MariadbTask` to avoid infinite wait
18
+
19
+ ### Patch Changes
20
+
21
+ - [`b62a6f8`](https://github.com/swordev/datatruck/commit/b62a6f8a82409339afd65d4f96476eb57bbfb5a2) Thanks [@juanrgm](https://github.com/juanrgm)! - Resolve target/restore path in local repository
22
+
23
+ ## 0.5.0
24
+
25
+ ### Minor Changes
26
+
27
+ - [`5aeb2af`](https://github.com/swordev/datatruck/commit/5aeb2afb96692e00bdba501b58df9cc0e02dceaa) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `enabled` option to repository config
28
+
29
+ * [`75de836`](https://github.com/swordev/datatruck/commit/75de8369356cf02ed3fd5c58b1f9bea66432cda8) Thanks [@juanrgm](https://github.com/juanrgm)! - Allow restic password without file
30
+
3
31
  ## 0.4.0
4
32
 
5
33
  ### Minor Changes
@@ -4,8 +4,12 @@ import { ResticRepositoryConfigType, resticRepositoryName } from "../Repository/
4
4
  import type { JSONSchema7 } from "json-schema";
5
5
  export declare const repositoryConfigDefinition: JSONSchema7;
6
6
  export declare type RepositoryConfigTypeType = RepositoryConfigType["type"];
7
+ export declare type RepositoryConfigEnabledActionType = "backup" | "init" | "prune" | "restore" | "snapshots";
7
8
  export declare type RepositoryConfigType = {
8
9
  name: string;
10
+ enabled?: boolean | {
11
+ [K in "defaults" | RepositoryConfigEnabledActionType]?: boolean;
12
+ };
9
13
  } & ({
10
14
  type: typeof resticRepositoryName;
11
15
  config: ResticRepositoryConfigType;
@@ -17,6 +17,25 @@ exports.repositoryConfigDefinition = {
17
17
  properties: {
18
18
  type: { type: "string" },
19
19
  name: { type: "string" },
20
+ enabled: {
21
+ anyOf: [
22
+ {
23
+ type: "boolean",
24
+ },
25
+ {
26
+ type: "object",
27
+ additionalProperties: false,
28
+ properties: {
29
+ defaults: { type: "boolean" },
30
+ backup: { type: "boolean" },
31
+ init: { type: "boolean" },
32
+ prune: { type: "boolean" },
33
+ restore: { type: "boolean" },
34
+ snapshots: { type: "boolean" },
35
+ },
36
+ },
37
+ ],
38
+ },
20
39
  config: {},
21
40
  },
22
41
  anyOf: Object.keys(types).map((type) => ({
@@ -13,7 +13,6 @@ const string_util_1 = require("../util/string-util");
13
13
  const RepositoryAbstract_1 = require("./RepositoryAbstract");
14
14
  const assert_1 = require("assert");
15
15
  const fast_glob_1 = __importDefault(require("fast-glob"));
16
- const fs_extra_1 = require("fs-extra");
17
16
  const promises_1 = require("fs/promises");
18
17
  const micromatch_1 = require("micromatch");
19
18
  const path_1 = require("path");
@@ -62,7 +61,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
62
61
  log: data.options.verbose,
63
62
  });
64
63
  if (await git.canBeInit(this.config.repo)) {
65
- await (0, fs_extra_1.mkdir)(git.options.dir);
64
+ await (0, promises_1.mkdir)(git.options.dir);
66
65
  await git.exec(["init", "--bare", this.config.repo]);
67
66
  }
68
67
  const branchName = this.config.branch ?? "master";
@@ -182,7 +181,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
182
181
  const target = (0, path_1.join)(tmpPath, entry);
183
182
  const dir = (0, path_1.dirname)(target);
184
183
  if (!createdPaths.includes(dir)) {
185
- await (0, fs_extra_1.mkdir)(dir, {
184
+ await (0, promises_1.mkdir)(dir, {
186
185
  recursive: true,
187
186
  });
188
187
  createdPaths.push(dir);
@@ -10,6 +10,10 @@ export declare type MetaDataType = {
10
10
  export declare type LocalRepositoryConfigType = {
11
11
  outPath: string;
12
12
  compress?: boolean;
13
+ /**
14
+ * @default 1
15
+ */
16
+ fileCopyConcurrency?: number;
13
17
  };
14
18
  declare type CompressObjectType = {
15
19
  packs?: {
@@ -16,11 +16,9 @@ const RepositoryAbstract_1 = require("./RepositoryAbstract");
16
16
  const assert_1 = require("assert");
17
17
  const fast_glob_1 = __importDefault(require("fast-glob"));
18
18
  const fs_1 = require("fs");
19
- const fs_extra_1 = require("fs-extra");
20
19
  const promises_1 = require("fs/promises");
21
20
  const micromatch_1 = require("micromatch");
22
21
  const path_1 = require("path");
23
- const path_2 = require("path");
24
22
  const readline_1 = require("readline");
25
23
  exports.localRepositoryName = "local";
26
24
  exports.localRepositoryDefinition = {
@@ -62,6 +60,10 @@ exports.localPackageRepositoryDefinition = {
62
60
  },
63
61
  ],
64
62
  },
63
+ fileCopyConcurrency: {
64
+ type: "integer",
65
+ minimum: 1,
66
+ },
65
67
  },
66
68
  };
67
69
  class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
@@ -111,11 +113,11 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
111
113
  if (data.options.verbose)
112
114
  (0, cli_util_1.logExec)(`Deleting ${snapshotPath}`);
113
115
  if (await (0, fs_util_1.checkDir)(snapshotPath))
114
- await (0, fs_extra_1.rm)(snapshotPath, {
116
+ await (0, promises_1.rm)(snapshotPath, {
115
117
  recursive: true,
116
118
  });
117
119
  if (await (0, fs_util_1.checkFile)(metaPath))
118
- await (0, fs_extra_1.rm)(metaPath);
120
+ await (0, promises_1.rm)(metaPath);
119
121
  }
120
122
  async onSnapshots(data) {
121
123
  if (!(await (0, fs_util_1.checkDir)(this.config.outPath)))
@@ -173,8 +175,7 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
173
175
  snapshotDate: data.snapshot.date,
174
176
  packageName: data.package.name,
175
177
  });
176
- const outPath = (0, path_1.join)(this.config.outPath, snapshotName);
177
- const createdPaths = [];
178
+ const outPath = (0, path_1.resolve)((0, path_1.join)(this.config.outPath, snapshotName));
178
179
  const pkg = data.package;
179
180
  await (0, promises_1.mkdir)(outPath, {
180
181
  recursive: true,
@@ -260,35 +261,26 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
260
261
  }
261
262
  if (data.options.verbose)
262
263
  (0, cli_util_1.logExec)(`Copying files to ${outPath}`);
263
- const reader = (0, readline_1.createInterface)({
264
- input: (0, fs_1.createReadStream)(pathLists.path),
265
- });
266
- for await (const entry of reader) {
267
- const source = (0, path_1.join)(sourcePath, entry);
268
- const target = (0, path_1.join)(outPath, entry);
269
- if (entry.endsWith("/")) {
270
- await (0, promises_1.mkdir)(target, {
271
- recursive: true,
272
- });
273
- }
274
- else {
264
+ await (0, fs_util_1.cpy)({
265
+ input: {
266
+ type: "pathList",
267
+ path: pathLists.path,
268
+ basePath: sourcePath,
269
+ },
270
+ targetPath: outPath,
271
+ concurrency: this.config.fileCopyConcurrency,
272
+ async onPath({ isDir, entryPath }) {
273
+ if (isDir)
274
+ return;
275
275
  currentFiles++;
276
276
  await data.onProgress({
277
277
  total: pathLists.total.all,
278
278
  current: currentFiles,
279
279
  percent: (0, math_util_1.progressPercent)(pathLists.total.all, currentFiles),
280
- step: entry,
280
+ step: entryPath,
281
281
  });
282
- const dir = (0, path_2.dirname)(target);
283
- if (!createdPaths.includes(dir)) {
284
- await (0, promises_1.mkdir)(dir, {
285
- recursive: true,
286
- });
287
- createdPaths.push(dir);
288
- }
289
- await (0, promises_1.copyFile)(source, target);
290
- }
291
- }
282
+ },
283
+ });
292
284
  const metaPath = `${outPath}.json`;
293
285
  const nodePkg = (0, fs_util_1.parsePackageFile)();
294
286
  const meta = {
@@ -303,8 +295,9 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
303
295
  await (0, promises_1.writeFile)(metaPath, LocalRepository.stringifyMetaData(meta));
304
296
  }
305
297
  async onRestore(data) {
306
- const restorePath = data.targetPath ?? data.package.restorePath;
307
- (0, assert_1.ok)(restorePath);
298
+ const relRestorePath = data.targetPath ?? data.package.restorePath;
299
+ (0, assert_1.ok)(relRestorePath);
300
+ const restorePath = (0, path_1.resolve)(relRestorePath);
308
301
  const [snapshot] = await this.onSnapshots({
309
302
  options: {
310
303
  ids: [data.options.snapshotId],
@@ -325,19 +318,27 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
325
318
  }, true);
326
319
  if (data.options.verbose)
327
320
  (0, cli_util_1.logExec)(`Copying files to ${restorePath}`);
328
- await (0, fs_extra_1.copy)(sourcePath, restorePath, {
329
- filter: async (path) => {
330
- const [firstFolder] = (0, path_1.relative)(sourcePath, path).split(path_1.sep);
331
- const isZipFile = firstFolder.startsWith(".") && firstFolder.endsWith(".dd.zip");
321
+ await (0, fs_util_1.cpy)({
322
+ input: {
323
+ type: "glob",
324
+ sourcePath,
325
+ },
326
+ targetPath: restorePath,
327
+ concurrency: this.config.fileCopyConcurrency,
328
+ onPath: async ({ entryPath, entrySourcePath }) => {
329
+ const isRootFile = (0, path_1.basename)(entryPath) === entryPath;
330
+ const isZipFile = isRootFile &&
331
+ entryPath.startsWith(".") &&
332
+ entryPath.endsWith(".dd.zip");
332
333
  await data.onProgress({
333
334
  total: totalFiles,
334
335
  current: Math.max(currentFiles, 0),
335
336
  percent: (0, math_util_1.progressPercent)(totalFiles, Math.max(currentFiles, 0)),
336
- step: (0, path_1.relative)(sourcePath, path),
337
+ step: entryPath,
337
338
  });
338
339
  if (isZipFile) {
339
340
  await (0, zip_util_1.unzip)({
340
- input: path,
341
+ input: entrySourcePath,
341
342
  output: restorePath,
342
343
  verbose: data.options.verbose,
343
344
  onStream: async (stream) => await data.onProgress({
@@ -14,10 +14,10 @@ export declare type SnapshotResultType = SnapshotType & {
14
14
  tags: string[];
15
15
  };
16
16
  export declare type ProgressDataType = {
17
- total: number;
18
- current: number;
19
- percent: number;
20
- step: string;
17
+ total?: number;
18
+ current?: number;
19
+ percent?: number;
20
+ step?: string;
21
21
  stepPercent?: number | null;
22
22
  };
23
23
  export declare type InitDataType = {
@@ -2,7 +2,9 @@ import { RepositoryType } from "../util/ResticUtil";
2
2
  import { RepositoryAbstract, BackupDataType, InitDataType, RestoreDataType, SnapshotsDataType, SnapshotResultType, SnapshotTagObjectType, SnapshotTagEnum, PruneDataType } from "./RepositoryAbstract";
3
3
  import { JSONSchema7 } from "json-schema";
4
4
  export declare type ResticRepositoryConfigType = {
5
- passwordFile: string;
5
+ password: string | {
6
+ path: string;
7
+ };
6
8
  repository: RepositoryType;
7
9
  };
8
10
  export declare type ResticPackageRepositoryConfigType = {};
@@ -12,11 +14,13 @@ export declare const resticPackageRepositoryDefinition: JSONSchema7;
12
14
  export declare class ResticRepository extends RepositoryAbstract<ResticRepositoryConfigType> {
13
15
  static refPrefix: string;
14
16
  protected env: {
15
- RESTIC_PASSWORD_FILE: string;
17
+ RESTIC_PASSWORD?: string;
18
+ RESTIC_PASSWORD_FILE?: string;
16
19
  RESTIC_REPOSITORY: string;
17
20
  };
18
21
  buildEnv(): Promise<{
19
- RESTIC_PASSWORD_FILE: string;
22
+ RESTIC_PASSWORD?: string | undefined;
23
+ RESTIC_PASSWORD_FILE?: string | undefined;
20
24
  RESTIC_REPOSITORY: string;
21
25
  }>;
22
26
  static buildSnapshotTag(name: SnapshotTagEnum, value: string): string;
@@ -18,10 +18,22 @@ const path_1 = require("path");
18
18
  exports.resticRepositoryName = "restic";
19
19
  exports.resticRepositoryDefinition = {
20
20
  type: "object",
21
- required: ["passwordFile", "repository"],
21
+ required: ["password", "repository"],
22
22
  additionalProperties: false,
23
23
  properties: {
24
- passwordFile: { type: "string" },
24
+ password: {
25
+ anyOf: [
26
+ { type: "string" },
27
+ {
28
+ type: "object",
29
+ additionalProperties: false,
30
+ required: ["path"],
31
+ properties: {
32
+ path: { type: "string" },
33
+ },
34
+ },
35
+ ],
36
+ },
25
37
  repository: {
26
38
  type: "object",
27
39
  additionalProperties: false,
@@ -59,7 +71,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
59
71
  if (this.env)
60
72
  return this.env;
61
73
  return (this.env = {
62
- RESTIC_PASSWORD_FILE: (0, path_1.resolve)(this.config.passwordFile),
74
+ ...(typeof this.config.password === "string"
75
+ ? { RESTIC_PASSWORD: this.config.password }
76
+ : { RESTIC_PASSWORD_FILE: (0, path_1.resolve)(this.config.password.path) }),
63
77
  RESTIC_REPOSITORY: await ResticUtil_1.ResticUtil.formatRepository(this.config.repository),
64
78
  });
65
79
  }
@@ -176,6 +190,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
176
190
  });
177
191
  if (data.options.verbose)
178
192
  (0, cli_util_1.logExec)(`Writing paths lists`);
193
+ await data.onProgress({
194
+ step: "Writing excluded paths list...",
195
+ });
179
196
  gitignorePath = await (0, fs_util_1.writeGitIgnoreList)({
180
197
  paths: stream,
181
198
  });
@@ -183,12 +200,21 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
183
200
  if (data.options.tags?.some((tag) => tag.startsWith(ResticRepository.refPrefix)))
184
201
  throw new AppError_1.AppError(`Tag prefix is not allowed`);
185
202
  const packageTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.PACKAGE, data.package.name);
203
+ await data.onProgress({
204
+ step: "Fetching last snapshot...",
205
+ });
186
206
  const [lastSnapshot] = await restic.snapshots({
187
207
  json: true,
188
208
  tags: [packageTag],
189
209
  latest: 1,
190
210
  });
191
211
  const nodePkg = (0, fs_util_1.parsePackageFile)();
212
+ let lastProgress;
213
+ let totalFilesChanges = 0;
214
+ const totalFilesChangesLimit = 10;
215
+ await data.onProgress({
216
+ step: "Executing backup action...",
217
+ });
192
218
  await restic.backup({
193
219
  cwd: sourcePath,
194
220
  paths: ["."],
@@ -209,22 +235,31 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
209
235
  ],
210
236
  onStream: async (streamData) => {
211
237
  if (streamData.message_type === "status") {
212
- await data.onProgress({
213
- total: Number((streamData.total_bytes / 1024 / 1024).toFixed(2)),
214
- current: streamData.bytes_done
215
- ? Number((streamData.bytes_done / 1024 / 1024).toFixed(2))
238
+ let showProgressBar = false;
239
+ if (totalFilesChanges > totalFilesChangesLimit) {
240
+ showProgressBar = true;
241
+ }
242
+ else if (lastProgress?.total !== streamData.total_files) {
243
+ totalFilesChanges = 0;
244
+ }
245
+ else {
246
+ totalFilesChanges++;
247
+ }
248
+ await data.onProgress((lastProgress = {
249
+ total: Math.max(lastProgress?.total || 0, streamData.total_files),
250
+ current: Math.max(lastProgress?.current || 0, streamData.files_done ?? 0),
251
+ percent: showProgressBar
252
+ ? Number((streamData.percent_done * 100).toFixed(2))
216
253
  : 0,
217
- percent: Number((streamData.percent_done * 100).toFixed(2)),
218
254
  step: streamData.current_files?.join(", ") ?? "-",
219
- });
255
+ }));
220
256
  }
221
257
  },
222
258
  });
223
259
  await data.onProgress({
224
- current: 100,
260
+ total: lastProgress?.total || 0,
261
+ current: lastProgress?.total || 0,
225
262
  percent: 100,
226
- step: "",
227
- total: 100,
228
263
  });
229
264
  }
230
265
  async onRestore(data) {
@@ -82,18 +82,19 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
82
82
  const parts = [
83
83
  `${padding}${message.textPrefix} [${(0, chalk_1.grey)(sessionId)}] ${message.text}`,
84
84
  badges,
85
- ...(haveProgressBar
86
- ? [
87
- (0, chalk_1.cyan)((0, cli_util_1.renderProgressBar)(message.progressPercent ?? 0, 10)),
88
- `${message.progressPercent?.toFixed(2)}%`,
89
- `${message.progressCurrent}/${message.progressTotal}`,
90
- message.progressStep,
91
- `${message.progressStepPercent
92
- ? (0, chalk_1.cyan)((0, cli_util_1.renderProgressBar)(message.progressStepPercent ?? 0, 10))
93
- : ""}`,
94
- ].filter((v) => !!v?.length)
95
- : []),
96
85
  ];
86
+ if (typeof message.progressPercent === "number") {
87
+ parts.push((0, chalk_1.cyan)((0, cli_util_1.renderProgressBar)(message.progressPercent ?? 0, 10)), `${message.progressPercent?.toFixed(2)}%`);
88
+ }
89
+ if (typeof message.progressCurrent === "number" ||
90
+ typeof message.progressTotal === "number") {
91
+ parts.push(`${message.progressCurrent ?? "?"}/${message.progressTotal ?? "?"}`);
92
+ }
93
+ if (typeof message.progressStep === "string")
94
+ parts.push(message.progressStep);
95
+ if (typeof message.progressStepPercent === "number") {
96
+ parts.push((0, chalk_1.cyan)((0, cli_util_1.renderProgressBar)(message.progressStepPercent ?? 0, 10)));
97
+ }
97
98
  return parts.join(` ${sep} `);
98
99
  }
99
100
  async onWrite(data) {
package/Task/GitTask.d.ts CHANGED
@@ -18,6 +18,10 @@ export declare type GitTaskConfigType = {
18
18
  * @default true
19
19
  */
20
20
  includeConfig?: boolean;
21
+ /**
22
+ * @default 1
23
+ */
24
+ fileCopyConcurrency?: number;
21
25
  };
22
26
  export declare const gitTaskName = "git";
23
27
  export declare const gitTaskDefinition: JSONSchema7;
package/Task/GitTask.js CHANGED
@@ -9,7 +9,6 @@ const process_util_1 = require("../util/process-util");
9
9
  const TaskAbstract_1 = require("./TaskAbstract");
10
10
  const assert_1 = require("assert");
11
11
  const fs_1 = require("fs");
12
- const fs_extra_1 = require("fs-extra");
13
12
  const promises_1 = require("fs/promises");
14
13
  const micromatch_1 = require("micromatch");
15
14
  const path_1 = require("path");
@@ -49,6 +48,10 @@ exports.gitTaskDefinition = {
49
48
  includeConfig: {
50
49
  type: "boolean",
51
50
  },
51
+ fileCopyConcurrency: {
52
+ type: "integer",
53
+ minimum: 1,
54
+ },
52
55
  },
53
56
  };
54
57
  class GitTask extends TaskAbstract_1.TaskAbstract {
@@ -69,6 +72,9 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
69
72
  (0, assert_1.ok)(typeof targetPath === "string");
70
73
  // Bundle
71
74
  const bundlePath = (0, path_1.join)(targetPath, "repo.bundle");
75
+ await data.onProgress({
76
+ step: "Creating bundle...",
77
+ });
72
78
  await (0, process_util_1.exec)(this.command, ["bundle", "create", bundlePath, "--all"], {
73
79
  cwd: path,
74
80
  }, {
@@ -152,40 +158,28 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
152
158
  for (const option of lsFilesConfig) {
153
159
  if (!option.include)
154
160
  continue;
155
- const createdPaths = [];
156
161
  const outPath = (0, path_1.join)(targetPath, `repo.${option.name}`);
157
162
  await (0, fs_util_1.mkdirIfNotExists)(outPath);
158
163
  if (data.options.verbose)
159
164
  (0, cli_util_1.logExec)(`Copying ${option.name} files to ${outPath}`);
160
- const reader = (0, readline_1.createInterface)({
161
- input: (0, fs_1.createReadStream)(option.pathsPath),
162
- });
163
- for await (const entry of reader) {
164
- const source = (0, path_1.join)(path, entry);
165
- const target = (0, path_1.join)(outPath, entry);
166
- if (entry.endsWith("/")) {
167
- await (0, promises_1.mkdir)(target, {
168
- recursive: true,
169
- });
170
- }
171
- else {
165
+ await (0, fs_util_1.cpy)({
166
+ input: {
167
+ type: "pathList",
168
+ path: option.pathsPath,
169
+ basePath: path,
170
+ },
171
+ targetPath: outPath,
172
+ concurrency: this.config.fileCopyConcurrency,
173
+ onPath: async ({ entryPath }) => {
172
174
  currentFiles++;
173
175
  await data.onProgress({
174
176
  total,
175
177
  current: currentFiles,
176
178
  percent: (0, math_util_1.progressPercent)(total, currentFiles),
177
- step: entry,
179
+ step: entryPath,
178
180
  });
179
- const dir = (0, path_1.dirname)(target);
180
- if (!createdPaths.includes(dir)) {
181
- await (0, promises_1.mkdir)(dir, {
182
- recursive: true,
183
- });
184
- createdPaths.push(dir);
185
- }
186
- await (0, promises_1.copyFile)(source, target);
187
- }
188
- }
181
+ },
182
+ });
189
183
  await (0, promises_1.rm)(option.pathsPath);
190
184
  }
191
185
  }
@@ -235,10 +229,15 @@ class GitTask extends TaskAbstract_1.TaskAbstract {
235
229
  if (await (0, fs_util_1.checkDir)(sourcePath)) {
236
230
  if (data.options.verbose)
237
231
  (0, cli_util_1.logExec)(`Copying ${name} files to ${restorePath}`);
238
- await (0, fs_extra_1.copy)(sourcePath, restorePath, {
239
- filter: async (path) => {
240
- await incrementProgress((0, path_1.relative)(sourcePath, path));
241
- return true;
232
+ await (0, fs_util_1.cpy)({
233
+ input: {
234
+ type: "glob",
235
+ sourcePath,
236
+ },
237
+ targetPath: restorePath,
238
+ concurrency: this.config.fileCopyConcurrency,
239
+ onPath: async ({ entryPath }) => {
240
+ await incrementProgress(entryPath);
242
241
  },
243
242
  });
244
243
  }
@@ -83,21 +83,30 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
83
83
  await (0, fs_util_1.forEachFile)(sourcePath, () => {
84
84
  total++;
85
85
  });
86
- const onData = async (lines) => {
87
- const regex = /\[\d{1,}\] \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} Copying (.+) to/;
88
- let path = lines
89
- .split(/\r?\n/)
90
- .reduce((result, line) => {
91
- const matches = regex.exec(line);
92
- if (matches) {
93
- current++;
94
- result.push(matches[1]);
86
+ let childProcess;
87
+ const onData = async (strLines) => {
88
+ const paths = [];
89
+ const pathRegex = /\[\d{1,}\] \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} Copying (.+) to/;
90
+ const lines = strLines.split(/\r?\n/);
91
+ let fatalError = false;
92
+ for (const line of lines) {
93
+ if (line.includes("[ERROR] InnoDB: Unsupported redo log format.") ||
94
+ line.includes("Error: cannot read redo log header")) {
95
+ fatalError = true;
95
96
  }
96
- return result;
97
- }, [])
98
- .pop();
99
- if (path) {
100
- path = (0, posix_1.normalize)(path);
97
+ else {
98
+ const matches = pathRegex.exec(line);
99
+ if (matches) {
100
+ current++;
101
+ paths.push(matches[1]);
102
+ }
103
+ }
104
+ }
105
+ if (fatalError) {
106
+ childProcess.kill();
107
+ }
108
+ else if (paths.length) {
109
+ const path = (0, posix_1.normalize)(paths[0]);
101
110
  await data.onProgress({
102
111
  current,
103
112
  percent: (0, math_util_1.progressPercent)(total, current),
@@ -108,6 +117,9 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
108
117
  };
109
118
  await (0, process_util_1.exec)(command, args, undefined, {
110
119
  log: this.verbose,
120
+ onSpawn: (p) => {
121
+ childProcess = p;
122
+ },
111
123
  stdout: {
112
124
  onData,
113
125
  },
@@ -117,7 +129,7 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
117
129
  });
118
130
  await (0, process_util_1.exec)(command, [`--prepare`, `--target-dir=${targetPath}`], undefined, {
119
131
  log: this.verbose,
120
- stderr: { onData: async () => { } },
132
+ stderr: { onData: () => { } },
121
133
  });
122
134
  }
123
135
  async onRestore(data) {
package/Task/MssqlTask.js CHANGED
@@ -8,7 +8,6 @@ const fs_util_1 = require("../util/fs-util");
8
8
  const process_util_1 = require("../util/process-util");
9
9
  const TaskAbstract_1 = require("./TaskAbstract");
10
10
  const assert_1 = require("assert");
11
- const fs_extra_1 = require("fs-extra");
12
11
  const promises_1 = require("fs/promises");
13
12
  const micromatch_1 = require("micromatch");
14
13
  const path_1 = require("path");
@@ -85,7 +84,7 @@ class MssqlTask extends TaskAbstract_1.TaskAbstract {
85
84
  const restorePath = data.package.restorePath;
86
85
  (0, assert_1.ok)(typeof restorePath === "string");
87
86
  await (0, fs_util_1.mkdirIfNotExists)(restorePath);
88
- const files = await (0, fs_extra_1.readdir)(restorePath);
87
+ const files = await (0, promises_1.readdir)(restorePath);
89
88
  for (const file of files) {
90
89
  if (!file.endsWith(MssqlTask.SUFFIX))
91
90
  continue;
@@ -3,10 +3,10 @@ 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;
6
+ total?: number;
7
+ current?: number;
8
+ percent?: number;
9
+ step?: string;
10
10
  stepPercent?: number;
11
11
  };
12
12
  export declare type BackupDataType = {
@@ -20,6 +20,37 @@
20
20
  "name": {
21
21
  "type": "string"
22
22
  },
23
+ "enabled": {
24
+ "anyOf": [
25
+ {
26
+ "type": "boolean"
27
+ },
28
+ {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "properties": {
32
+ "defaults": {
33
+ "type": "boolean"
34
+ },
35
+ "backup": {
36
+ "type": "boolean"
37
+ },
38
+ "init": {
39
+ "type": "boolean"
40
+ },
41
+ "prune": {
42
+ "type": "boolean"
43
+ },
44
+ "restore": {
45
+ "type": "boolean"
46
+ },
47
+ "snapshots": {
48
+ "type": "boolean"
49
+ }
50
+ }
51
+ }
52
+ ]
53
+ },
23
54
  "config": {}
24
55
  },
25
56
  "anyOf": [
@@ -456,19 +487,39 @@
456
487
  }
457
488
  }
458
489
  ]
490
+ },
491
+ "fileCopyConcurrency": {
492
+ "type": "integer",
493
+ "minimum": 1
459
494
  }
460
495
  }
461
496
  },
462
497
  "restic-repository": {
463
498
  "type": "object",
464
499
  "required": [
465
- "passwordFile",
500
+ "password",
466
501
  "repository"
467
502
  ],
468
503
  "additionalProperties": false,
469
504
  "properties": {
470
- "passwordFile": {
471
- "type": "string"
505
+ "password": {
506
+ "anyOf": [
507
+ {
508
+ "type": "string"
509
+ },
510
+ {
511
+ "type": "object",
512
+ "additionalProperties": false,
513
+ "required": [
514
+ "path"
515
+ ],
516
+ "properties": {
517
+ "path": {
518
+ "type": "string"
519
+ }
520
+ }
521
+ }
522
+ ]
472
523
  },
473
524
  "repository": {
474
525
  "type": "object",
@@ -568,6 +619,10 @@
568
619
  },
569
620
  "includeConfig": {
570
621
  "type": "boolean"
622
+ },
623
+ "fileCopyConcurrency": {
624
+ "type": "integer",
625
+ "minimum": 1
571
626
  }
572
627
  }
573
628
  },
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.4.0",
3
+ "version": "0.6.1",
4
4
  "dependencies": {
5
5
  "ajv": "^8.11.0",
6
+ "async": "^3.2.4",
6
7
  "chalk": "^4.1.2",
7
8
  "cli-table3": "^0.6.2",
8
9
  "commander": "^9.2.0",
9
10
  "dayjs": "^1.11.2",
10
11
  "fast-glob": "^3.2.11",
11
- "fs-extra": "^10.1.0",
12
12
  "micromatch": "^4.0.5",
13
13
  "sqlite": "^4.1.1",
14
14
  "sqlite3": "^5.0.8"
package/util/GitUtil.js CHANGED
@@ -3,7 +3,7 @@ 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 fs_extra_1 = require("fs-extra");
6
+ const promises_1 = require("fs/promises");
7
7
  class GitUtil {
8
8
  constructor(options) {
9
9
  this.options = options;
@@ -16,7 +16,7 @@ class GitUtil {
16
16
  }
17
17
  async canBeInit(repo) {
18
18
  return ((0, fs_util_1.isLocalDir)(repo) &&
19
- (!(await (0, fs_util_1.checkDir)(repo)) || !(await (0, fs_extra_1.readdir)(repo)).length));
19
+ (!(await (0, fs_util_1.checkDir)(repo)) || !(await (0, promises_1.readdir)(repo)).length));
20
20
  }
21
21
  async clone(options) {
22
22
  return await this.exec([
@@ -84,7 +84,7 @@ export declare class ResticUtil {
84
84
  excludeFile?: string[];
85
85
  parent?: string;
86
86
  allowEmptySnapshot?: boolean;
87
- onStream?: (data: BackupStreamType) => Promise<void>;
87
+ onStream?: (data: BackupStreamType) => void;
88
88
  }): Promise<ExecResultType>;
89
89
  restore(options: {
90
90
  id: string;
@@ -4,7 +4,6 @@ exports.ResticUtil = void 0;
4
4
  const fs_util_1 = require("./fs-util");
5
5
  const process_util_1 = require("./process-util");
6
6
  const string_util_1 = require("./string-util");
7
- const fs_extra_1 = require("fs-extra");
8
7
  const promises_1 = require("fs/promises");
9
8
  const path_1 = require("path");
10
9
  class ResticUtil {
@@ -20,7 +19,7 @@ class ResticUtil {
20
19
  if (input.passwordFile)
21
20
  input = {
22
21
  ...input,
23
- password: (await (0, fs_extra_1.readFile)(input.passwordFile)).toString(),
22
+ password: (await (0, promises_1.readFile)(input.passwordFile)).toString(),
24
23
  };
25
24
  return `${input.backend}:${(0, string_util_1.formatUri)(input, hidePassword)}`;
26
25
  }
@@ -116,7 +115,7 @@ class ResticUtil {
116
115
  },
117
116
  stdout: {
118
117
  ...(options.onStream && {
119
- onData: async (data) => {
118
+ onData: (data) => {
120
119
  for (const rawLine of data.split("\n")) {
121
120
  const line = rawLine.trim();
122
121
  if (line.startsWith("{") && line.endsWith("}")) {
@@ -126,7 +125,7 @@ class ResticUtil {
126
125
  }
127
126
  catch (error) { }
128
127
  if (parsedLine)
129
- await options.onStream?.(parsedLine);
128
+ options.onStream?.(parsedLine);
130
129
  }
131
130
  }
132
131
  },
@@ -1,10 +1,13 @@
1
1
  import { ConfigType } from "../../Config/Config";
2
2
  import type { PackageConfigType } from "../../Config/PackageConfig";
3
- export declare function findRepositoryOrFail(config: ConfigType, repositoryName: string): import("../../Config/RepositoryConfig").RepositoryConfigType;
3
+ import { RepositoryConfigEnabledActionType, RepositoryConfigType } from "../../Config/RepositoryConfig";
4
+ export declare function findRepositoryOrFail(config: ConfigType, repositoryName: string): RepositoryConfigType;
5
+ export declare function filterRepository(repository: RepositoryConfigType, action?: RepositoryConfigEnabledActionType): boolean;
4
6
  export declare function filterPackages(config: ConfigType, options: {
5
7
  packageNames?: string[];
6
8
  repositoryNames?: string[];
7
9
  repositoryTypes?: string[];
10
+ sourceAction?: RepositoryConfigEnabledActionType;
8
11
  }): PackageConfigType[];
9
12
  declare type ResolvePackagePathParamsType = ResolvePackageParamsType & {
10
13
  packageName: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.params = exports.dbNameParams = exports.pkgRestorePathParams = exports.pkgExcludeParams = exports.pkgIncludeParams = exports.pkgPathParams = exports.resolvePackages = exports.resolvePackage = exports.resolveDatabaseName = exports.resolvePackagePath = exports.filterPackages = exports.findRepositoryOrFail = void 0;
3
+ exports.params = exports.dbNameParams = exports.pkgRestorePathParams = exports.pkgExcludeParams = exports.pkgIncludeParams = exports.pkgPathParams = exports.resolvePackages = exports.resolvePackage = exports.resolveDatabaseName = exports.resolvePackagePath = exports.filterPackages = exports.filterRepository = exports.findRepositoryOrFail = void 0;
4
4
  const AppError_1 = require("../../Error/AppError");
5
5
  const fs_util_1 = require("../fs-util");
6
6
  const string_util_1 = require("../string-util");
@@ -12,6 +12,14 @@ function findRepositoryOrFail(config, repositoryName) {
12
12
  return repo;
13
13
  }
14
14
  exports.findRepositoryOrFail = findRepositoryOrFail;
15
+ function filterRepository(repository, action) {
16
+ const enabled = repository.enabled ?? true;
17
+ if (typeof enabled === "boolean")
18
+ return enabled;
19
+ const defaults = enabled["defaults"] ?? true;
20
+ return action ? enabled[action] ?? defaults : defaults;
21
+ }
22
+ exports.filterRepository = filterRepository;
15
23
  function filterPackages(config, options) {
16
24
  const packagePatterns = (0, string_util_1.makePathPatterns)(options.packageNames);
17
25
  return config.packages
@@ -19,6 +27,8 @@ function filterPackages(config, options) {
19
27
  pkg = Object.assign({}, pkg);
20
28
  pkg.repositoryNames = (pkg.repositoryNames ?? []).filter((name) => {
21
29
  const repo = findRepositoryOrFail(config, name);
30
+ if (!filterRepository(repo, options?.sourceAction))
31
+ return false;
22
32
  return ((!options.repositoryNames ||
23
33
  options.repositoryNames.includes(name)) &&
24
34
  (!options.repositoryTypes ||
package/util/fs-util.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ import { Interface } from "readline";
2
3
  export declare function isLocalDir(path: string): boolean;
3
4
  export declare function isDirEmpty(path: string): Promise<boolean>;
4
5
  export declare function mkdirIfNotExists(path: string): Promise<string>;
@@ -44,3 +45,35 @@ export declare function writePathLists(options: {
44
45
  multipleStats: Record<string, number>;
45
46
  };
46
47
  }>;
48
+ export declare function cpy(options: {
49
+ input: {
50
+ type: "glob";
51
+ sourcePath: string;
52
+ include?: string[];
53
+ exclude?: string[];
54
+ } | {
55
+ type: "stream";
56
+ basePath: string;
57
+ value: Interface;
58
+ } | {
59
+ type: "pathList";
60
+ path: string;
61
+ basePath: string;
62
+ };
63
+ targetPath: string;
64
+ /**
65
+ * @default 1
66
+ */
67
+ concurrency?: number;
68
+ onPath?: (data: {
69
+ isDir: boolean;
70
+ entryPath: string;
71
+ entrySourcePath: string;
72
+ entryTargetPath: string;
73
+ stats: {
74
+ paths: number;
75
+ files: number;
76
+ dirs: number;
77
+ };
78
+ }) => Promise<boolean | void>;
79
+ }): Promise<void>;
package/util/fs-util.js CHANGED
@@ -3,17 +3,19 @@ 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.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.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
+ const async_1 = require("async");
9
10
  const crypto_1 = require("crypto");
11
+ const fast_glob_1 = __importDefault(require("fast-glob"));
10
12
  const fs_1 = require("fs");
11
13
  const fs_2 = require("fs");
12
- const fs_extra_1 = require("fs-extra");
13
14
  const promises_1 = require("fs/promises");
14
15
  const micromatch_1 = require("micromatch");
15
16
  const path_1 = require("path");
16
17
  const path_2 = require("path");
18
+ const readline_1 = require("readline");
17
19
  function isLocalDir(path) {
18
20
  return /^[\/\.]|([A-Z]:)/i.test(path);
19
21
  }
@@ -25,7 +27,7 @@ async function isDirEmpty(path) {
25
27
  exports.isDirEmpty = isDirEmpty;
26
28
  async function mkdirIfNotExists(path) {
27
29
  try {
28
- await (0, fs_extra_1.mkdir)(path, {
30
+ await (0, promises_1.mkdir)(path, {
29
31
  recursive: true,
30
32
  });
31
33
  }
@@ -128,7 +130,7 @@ function tmpDir(prefix, id) {
128
130
  exports.tmpDir = tmpDir;
129
131
  async function mkTmpDir(prefix, id) {
130
132
  const path = tmpDir(prefix, id);
131
- await (0, fs_extra_1.mkdir)(path, { recursive: true });
133
+ await (0, promises_1.mkdir)(path, { recursive: true });
132
134
  return path;
133
135
  }
134
136
  exports.mkTmpDir = mkTmpDir;
@@ -313,3 +315,70 @@ async function writePathLists(options) {
313
315
  };
314
316
  }
315
317
  exports.writePathLists = writePathLists;
318
+ async function cpy(options) {
319
+ const stats = { paths: 0, files: 0, dirs: 0 };
320
+ const dirs = new Set();
321
+ const makeRecursiveDir = async (path) => {
322
+ if (!dirs.has(path)) {
323
+ stats.paths++;
324
+ stats.dirs++;
325
+ await (0, promises_1.mkdir)(path, {
326
+ recursive: true,
327
+ });
328
+ dirs.add(path);
329
+ }
330
+ };
331
+ const task = async (rawEntryPath, basePath) => {
332
+ const isDir = rawEntryPath.endsWith("/");
333
+ const entryPath = (0, path_1.normalize)(rawEntryPath);
334
+ const entrySourcePath = (0, path_1.resolve)((0, path_1.join)(basePath, rawEntryPath));
335
+ const entryTargetPath = (0, path_1.resolve)((0, path_1.join)(options.targetPath, rawEntryPath));
336
+ const onPathResult = await options?.onPath?.({
337
+ isDir,
338
+ entryPath,
339
+ entrySourcePath,
340
+ entryTargetPath,
341
+ stats,
342
+ });
343
+ if (onPathResult === false) {
344
+ return;
345
+ }
346
+ else if (isDir) {
347
+ await makeRecursiveDir(entryTargetPath);
348
+ }
349
+ else {
350
+ const dir = (0, path_1.dirname)(entryTargetPath);
351
+ await makeRecursiveDir(dir);
352
+ stats.files++;
353
+ await (0, promises_1.cp)(entrySourcePath, entryTargetPath);
354
+ }
355
+ };
356
+ const { input } = options;
357
+ if (input.type === "glob") {
358
+ const stream = await (0, fast_glob_1.default)(input.include || ["**"], {
359
+ cwd: input.sourcePath,
360
+ ignore: input.exclude,
361
+ dot: true,
362
+ onlyFiles: false,
363
+ markDirectories: true,
364
+ });
365
+ await (0, async_1.eachLimit)(stream, options.concurrency ?? 1, async (entryPath) => await task(entryPath, input.sourcePath));
366
+ }
367
+ else if (input.type === "stream") {
368
+ await (0, async_1.eachLimit)(input.value, options.concurrency ?? 1, async (entryPath) => await task(entryPath, input.basePath));
369
+ }
370
+ else if (input.type === "pathList") {
371
+ const stream = (0, readline_1.createInterface)({
372
+ input: (0, fs_1.createReadStream)(input.path),
373
+ });
374
+ await cpy({
375
+ ...options,
376
+ input: {
377
+ type: "stream",
378
+ value: stream,
379
+ basePath: input.basePath,
380
+ },
381
+ });
382
+ }
383
+ }
384
+ exports.cpy = cpy;
@@ -23,11 +23,11 @@ export interface ExecSettingsInterface {
23
23
  onSpawn?: (p: ChildProcess) => void;
24
24
  stdout?: {
25
25
  save?: boolean;
26
- onData?: (data: string) => Promise<void>;
26
+ onData?: (data: string) => void;
27
27
  };
28
28
  stderr?: {
29
29
  save?: boolean;
30
- onData?: (data: string) => Promise<void>;
30
+ onData?: (data: string) => void;
31
31
  toExitCode?: boolean;
32
32
  };
33
33
  onExitCodeError?: (data: ExecResultType, error: Error) => Error | false;
@@ -127,7 +127,7 @@ async function exec(command, argv = [], options = null, settings = {}) {
127
127
  if (log.stdout || settings.stdout) {
128
128
  if (!p.stdout)
129
129
  throw new Error(`stdout is not defined`);
130
- p.stdout.on("data", async (data) => {
130
+ p.stdout.on("data", (data) => {
131
131
  if (log.stdout)
132
132
  logExecStdout({
133
133
  data: data.toString(),
@@ -137,13 +137,13 @@ async function exec(command, argv = [], options = null, settings = {}) {
137
137
  if (settings.stdout?.save)
138
138
  spawnData.stdout += data.toString();
139
139
  if (settings.stdout?.onData)
140
- await settings.stdout.onData(data.toString());
140
+ settings.stdout.onData(data.toString());
141
141
  });
142
142
  }
143
143
  if (log.stderr || settings.stderr) {
144
144
  if (!p.stderr)
145
145
  throw new Error(`stderr is not defined`);
146
- p.stderr.on("data", async (data) => {
146
+ p.stderr.on("data", (data) => {
147
147
  if (log.stderr)
148
148
  logExecStdout({
149
149
  data: data.toString(),
@@ -153,7 +153,7 @@ async function exec(command, argv = [], options = null, settings = {}) {
153
153
  if (settings.stderr?.save || settings.stderr?.toExitCode)
154
154
  spawnData.stderr += data.toString();
155
155
  if (settings.stderr?.onData)
156
- await settings.stderr.onData(data.toString());
156
+ settings.stderr.onData(data.toString());
157
157
  });
158
158
  }
159
159
  p.on("error", (error) => (spawnError = error)).on("close", (exitCode) => {
@@ -26,7 +26,7 @@ export interface ZipDataType {
26
26
  includeList?: string;
27
27
  excludeList?: string;
28
28
  verbose?: boolean;
29
- onStream?: (data: ZipStreamDataType) => Promise<void>;
29
+ onStream?: (data: ZipStreamDataType) => void;
30
30
  }
31
31
  export interface UnzipDataType {
32
32
  command?: string;
@@ -34,7 +34,7 @@ export interface UnzipDataType {
34
34
  files?: (ZipDataFilterType | string)[];
35
35
  output: string;
36
36
  verbose?: boolean;
37
- onStream?: (data: UnzipStreamDataType) => Promise<void>;
37
+ onStream?: (data: UnzipStreamDataType) => void;
38
38
  }
39
39
  export declare type UnzipStreamDataType = {
40
40
  type: "progress";
package/util/zip-util.js CHANGED
@@ -30,7 +30,7 @@ function buildArguments(filters) {
30
30
  return args;
31
31
  }
32
32
  exports.buildArguments = buildArguments;
33
- async function parseZipStream(chunk, buffer, cb) {
33
+ function parseZipStream(chunk, buffer, cb) {
34
34
  const lines = chunk.trim().split(/\r?\n/g);
35
35
  for (const line of lines) {
36
36
  let matches = null;
@@ -42,7 +42,7 @@ async function parseZipStream(chunk, buffer, cb) {
42
42
  if (path !== buffer.lastPath)
43
43
  buffer.currentPaths++;
44
44
  buffer.lastPath = path;
45
- await cb({
45
+ cb({
46
46
  type: "progress",
47
47
  data: { progress, path, files: buffer.currentPaths },
48
48
  });
@@ -50,7 +50,7 @@ async function parseZipStream(chunk, buffer, cb) {
50
50
  else if (line.startsWith("Add new data to archive:")) {
51
51
  const [, folders] = /(\d+) folders?/i.exec(line) || [, 0];
52
52
  const [, files] = /(\d+) files?/i.exec(line) || [, 0];
53
- await cb({
53
+ cb({
54
54
  type: "summary",
55
55
  data: {
56
56
  folders: Number(folders),
@@ -83,9 +83,9 @@ async function zip(data) {
83
83
  toExitCode: true,
84
84
  },
85
85
  stdout: {
86
- onData: async (chunk) => {
87
- parseZipStream(chunk, buffer, async (stream) => {
88
- await data.onStream?.(stream);
86
+ onData: (chunk) => {
87
+ parseZipStream(chunk, buffer, (stream) => {
88
+ data.onStream?.(stream);
89
89
  if (stream.type === "summary")
90
90
  result = stream.data;
91
91
  });
@@ -95,7 +95,7 @@ async function zip(data) {
95
95
  return result;
96
96
  }
97
97
  exports.zip = zip;
98
- async function parseUnzipStream(chunk, cb) {
98
+ function parseUnzipStream(chunk, cb) {
99
99
  const lines = chunk.trim().split(/\r?\n/g);
100
100
  for (const line of lines) {
101
101
  let matches = null;
@@ -103,7 +103,7 @@ async function parseUnzipStream(chunk, cb) {
103
103
  const progress = Number(matches[1]);
104
104
  const files = Number(matches[2]);
105
105
  const path = line.slice(line.indexOf("-") + 1).trim();
106
- await cb({
106
+ cb({
107
107
  type: "progress",
108
108
  data: { progress, path, files },
109
109
  });
@@ -124,7 +124,7 @@ async function unzip(data) {
124
124
  stderr: { toExitCode: true },
125
125
  stdout: {
126
126
  ...(data.onStream && {
127
- onData: async (chunk) => {
127
+ onData: (chunk) => {
128
128
  if (data.onStream)
129
129
  parseUnzipStream(chunk, data.onStream);
130
130
  },