@datatruck/cli 0.13.1 → 0.16.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 (48) hide show
  1. package/Action/BackupAction.js +7 -19
  2. package/Action/RestoreAction.js +4 -12
  3. package/Command/BackupCommand.js +2 -1
  4. package/Command/BackupSessionsCommand.js +1 -0
  5. package/Command/RestoreCommand.js +1 -1
  6. package/Command/RestoreSessionsCommand.js +1 -0
  7. package/Entity/StateEntityAbstract.d.ts +2 -5
  8. package/Error/AppError.d.ts +1 -0
  9. package/Error/AppError.js +4 -0
  10. package/Repository/DatatruckRepository.d.ts +2 -0
  11. package/Repository/DatatruckRepository.js +234 -123
  12. package/Repository/RepositoryAbstract.d.ts +4 -10
  13. package/Repository/ResticRepository.js +34 -17
  14. package/SessionDriver/ConsoleSessionDriver.d.ts +2 -7
  15. package/SessionDriver/ConsoleSessionDriver.js +51 -24
  16. package/SessionDriver/SqliteSessionDriver.js +5 -0
  17. package/SessionManager/BackupSessionManager.d.ts +12 -11
  18. package/SessionManager/BackupSessionManager.js +20 -5
  19. package/SessionManager/RestoreSessionManager.d.ts +14 -11
  20. package/SessionManager/RestoreSessionManager.js +20 -5
  21. package/SessionManager/SessionManagerAbstract.d.ts +18 -0
  22. package/SessionManager/SessionManagerAbstract.js +32 -0
  23. package/Task/GitTask.js +22 -14
  24. package/Task/MariadbTask.js +9 -4
  25. package/Task/MysqlDumpTask.d.ts +3 -1
  26. package/Task/MysqlDumpTask.js +5 -2
  27. package/Task/PostgresqlDumpTask.d.ts +3 -1
  28. package/Task/PostgresqlDumpTask.js +2 -2
  29. package/Task/SqlDumpTaskAbstract.d.ts +3 -1
  30. package/Task/SqlDumpTaskAbstract.js +55 -13
  31. package/Task/TaskAbstract.d.ts +3 -9
  32. package/cli.js +1 -1
  33. package/config.schema.json +3 -0
  34. package/migrations/001-initial.sql +6 -30
  35. package/package.json +1 -1
  36. package/util/cli-util.d.ts +1 -1
  37. package/util/cli-util.js +17 -2
  38. package/util/fs-util.d.ts +25 -21
  39. package/util/fs-util.js +60 -93
  40. package/util/math-util.js +2 -0
  41. package/util/process-util.d.ts +4 -0
  42. package/util/process-util.js +31 -4
  43. package/util/progress.d.ts +12 -0
  44. package/util/progress.js +2 -0
  45. package/util/string-util.d.ts +1 -0
  46. package/util/string-util.js +8 -1
  47. package/util/zip-util.d.ts +64 -20
  48. package/util/zip-util.js +153 -59
@@ -70,7 +70,7 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
70
70
  table_name
71
71
  `);
72
72
  }
73
- async onExportTables(tableNames, output) {
73
+ async onExportTables(tableNames, output, onProgress) {
74
74
  const stream = (0, fs_1.createWriteStream)(output);
75
75
  await Promise.all([
76
76
  new Promise((resolve, reject) => {
@@ -83,7 +83,10 @@ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
83
83
  "--skip-add-drop-table=false",
84
84
  ...tableNames,
85
85
  ], null, {
86
- pipe: { stream: stream },
86
+ pipe: {
87
+ stream,
88
+ onWriteProgress: onProgress,
89
+ },
87
90
  log: {
88
91
  exec: this.verbose,
89
92
  stderr: this.verbose,
@@ -9,7 +9,9 @@ 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
- onExportTables(tableNames: string[], output: string): Promise<void>;
12
+ onExportTables(tableNames: string[], output: string, onProgress: (progress: {
13
+ totalBytes: number;
14
+ }) => void): Promise<void>;
13
15
  onExportStoredPrograms(): Promise<void>;
14
16
  onImport(path: string, database: string): Promise<void>;
15
17
  }
@@ -73,7 +73,7 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
73
73
  CONCAT(table_schema, '.', table_name)
74
74
  `);
75
75
  }
76
- async onExportTables(tableNames, output) {
76
+ async onExportTables(tableNames, output, onProgress) {
77
77
  const stream = (0, fs_1.createWriteStream)(output);
78
78
  await Promise.all([
79
79
  new Promise((resolve, reject) => {
@@ -84,7 +84,7 @@ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
84
84
  ...(await this.buildConnectionArgs()),
85
85
  ...(tableNames?.flatMap((v) => ["-t", v]) ?? []),
86
86
  ], null, {
87
- pipe: { stream: stream },
87
+ pipe: { stream, onWriteProgress: onProgress },
88
88
  stderr: {
89
89
  toExitCode: true,
90
90
  },
@@ -29,7 +29,9 @@ export declare abstract class SqlDumpTaskAbstract<TConfig extends SqlDumpTaskCon
29
29
  abstract onDatabaseIsEmpty(databaseName: string): Promise<boolean>;
30
30
  abstract onFetchTableNames(database: string): Promise<string[]>;
31
31
  abstract onExecQuery(query: string): ReturnType<typeof exec>;
32
- abstract onExportTables(tableNames: string[], output: string): Promise<void>;
32
+ abstract onExportTables(tableNames: string[], output: string, onProgress: (data: {
33
+ totalBytes: number;
34
+ }) => void): Promise<void>;
33
35
  abstract onExportStoredPrograms(output: string): Promise<void>;
34
36
  abstract onImport(path: string, database: string): Promise<void>;
35
37
  onBackup(data: BackupDataType): Promise<void>;
@@ -118,24 +118,61 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
118
118
  await (0, promises_1.mkdir)(outputPath, { recursive: true });
119
119
  if (!this.config.oneFileByTable) {
120
120
  const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ database: this.config.database }));
121
- await this.onExportTables(tableNames, outPath);
121
+ data.onProgress({
122
+ relative: {
123
+ description: "Exporting",
124
+ },
125
+ });
126
+ await this.onExportTables(tableNames, outPath, async (progress) => {
127
+ await data.onProgress({
128
+ absolute: {
129
+ description: "Exporting in single file",
130
+ current: progress.totalBytes,
131
+ format: "size",
132
+ },
133
+ });
134
+ });
122
135
  }
123
136
  else {
124
137
  let current = 0;
125
138
  for (const tableName of tableNames) {
126
- data.onProgress({
127
- total: tableNames.length,
128
- current: current,
129
- percent: (0, math_util_1.progressPercent)(tableNames.length, current),
130
- step: tableName,
139
+ await data.onProgress({
140
+ relative: {
141
+ description: "Exporting",
142
+ payload: tableName,
143
+ },
144
+ absolute: {
145
+ total: tableNames.length,
146
+ current: current,
147
+ percent: (0, math_util_1.progressPercent)(tableNames.length, current),
148
+ },
131
149
  });
132
- current++;
133
150
  const outPath = (0, path_1.join)(outputPath, serializeSqlFile({ table: tableName }));
134
- await this.onExportTables([tableName], outPath);
151
+ await this.onExportTables([tableName], outPath, async (progress) => {
152
+ await data.onProgress({
153
+ relative: {
154
+ description: "Exporting",
155
+ payload: tableName,
156
+ current: progress.totalBytes,
157
+ format: "size",
158
+ },
159
+ absolute: {
160
+ total: tableNames.length,
161
+ current: current,
162
+ percent: (0, math_util_1.progressPercent)(tableNames.length, current),
163
+ },
164
+ });
165
+ });
166
+ current++;
135
167
  }
136
168
  }
137
169
  if (this.config.storedPrograms) {
138
170
  const outPath = (0, path_1.join)(outputPath, "stored-programs.sql");
171
+ data.onProgress({
172
+ relative: {
173
+ description: "Exporting storaged programs",
174
+ },
175
+ });
139
176
  await this.onExportStoredPrograms(outPath);
140
177
  }
141
178
  }
@@ -184,13 +221,18 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
184
221
  for (const item of items) {
185
222
  const path = (0, path_1.join)(restorePath, item.fileName);
186
223
  data.onProgress({
187
- total: items.length,
188
- current: current,
189
- percent: (0, math_util_1.progressPercent)(items.length, current),
190
- step: item.fileName,
224
+ relative: {
225
+ description: "Importing",
226
+ payload: item.fileName,
227
+ },
228
+ absolute: {
229
+ total: items.length,
230
+ current: current,
231
+ percent: (0, math_util_1.progressPercent)(items.length, current),
232
+ },
191
233
  });
192
- current++;
193
234
  await this.onImport(path, database.name);
235
+ current++;
194
236
  }
195
237
  }
196
238
  }
@@ -2,22 +2,16 @@ import { BackupActionOptionsType } from "../Action/BackupAction";
2
2
  import { RestoreActionOptionsType } from "../Action/RestoreAction";
3
3
  import { PackageConfigType } from "../Config/PackageConfig";
4
4
  import { SnapshotType } from "../Repository/RepositoryAbstract";
5
- export declare type ProgressDataType = {
6
- total?: number;
7
- current?: number;
8
- percent?: number;
9
- step?: string;
10
- stepPercent?: number;
11
- };
5
+ import { Progress } from "../util/progress";
12
6
  export declare type BackupDataType = {
13
- onProgress: (data: ProgressDataType) => Promise<void>;
7
+ onProgress: (data: Progress) => Promise<void>;
14
8
  options: BackupActionOptionsType;
15
9
  package: PackageConfigType;
16
10
  targetPath: string | undefined;
17
11
  snapshot: SnapshotType;
18
12
  };
19
13
  export declare type RestoreDataType = {
20
- onProgress: (data: ProgressDataType) => Promise<void>;
14
+ onProgress: (data: Progress) => Promise<void>;
21
15
  options: RestoreActionOptionsType;
22
16
  package: PackageConfigType;
23
17
  targetPath: string | undefined;
package/cli.js CHANGED
@@ -81,7 +81,7 @@ program.usage("dtt");
81
81
  program.option("-v,--verbose", "Verbose", (_, previous) => previous + 1, 0);
82
82
  program.option("-c,--config <path>", "Config path", process.env["DATATRUCK_CONFIG"] ?? (cwd.endsWith(path_1.sep) ? cwd : `${cwd}${path_1.sep}`));
83
83
  program.option("--progress <value>", "Progress type (auto, plain, tty)", "auto");
84
- program.option("--progress-interval <ms>", "Progress interval");
84
+ program.option("--progress-interval <ms>", "Progress interval", Number, 1000);
85
85
  program.option("-o,--output-format <format>", "Output format (json, pjson, yaml, table, custom=$, tpl=name)", "table");
86
86
  makeCommand(CommandFactory_1.CommandEnum.config).alias("c");
87
87
  makeCommand(CommandFactory_1.CommandEnum.init).alias("i");
@@ -475,6 +475,9 @@
475
475
  "include"
476
476
  ],
477
477
  "properties": {
478
+ "name": {
479
+ "type": "string"
480
+ },
478
481
  "include": {
479
482
  "$ref": "#/definitions/stringlist-util"
480
483
  },
@@ -11,11 +11,7 @@ CREATE TABLE "backup_session" (
11
11
  "endDate" TEXT,
12
12
  "state" TEXT,
13
13
  "error" TEXT,
14
- "progressCurrent" INTEGER,
15
- "progressTotal" INTEGER,
16
- "progressPercent" INTEGER,
17
- "progressStep" TEXT,
18
- "progressStepPercent" INTEGER,
14
+ "progress" TEXT,
19
15
 
20
16
  "snapshotId" TEXT NOT NULL,
21
17
  "packageName" TEXT NOT NULL,
@@ -32,11 +28,7 @@ CREATE TABLE "backup_session_task" (
32
28
  "endDate" TEXT,
33
29
  "state" TEXT,
34
30
  "error" TEXT,
35
- "progressCurrent" INTEGER,
36
- "progressTotal" INTEGER,
37
- "progressPercent" INTEGER,
38
- "progressStep" TEXT,
39
- "progressStepPercent" INTEGER,
31
+ "progress" TEXT,
40
32
 
41
33
  "sessionId" INTEGER NOT NULL,
42
34
  "taskName" TEXT NOT NULL
@@ -51,11 +43,7 @@ CREATE TABLE "backup_session_repository" (
51
43
  "endDate" TEXT,
52
44
  "state" TEXT,
53
45
  "error" TEXT,
54
- "progressCurrent" INTEGER,
55
- "progressTotal" INTEGER,
56
- "progressPercent" INTEGER,
57
- "progressStep" TEXT,
58
- "progressStepPercent" INTEGER,
46
+ "progress" TEXT,
59
47
 
60
48
  "sessionId" INTEGER NOT NULL,
61
49
  "repositoryName" TEXT NOT NULL,
@@ -71,11 +59,7 @@ CREATE TABLE "restore_session" (
71
59
  "endDate" TEXT,
72
60
  "state" TEXT,
73
61
  "error" TEXT,
74
- "progressCurrent" INTEGER,
75
- "progressTotal" INTEGER,
76
- "progressPercent" INTEGER,
77
- "progressStep" TEXT,
78
- "progressStepPercent" INTEGER,
62
+ "progress" TEXT,
79
63
 
80
64
  "snapshotId" TEXT NOT NULL,
81
65
  "packageName" TEXT NOT NULL -- ,
@@ -91,11 +75,7 @@ CREATE TABLE "restore_session_task" (
91
75
  "endDate" TEXT,
92
76
  "state" TEXT,
93
77
  "error" TEXT,
94
- "progressCurrent" INTEGER,
95
- "progressTotal" INTEGER,
96
- "progressPercent" INTEGER,
97
- "progressStep" TEXT,
98
- "progressStepPercent" INTEGER,
78
+ "progress" TEXT,
99
79
 
100
80
  "sessionId" INTEGER NOT NULL,
101
81
  "taskName" TEXT NOT NULL
@@ -110,11 +90,7 @@ CREATE TABLE "restore_session_repository" (
110
90
  "endDate" TEXT,
111
91
  "state" TEXT,
112
92
  "error" TEXT,
113
- "progressCurrent" INTEGER,
114
- "progressTotal" INTEGER,
115
- "progressPercent" INTEGER,
116
- "progressStep" TEXT,
117
- "progressStepPercent" INTEGER,
93
+ "progress" TEXT,
118
94
 
119
95
  "sessionId" INTEGER NOT NULL,
120
96
  "repositoryName" TEXT NOT NULL,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.13.1",
3
+ "version": "0.16.0",
4
4
  "dependencies": {
5
5
  "ajv": "^8.11.0",
6
6
  "async": "^3.2.4",
@@ -5,7 +5,7 @@ export declare const showCursorCommand = "\u001B[?25h";
5
5
  export declare const clearCommand = "\r\u001B[K";
6
6
  export declare const hideCursorCommand = "\u001B[?25l";
7
7
  export declare function renderSpinner(counter: number): string;
8
- export declare function renderProgressBar(progress: number, size?: number): string;
8
+ export declare function renderProgressBar(progress: number, size?: number, subprogress?: number): string;
9
9
  export declare function logVars(data: Record<string, any>): void;
10
10
  export declare function logExec(command: string, argv?: string[], env?: NodeJS.ProcessEnv, logToStderr?: boolean): void;
11
11
  export declare function resultColumn(error: Error | null | string, state?: "started" | "ended"): "❌" | " ? " | "✅";
package/util/cli-util.js CHANGED
@@ -20,12 +20,27 @@ function renderSpinner(counter) {
20
20
  return exports.spinnerChars[counter % (exports.spinnerChars.length - 1)];
21
21
  }
22
22
  exports.renderSpinner = renderSpinner;
23
- function renderProgressBar(progress, size = 10) {
23
+ function renderProgressBar(progress, size = 10, subprogress) {
24
24
  const completeChar = "\u2588";
25
25
  const incompleteChar = "\u2591";
26
26
  const completedSize = Math.round((progress * size) / 100);
27
27
  const restSize = Math.max(size - completedSize, 0);
28
- return completeChar.repeat(completedSize) + incompleteChar.repeat(restSize);
28
+ let result = completeChar.repeat(completedSize) + incompleteChar.repeat(restSize);
29
+ if (typeof subprogress === "number") {
30
+ const subprogressChar = Math.round((subprogress * size) / 100);
31
+ if (subprogressChar === size) {
32
+ result =
33
+ result.slice(0, subprogressChar - 1) +
34
+ chalk_1.default.white(result[Math.max(0, subprogressChar - 1)]);
35
+ }
36
+ else {
37
+ result =
38
+ result.slice(0, subprogressChar) +
39
+ chalk_1.default.white(result[Math.max(0, subprogressChar - 1)]) +
40
+ result.slice(subprogressChar + 1);
41
+ }
42
+ }
43
+ return (0, chalk_2.cyan)(result);
29
44
  }
30
45
  exports.renderProgressBar = renderProgressBar;
31
46
  function logVars(data) {
package/util/fs-util.d.ts CHANGED
@@ -1,9 +1,20 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  /// <reference types="node" />
4
- import { Stats } from "fs";
4
+ /// <reference types="node" />
5
+ import { Dirent, Stats } from "fs";
6
+ import { WriteStream } from "fs";
5
7
  import { Interface } from "readline";
6
8
  export declare const isWSLSystem: boolean;
9
+ export declare function isEmptyDir(path: string): Promise<boolean>;
10
+ declare type EntryObject = {
11
+ name: string;
12
+ path: string;
13
+ dirent: Dirent;
14
+ stats: Stats;
15
+ };
16
+ export declare function applyPermissions(baseDir: string, permissionsPath: string): Promise<void>;
17
+ export declare function pathIterator(stream: AsyncIterable<string | Buffer>): AsyncIterable<EntryObject>;
7
18
  export declare function isLocalDir(path: string): boolean;
8
19
  export declare function isDirEmpty(path: string): Promise<boolean>;
9
20
  export declare function mkdirIfNotExists(path: string): Promise<string>;
@@ -28,7 +39,7 @@ export declare function mkTmpDir(prefix: string, id?: string): Promise<string>;
28
39
  export declare function readPartialFile(path: string, positions: [number, number?]): Promise<string>;
29
40
  export declare function checkFile(path: string): Promise<boolean>;
30
41
  export declare function checkDir(path: string): Promise<boolean>;
31
- export declare function readDir(path: string): Promise<string[]>;
42
+ export declare function readDir(path: string, optional?: boolean): Promise<string[]>;
32
43
  export declare function forEachFile(dirPath: string, cb: (path: string, dir: boolean) => void, includeDir?: boolean): Promise<void>;
33
44
  /**
34
45
  * @experimental
@@ -37,24 +48,7 @@ export declare function fastglobToGitIgnore(patterns: string[], baseDir: string)
37
48
  export declare function writeGitIgnoreList(options: {
38
49
  paths: NodeJS.ReadableStream | string[];
39
50
  }): Promise<string>;
40
- export declare function writePathLists(options: {
41
- paths: NodeJS.ReadableStream | string[];
42
- packs?: {
43
- include: string[];
44
- exclude?: string[];
45
- multiple?: boolean;
46
- }[];
47
- }): Promise<{
48
- path: string;
49
- includedPackPaths: string[];
50
- excludedPackPaths: string[];
51
- total: {
52
- all: number;
53
- path: number;
54
- packsPaths: number[];
55
- multipleStats: Record<string, number>;
56
- };
57
- }>;
51
+ export declare function waitForClose(stream: WriteStream): Promise<WriteStream>;
58
52
  export declare function copyFileWithStreams(source: string, target: string): Promise<unknown>;
59
53
  export declare function updateFileStats(path: string, fileInfo: Stats): Promise<void>;
60
54
  export declare function isNotFoundError(error: unknown): boolean;
@@ -79,6 +73,11 @@ export declare function cpy(options: {
79
73
  */
80
74
  concurrency?: number;
81
75
  skipNotFoundError?: boolean;
76
+ onProgress?: (data: {
77
+ current: number;
78
+ path?: string;
79
+ type?: "start" | "end";
80
+ }) => Promise<boolean | void>;
82
81
  onPath?: (data: {
83
82
  isDir: boolean;
84
83
  entryPath: string;
@@ -90,4 +89,9 @@ export declare function cpy(options: {
90
89
  dirs: number;
91
90
  };
92
91
  }) => Promise<boolean | void>;
93
- }): Promise<void>;
92
+ }): Promise<{
93
+ paths: number;
94
+ files: number;
95
+ dirs: number;
96
+ }>;
97
+ export {};
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.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.writePathLists = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = 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 = exports.isWSLSystem = void 0;
6
+ exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = 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 = exports.pathIterator = exports.applyPermissions = exports.isEmptyDir = exports.isWSLSystem = 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");
@@ -13,13 +13,49 @@ const fast_glob_1 = __importDefault(require("fast-glob"));
13
13
  const fs_1 = require("fs");
14
14
  const fs_2 = require("fs");
15
15
  const promises_1 = require("fs/promises");
16
- const micromatch_1 = require("micromatch");
17
16
  const os_1 = require("os");
18
17
  const path_1 = require("path");
19
18
  const path_2 = require("path");
20
19
  const readline_1 = require("readline");
21
20
  const util_1 = require("util");
22
21
  exports.isWSLSystem = (0, os_1.release)().includes("microsoft-standard-WSL");
22
+ async function isEmptyDir(path) {
23
+ const iterator = await (0, promises_1.opendir)(path);
24
+ let done = false;
25
+ try {
26
+ const next = await iterator[Symbol.asyncIterator]().next();
27
+ done = !!next.done;
28
+ return done;
29
+ }
30
+ finally {
31
+ if (!done) {
32
+ await iterator.close();
33
+ }
34
+ }
35
+ }
36
+ exports.isEmptyDir = isEmptyDir;
37
+ async function applyPermissions(baseDir, permissionsPath) {
38
+ const singleReader = (0, readline_1.createInterface)({
39
+ input: (0, fs_1.createReadStream)(permissionsPath),
40
+ });
41
+ for await (const line of singleReader) {
42
+ const [rpath, rawUid, rawGui, rawMode] = line.split(":");
43
+ const path = (0, path_1.join)(baseDir, rpath);
44
+ if (!path.startsWith(baseDir)) {
45
+ throw new Error(`Entry path is out of the base dir: (${path}, ${baseDir})`);
46
+ }
47
+ const uid = Number(rawUid);
48
+ const guid = Number(rawGui);
49
+ await (0, promises_1.chown)(path, uid, guid);
50
+ const mode = Number(rawMode);
51
+ await (0, promises_1.chmod)(path, mode);
52
+ }
53
+ }
54
+ exports.applyPermissions = applyPermissions;
55
+ function pathIterator(stream) {
56
+ return stream;
57
+ }
58
+ exports.pathIterator = pathIterator;
23
59
  function isLocalDir(path) {
24
60
  return /^[\/\.]|([A-Z]:)/i.test(path);
25
61
  }
@@ -59,9 +95,7 @@ async function writeJSONFile(path, json) {
59
95
  }
60
96
  exports.writeJSONFile = writeJSONFile;
61
97
  async function readdirIfExists(path) {
62
- if (!(await existsDir(path)))
63
- return [];
64
- return await readDir(path);
98
+ return await readDir(path, true);
65
99
  }
66
100
  exports.readdirIfExists = readdirIfExists;
67
101
  exports.parseFileExtensions = ["json", "js", "ts", "yaml", "yml"];
@@ -128,7 +162,7 @@ function sessionTmpDir() {
128
162
  exports.sessionTmpDir = sessionTmpDir;
129
163
  function tmpDir(prefix, id) {
130
164
  if (!id)
131
- id = (0, crypto_1.randomBytes)(8).toString("hex");
165
+ id = (0, crypto_1.randomUUID)().slice(0, 8);
132
166
  return (0, path_1.join)(sessionTmpDir(), `${prefix}-${id}`);
133
167
  }
134
168
  exports.tmpDir = tmpDir;
@@ -187,13 +221,15 @@ async function checkDir(path) {
187
221
  }
188
222
  }
189
223
  exports.checkDir = checkDir;
190
- async function readDir(path) {
224
+ async function readDir(path, optional) {
191
225
  try {
192
226
  return await (0, promises_1.readdir)(path);
193
227
  }
194
228
  catch (anyError) {
195
229
  const nodeError = anyError;
196
230
  if (nodeError.code === "ENOENT") {
231
+ if (optional)
232
+ return [];
197
233
  const error = new Error(nodeError.message);
198
234
  error.code = nodeError.code;
199
235
  error.errno = nodeError.errno;
@@ -262,93 +298,14 @@ async function writeGitIgnoreList(options) {
262
298
  return path;
263
299
  }
264
300
  exports.writeGitIgnoreList = writeGitIgnoreList;
265
- async function writePathLists(options) {
266
- const tempDir = await mkTmpDir("path-lists");
267
- const includedPaths = [];
268
- const excludedPaths = [];
269
- const included = [];
270
- const excluded = [];
271
- const multipleStats = {};
272
- const total = new Array((options.packs?.length || 0) + 1).fill(0);
273
- await Promise.all([
274
- ...new Array((options.packs?.length || 0) + 1).fill(null).map((_, index) => new Promise((resolve, reject) => {
275
- const path = (0, path_1.join)(tempDir, `${index}-included.txt`);
276
- const stream = (0, fs_2.createWriteStream)(path);
277
- includedPaths.push(path);
278
- included.push(stream);
279
- stream.on("close", resolve);
280
- stream.on("error", reject);
281
- })),
282
- ...new Array(options.packs?.length || 0).fill(null).map((_, index) => new Promise((resolve, reject) => {
283
- const path = (0, path_1.join)(tempDir, `${index}-excluded.txt`);
284
- const stream = (0, fs_2.createWriteStream)(path);
285
- excludedPaths.push(path);
286
- excluded.push(stream);
287
- stream.on("close", resolve);
288
- stream.on("error", reject);
289
- })),
290
- new Promise(async (resolve) => {
291
- const packDirectories = [];
292
- for await (const value of options.paths) {
293
- const entry = value.toString();
294
- const isDir = entry.endsWith("/");
295
- const matchEntry = isDir ? entry.slice(0, -1) : entry;
296
- let packIndex = 1;
297
- let matches = false;
298
- for (const pack of options.packs || []) {
299
- if ((0, micromatch_1.isMatch)(matchEntry, pack.include) &&
300
- (!pack.exclude || !(0, micromatch_1.isMatch)(matchEntry, pack.exclude))) {
301
- if (isDir)
302
- packDirectories.push([packIndex - 1, entry]);
303
- included[packIndex].write(`${entry}\n`);
304
- if (!isDir)
305
- total[packIndex]++;
306
- matches = true;
307
- break;
308
- }
309
- packIndex++;
310
- }
311
- if (!matches) {
312
- const packDir = packDirectories.find(([, p]) => entry.startsWith(p));
313
- if (packDir) {
314
- const [i, v] = packDir;
315
- const multipleExclude = options.packs?.[i].exclude;
316
- if (multipleExclude && (0, micromatch_1.isMatch)(matchEntry, multipleExclude)) {
317
- included[0].write(`${entry}\n`);
318
- excluded[i].write(`${entry}\n`);
319
- }
320
- else {
321
- if (!multipleStats[v])
322
- multipleStats[v] = 0;
323
- multipleStats[v]++;
324
- }
325
- }
326
- else {
327
- included[0].write(`${entry}\n`);
328
- }
329
- if (!isDir)
330
- total[0]++;
331
- }
332
- }
333
- for (const stream of [...included, ...excluded]) {
334
- stream.end();
335
- }
336
- resolve();
337
- }),
338
- ]);
339
- return {
340
- path: includedPaths[0],
341
- includedPackPaths: includedPaths.slice(1),
342
- excludedPackPaths: excludedPaths,
343
- total: {
344
- all: total.reduce((p, v) => p + v, 0),
345
- path: total[0],
346
- packsPaths: total.slice(1),
347
- multipleStats,
348
- },
349
- };
301
+ async function waitForClose(stream) {
302
+ return new Promise(async (resolve, reject) => {
303
+ stream.on("close", resolve);
304
+ stream.on("error", reject);
305
+ return stream;
306
+ });
350
307
  }
351
- exports.writePathLists = writePathLists;
308
+ exports.waitForClose = waitForClose;
352
309
  async function copyFileWithStreams(source, target) {
353
310
  const r = (0, fs_1.createReadStream)(source);
354
311
  const w = (0, fs_2.createWriteStream)(target);
@@ -391,6 +348,7 @@ async function cpy(options) {
391
348
  }
392
349
  };
393
350
  const task = async (rawEntryPath, basePath) => {
351
+ [rawEntryPath] = rawEntryPath.split(":");
394
352
  const isDir = rawEntryPath.endsWith("/");
395
353
  const entryPath = (0, path_1.normalize)(rawEntryPath);
396
354
  const entrySourcePath = (0, path_1.resolve)((0, path_1.join)(basePath, rawEntryPath));
@@ -411,6 +369,10 @@ async function cpy(options) {
411
369
  else {
412
370
  const dir = (0, path_1.dirname)(entryTargetPath);
413
371
  await makeRecursiveDir(dir);
372
+ await options.onProgress?.({
373
+ current: stats.files,
374
+ path: entryPath,
375
+ });
414
376
  stats.files++;
415
377
  // https://github.com/nodejs/node/issues/44261
416
378
  if (exports.isWSLSystem) {
@@ -471,5 +433,10 @@ async function cpy(options) {
471
433
  },
472
434
  });
473
435
  }
436
+ await options.onProgress?.({
437
+ current: stats.files,
438
+ type: "end",
439
+ });
440
+ return stats;
474
441
  }
475
442
  exports.cpy = cpy;
package/util/math-util.js CHANGED
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.progressPercent = void 0;
4
4
  function progressPercent(total, current) {
5
+ if (total === 0 && current === 0)
6
+ return 0;
5
7
  return Number(((current / total) * 100).toFixed(2));
6
8
  }
7
9
  exports.progressPercent = progressPercent;
@@ -14,6 +14,9 @@ export interface ExecSettingsInterface {
14
14
  exec?: boolean;
15
15
  pipe?: {
16
16
  stream: WriteStream | ReadStream;
17
+ onWriteProgress?: (data: {
18
+ totalBytes: number;
19
+ }) => void;
17
20
  onReadProgress?: (data: {
18
21
  totalBytes: number;
19
22
  currentBytes: number;
@@ -24,6 +27,7 @@ export interface ExecSettingsInterface {
24
27
  onSpawn?: (p: ChildProcess) => void;
25
28
  stdout?: {
26
29
  save?: boolean;
30
+ parseLines?: boolean;
27
31
  onData?: (data: string) => void;
28
32
  };
29
33
  stderr?: {