@datatruck/cli 0.5.0 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @datatruck/cli
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`0c6877d`](https://github.com/swordev/datatruck/commit/0c6877d189761e75dd434b0a8d72b71621d024de) Thanks [@juanrgm](https://github.com/juanrgm)! - Show more progress stats
8
+
9
+ * [`751e1f6`](https://github.com/swordev/datatruck/commit/751e1f6d6b33d3fa96eb40d998fdd140ce0e3875) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `fileCopyConcurrency` option
10
+
11
+ - [`05487e6`](https://github.com/swordev/datatruck/commit/05487e6a33f875a3afb7ff0815b16da6f2a41301) Thanks [@juanrgm](https://github.com/juanrgm)! - Parse InnoDB error in `MariadbTask` to avoid infinite wait
12
+
13
+ ### Patch Changes
14
+
15
+ - [`b62a6f8`](https://github.com/swordev/datatruck/commit/b62a6f8a82409339afd65d4f96476eb57bbfb5a2) Thanks [@juanrgm](https://github.com/juanrgm)! - Resolve target/restore path in local repository
16
+
3
17
  ## 0.5.0
4
18
 
5
19
  ### Minor Changes
@@ -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 = {
@@ -190,6 +190,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
190
190
  });
191
191
  if (data.options.verbose)
192
192
  (0, cli_util_1.logExec)(`Writing paths lists`);
193
+ await data.onProgress({
194
+ step: "Writing excluded paths list...",
195
+ });
193
196
  gitignorePath = await (0, fs_util_1.writeGitIgnoreList)({
194
197
  paths: stream,
195
198
  });
@@ -197,12 +200,19 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
197
200
  if (data.options.tags?.some((tag) => tag.startsWith(ResticRepository.refPrefix)))
198
201
  throw new AppError_1.AppError(`Tag prefix is not allowed`);
199
202
  const packageTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.PACKAGE, data.package.name);
203
+ await data.onProgress({
204
+ step: "Fetching last snapshot...",
205
+ });
200
206
  const [lastSnapshot] = await restic.snapshots({
201
207
  json: true,
202
208
  tags: [packageTag],
203
209
  latest: 1,
204
210
  });
205
211
  const nodePkg = (0, fs_util_1.parsePackageFile)();
212
+ let lastProgress;
213
+ await data.onProgress({
214
+ step: "Executing backup action...",
215
+ });
206
216
  await restic.backup({
207
217
  cwd: sourcePath,
208
218
  paths: ["."],
@@ -223,22 +233,19 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
223
233
  ],
224
234
  onStream: async (streamData) => {
225
235
  if (streamData.message_type === "status") {
226
- await data.onProgress({
227
- total: Number((streamData.total_bytes / 1024 / 1024).toFixed(2)),
228
- current: streamData.bytes_done
229
- ? Number((streamData.bytes_done / 1024 / 1024).toFixed(2))
230
- : 0,
236
+ await data.onProgress((lastProgress = {
237
+ total: streamData.total_files,
238
+ current: streamData.files_done ?? 0,
231
239
  percent: Number((streamData.percent_done * 100).toFixed(2)),
232
240
  step: streamData.current_files?.join(", ") ?? "-",
233
- });
241
+ }));
234
242
  }
235
243
  },
236
244
  });
237
245
  await data.onProgress({
238
- current: 100,
246
+ total: lastProgress?.total || 0,
247
+ current: lastProgress?.total || 0,
239
248
  percent: 100,
240
- step: "",
241
- total: 100,
242
249
  });
243
250
  }
244
251
  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
  },
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 = {
@@ -487,6 +487,10 @@
487
487
  }
488
488
  }
489
489
  ]
490
+ },
491
+ "fileCopyConcurrency": {
492
+ "type": "integer",
493
+ "minimum": 1
490
494
  }
491
495
  }
492
496
  },
@@ -615,6 +619,10 @@
615
619
  },
616
620
  "includeConfig": {
617
621
  "type": "boolean"
622
+ },
623
+ "fileCopyConcurrency": {
624
+ "type": "integer",
625
+ "minimum": 1
618
626
  }
619
627
  }
620
628
  },
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
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([
@@ -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
  }
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;