@datatruck/cli 0.18.0 → 0.20.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/Action/BackupAction.js +4 -2
- package/Action/BackupSessionsAction.js +2 -0
- package/Action/CleanCacheAction.js +1 -0
- package/Action/ConfigAction.js +1 -0
- package/Action/InitAction.js +2 -0
- package/Action/PruneAction.js +2 -0
- package/Action/RestoreAction.js +5 -3
- package/Action/RestoreSessionsAction.js +2 -0
- package/Action/SnapshotsAction.js +2 -0
- package/Command/CommandAbstract.js +2 -0
- package/Entity/BackupSessionEntity.js +5 -2
- package/Entity/BackupSessionRepositoryEntity.js +5 -2
- package/Entity/BackupSessionTaskEntity.js +4 -2
- package/Entity/CrudEntityAbstract.js +3 -0
- package/Entity/RestoreSessionEntity.js +4 -2
- package/Entity/RestoreSessionRepositoryEntity.js +5 -2
- package/Entity/RestoreSessionTaskEntity.js +4 -2
- package/Entity/StateEntityAbstract.js +5 -0
- package/Factory/CommandFactory.js +1 -1
- package/JsonSchema/DefinitionEnum.js +1 -1
- package/Repository/DatatruckRepository.d.ts +8 -13
- package/Repository/DatatruckRepository.js +122 -231
- package/Repository/GitRepository.js +1 -1
- package/Repository/RepositoryAbstract.js +4 -2
- package/Repository/ResticRepository.js +2 -1
- package/SessionDriver/ConsoleSessionDriver.js +9 -5
- package/SessionDriver/SessionDriverAbstract.js +3 -2
- package/SessionDriver/SqliteSessionDriver.js +2 -4
- package/SessionManager/BackupSessionManager.js +3 -6
- package/SessionManager/RestoreSessionManager.js +3 -6
- package/SessionManager/SessionManagerAbstract.js +4 -0
- package/Task/GitTask.js +3 -2
- package/Task/MariadbTask.js +6 -4
- package/Task/MssqlTask.js +2 -1
- package/Task/ScriptTask.js +1 -0
- package/Task/SqlDumpTaskAbstract.js +2 -1
- package/Task/TaskAbstract.js +2 -1
- package/config.schema.json +23 -37
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +8 -8
- package/utils/DataFormat.js +1 -0
- package/utils/Git.js +2 -1
- package/utils/ObjectVault.js +3 -5
- package/utils/Restic.js +1 -0
- package/utils/datatruck/paths.js +5 -1
- package/utils/fs.d.ts +23 -24
- package/utils/fs.js +108 -96
- package/utils/process.d.ts +1 -1
- package/utils/process.js +17 -8
- package/utils/string.d.ts +0 -2
- package/utils/string.js +1 -9
- package/utils/tar.d.ts +35 -0
- package/utils/tar.js +127 -0
- package/utils/zip.d.ts +0 -97
- package/utils/zip.js +0 -238
package/utils/process.js
CHANGED
|
@@ -188,7 +188,7 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
188
188
|
toStderr: log.allToStderr,
|
|
189
189
|
});
|
|
190
190
|
}
|
|
191
|
-
if (typeof options?.cwd === "string" && !(await (0, fs_1.
|
|
191
|
+
if (typeof options?.cwd === "string" && !(await (0, fs_1.existsDir)(options.cwd)))
|
|
192
192
|
throw new Error(`Current working directory does not exist: ${options.cwd}`);
|
|
193
193
|
if (pipe?.stream instanceof fs_2.ReadStream && "onReadProgress" in pipe) {
|
|
194
194
|
const fileInfo = await (0, promises_1.stat)(pipe.stream.path);
|
|
@@ -225,13 +225,13 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
225
225
|
if (spawnData.exitCode) {
|
|
226
226
|
let exitCodeError;
|
|
227
227
|
if (settings.stderr?.toExitCode) {
|
|
228
|
-
exitCodeError = new Error(`Exit code ${spawnData.exitCode}: ${spawnData.stderr
|
|
228
|
+
exitCodeError = new Error(`Exit code ${spawnData.exitCode}: ${command} ${argv.join(" ")} | ${spawnData.stderr
|
|
229
229
|
.split(/\r?\n/g)
|
|
230
230
|
.filter((v) => !!v.length)
|
|
231
231
|
.join(" | ")}`);
|
|
232
232
|
}
|
|
233
233
|
else {
|
|
234
|
-
exitCodeError = new Error(`Exit code
|
|
234
|
+
exitCodeError = new Error(`Exit code ${spawnData.exitCode}: ${command} ${argv.join(" ")}`);
|
|
235
235
|
}
|
|
236
236
|
const exitCodeErrorResult = settings.onExitCodeError?.(spawnData, exitCodeError);
|
|
237
237
|
if (exitCodeErrorResult instanceof Error) {
|
|
@@ -286,17 +286,24 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
286
286
|
if (!p.stdout)
|
|
287
287
|
throw new Error(`stdout is not defined`);
|
|
288
288
|
const parseLines = settings.stdout?.parseLines;
|
|
289
|
-
const
|
|
289
|
+
const skipEmptyLines = parseLines === "skip-empty";
|
|
290
|
+
const onData = (inData) => {
|
|
291
|
+
let data = inData.toString();
|
|
292
|
+
if (parseLines) {
|
|
293
|
+
if (skipEmptyLines && !data.trim().length)
|
|
294
|
+
return;
|
|
295
|
+
data = `${inData}\n`;
|
|
296
|
+
}
|
|
290
297
|
if (log.stdout)
|
|
291
298
|
logExecStdout({
|
|
292
|
-
data
|
|
299
|
+
data,
|
|
293
300
|
stderr: log.allToStderr,
|
|
294
301
|
colorize: log.colorize,
|
|
295
302
|
});
|
|
296
303
|
if (settings.stdout?.save)
|
|
297
|
-
spawnData.stdout += data
|
|
304
|
+
spawnData.stdout += data;
|
|
298
305
|
if (settings.stdout?.onData)
|
|
299
|
-
settings.stdout.onData(
|
|
306
|
+
settings.stdout.onData(inData.toString());
|
|
300
307
|
};
|
|
301
308
|
if (parseLines) {
|
|
302
309
|
const rl = (0, readline_1.createInterface)({
|
|
@@ -305,7 +312,9 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
305
312
|
rl.on("line", onData);
|
|
306
313
|
rl.on("close", tryFinish);
|
|
307
314
|
}
|
|
308
|
-
else
|
|
315
|
+
else if (log.stdout ||
|
|
316
|
+
settings.stdout?.save ||
|
|
317
|
+
settings.stdout?.onData) {
|
|
309
318
|
p.stdout.on("data", onData);
|
|
310
319
|
}
|
|
311
320
|
}
|
package/utils/string.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export declare function serialize(message: string, data?: Object): string;
|
|
2
|
-
export declare function ucfirst(value: string): string;
|
|
3
|
-
export declare function lcfirst(value: string): string;
|
|
4
2
|
export declare function snakeCase(value: string, char?: string): string;
|
|
5
3
|
export declare function render(subject: string, vars: Record<string, string | undefined>): string;
|
|
6
4
|
export declare function parseStringList(value: string, validValues?: string[]): string[];
|
package/utils/string.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatDateTime = exports.checkMatch = exports.checkPath = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.
|
|
3
|
+
exports.formatDateTime = exports.checkMatch = exports.checkPath = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.serialize = void 0;
|
|
4
4
|
const AppError_1 = require("../Error/AppError");
|
|
5
5
|
const micromatch_1 = require("micromatch");
|
|
6
6
|
function serialize(message, data) {
|
|
@@ -9,14 +9,6 @@ function serialize(message, data) {
|
|
|
9
9
|
return message;
|
|
10
10
|
}
|
|
11
11
|
exports.serialize = serialize;
|
|
12
|
-
function ucfirst(value) {
|
|
13
|
-
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
14
|
-
}
|
|
15
|
-
exports.ucfirst = ucfirst;
|
|
16
|
-
function lcfirst(value) {
|
|
17
|
-
return value.charAt(0).toLowerCase() + value.slice(1);
|
|
18
|
-
}
|
|
19
|
-
exports.lcfirst = lcfirst;
|
|
20
12
|
function snakeCase(value, char = "_") {
|
|
21
13
|
return value.replace(/[A-Z]/g, (letter) => `${char}${letter.toLowerCase()}`);
|
|
22
14
|
}
|
package/utils/tar.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type Progress = {
|
|
2
|
+
percent: number;
|
|
3
|
+
current: number;
|
|
4
|
+
total: number;
|
|
5
|
+
};
|
|
6
|
+
export type TarEntry = {
|
|
7
|
+
path: string;
|
|
8
|
+
progress: Progress;
|
|
9
|
+
};
|
|
10
|
+
export interface CreateTarOptions {
|
|
11
|
+
path: string;
|
|
12
|
+
verbose?: boolean;
|
|
13
|
+
output: string;
|
|
14
|
+
includeList: string;
|
|
15
|
+
compress?: boolean;
|
|
16
|
+
onEntry?: (entry: TarEntry) => void;
|
|
17
|
+
}
|
|
18
|
+
export interface ExtractOptions {
|
|
19
|
+
input: string;
|
|
20
|
+
output: string;
|
|
21
|
+
verbose?: boolean;
|
|
22
|
+
uncompress?: boolean;
|
|
23
|
+
total?: number;
|
|
24
|
+
onEntry?: (entry: TarEntry) => void;
|
|
25
|
+
}
|
|
26
|
+
export type TarVendor = "busybox" | "bsdtar" | "gnu";
|
|
27
|
+
export declare function getTarVendor(cache?: boolean, log?: boolean): Promise<TarVendor | null>;
|
|
28
|
+
export type ListTarOptions = {
|
|
29
|
+
input: string;
|
|
30
|
+
onEntry?: (entry: Pick<TarEntry, "path">) => void;
|
|
31
|
+
verbose?: boolean;
|
|
32
|
+
};
|
|
33
|
+
export declare function listTar(options: ListTarOptions): Promise<number>;
|
|
34
|
+
export declare function createTar(options: CreateTarOptions): Promise<void>;
|
|
35
|
+
export declare function extractTar(options: ExtractOptions): Promise<void>;
|
package/utils/tar.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractTar = exports.createTar = exports.listTar = exports.getTarVendor = void 0;
|
|
4
|
+
const cli_1 = require("./cli");
|
|
5
|
+
const fs_1 = require("./fs");
|
|
6
|
+
const math_1 = require("./math");
|
|
7
|
+
const process_1 = require("./process");
|
|
8
|
+
const promises_1 = require("fs/promises");
|
|
9
|
+
const os_1 = require("os");
|
|
10
|
+
let tarVendor;
|
|
11
|
+
async function getTarVendor(cache = true, log = false) {
|
|
12
|
+
if (cache && typeof tarVendor !== "undefined")
|
|
13
|
+
return tarVendor;
|
|
14
|
+
const p = await (0, process_1.exec)("tar", ["--help"], {}, {
|
|
15
|
+
log,
|
|
16
|
+
stdout: {
|
|
17
|
+
save: true,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
const find = () => {
|
|
21
|
+
if (p.stdout.includes("BusyBox")) {
|
|
22
|
+
return "busybox";
|
|
23
|
+
}
|
|
24
|
+
else if (p.stdout.includes("bsdtar")) {
|
|
25
|
+
return "bsdtar";
|
|
26
|
+
}
|
|
27
|
+
else if (p.stdout.includes("GNU")) {
|
|
28
|
+
return "gnu";
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
return (tarVendor = find());
|
|
35
|
+
}
|
|
36
|
+
exports.getTarVendor = getTarVendor;
|
|
37
|
+
async function listTar(options) {
|
|
38
|
+
let total = 0;
|
|
39
|
+
await (0, process_1.exec)("tar", ["-tf", toLocalPath(options.input), "--force-local"], {}, {
|
|
40
|
+
log: options.verbose,
|
|
41
|
+
stdout: {
|
|
42
|
+
parseLines: "skip-empty",
|
|
43
|
+
onData: (path) => {
|
|
44
|
+
options.onEntry?.({ path });
|
|
45
|
+
total++;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
return total;
|
|
50
|
+
}
|
|
51
|
+
exports.listTar = listTar;
|
|
52
|
+
async function createTar(options) {
|
|
53
|
+
const vendor = await getTarVendor(true, options.verbose);
|
|
54
|
+
const total = await (0, fs_1.countFileLines)(options.includeList);
|
|
55
|
+
let current = 0;
|
|
56
|
+
await (0, process_1.exec)("tar", [
|
|
57
|
+
"-C",
|
|
58
|
+
toLocalPath(options.path),
|
|
59
|
+
options.compress ? "-czvf" : "-cvf",
|
|
60
|
+
toLocalPath(options.output),
|
|
61
|
+
"-T",
|
|
62
|
+
toLocalPath(options.includeList),
|
|
63
|
+
"--ignore-failed-read",
|
|
64
|
+
"--force-local",
|
|
65
|
+
], {}, {
|
|
66
|
+
log: options.verbose,
|
|
67
|
+
stderr: { toExitCode: true },
|
|
68
|
+
stdout: {
|
|
69
|
+
parseLines: "skip-empty",
|
|
70
|
+
onData: (line) => {
|
|
71
|
+
current++;
|
|
72
|
+
const path = vendor === "bsdtar" ? line.slice(2) : line;
|
|
73
|
+
options.onEntry?.({
|
|
74
|
+
path,
|
|
75
|
+
progress: {
|
|
76
|
+
total,
|
|
77
|
+
current,
|
|
78
|
+
percent: (0, math_1.progressPercent)(total, current),
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
exports.createTar = createTar;
|
|
86
|
+
/**
|
|
87
|
+
* Fix `tar.exe: Option --force-local is not supported`
|
|
88
|
+
*/
|
|
89
|
+
function toLocalPath(path) {
|
|
90
|
+
return (0, os_1.platform)() === "win32" ? path.replace(/\\/g, "/") : path;
|
|
91
|
+
}
|
|
92
|
+
async function extractTar(options) {
|
|
93
|
+
let total = options.total ??
|
|
94
|
+
(await listTar({ input: options.input, verbose: options.verbose }));
|
|
95
|
+
if (options.verbose)
|
|
96
|
+
(0, cli_1.logExec)("mkdir", ["-p", options.output]);
|
|
97
|
+
await (0, promises_1.mkdir)(options.output, { recursive: true });
|
|
98
|
+
await (0, fs_1.ensureEmptyDir)(options.output);
|
|
99
|
+
let current = 0;
|
|
100
|
+
await (0, process_1.exec)("tar", [
|
|
101
|
+
options.uncompress ? "-xzvpf" : "-xvpf",
|
|
102
|
+
toLocalPath(options.input),
|
|
103
|
+
"-C",
|
|
104
|
+
toLocalPath(options.output),
|
|
105
|
+
"--force-local",
|
|
106
|
+
], {}, {
|
|
107
|
+
log: options.verbose,
|
|
108
|
+
stderr: {
|
|
109
|
+
toExitCode: true,
|
|
110
|
+
},
|
|
111
|
+
stdout: {
|
|
112
|
+
parseLines: "skip-empty",
|
|
113
|
+
onData: (path) => {
|
|
114
|
+
current++;
|
|
115
|
+
options.onEntry?.({
|
|
116
|
+
path,
|
|
117
|
+
progress: {
|
|
118
|
+
total,
|
|
119
|
+
current,
|
|
120
|
+
percent: (0, math_1.progressPercent)(total, current),
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
exports.extractTar = extractTar;
|
package/utils/zip.d.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
export interface ZipDataFilterType {
|
|
2
|
-
recursive?: boolean;
|
|
3
|
-
exclude?: boolean;
|
|
4
|
-
patterns: string[];
|
|
5
|
-
}
|
|
6
|
-
export interface ZipDataType {
|
|
7
|
-
command?: string;
|
|
8
|
-
path: string;
|
|
9
|
-
filter?: (ZipDataFilterType | string)[];
|
|
10
|
-
output: string;
|
|
11
|
-
deleteOnZip?: boolean;
|
|
12
|
-
includeList?: string;
|
|
13
|
-
excludeList?: string;
|
|
14
|
-
verbose?: boolean;
|
|
15
|
-
onProgress?: (data: {
|
|
16
|
-
percent: number;
|
|
17
|
-
total: number;
|
|
18
|
-
current: number;
|
|
19
|
-
path?: string;
|
|
20
|
-
type?: "start" | "end";
|
|
21
|
-
}) => void | Promise<void>;
|
|
22
|
-
onStream?: (data: ZipStream) => void | Promise<void>;
|
|
23
|
-
}
|
|
24
|
-
export interface UnzipDataType {
|
|
25
|
-
command?: string;
|
|
26
|
-
input: string;
|
|
27
|
-
files?: (ZipDataFilterType | string)[];
|
|
28
|
-
output: string;
|
|
29
|
-
verbose?: boolean;
|
|
30
|
-
onProgress?: (data: {
|
|
31
|
-
percent: number;
|
|
32
|
-
current: number;
|
|
33
|
-
path?: string;
|
|
34
|
-
type?: "start" | "end";
|
|
35
|
-
}) => void | Promise<void>;
|
|
36
|
-
onStream?: (data: UnzipStream) => void | Promise<void>;
|
|
37
|
-
}
|
|
38
|
-
export declare function buildArguments(filters: (ZipDataFilterType | string)[]): string[];
|
|
39
|
-
export declare function checkSSEOption(command?: string): Promise<boolean>;
|
|
40
|
-
type ListZipStream = {
|
|
41
|
-
Path?: string;
|
|
42
|
-
Folder?: string;
|
|
43
|
-
Size?: string;
|
|
44
|
-
"Packed Size"?: string;
|
|
45
|
-
Modified?: string;
|
|
46
|
-
Created?: string;
|
|
47
|
-
Accessed?: string;
|
|
48
|
-
Attributes?: string;
|
|
49
|
-
Encrypted?: string;
|
|
50
|
-
Comment?: string;
|
|
51
|
-
CRC?: string;
|
|
52
|
-
Method?: string;
|
|
53
|
-
Characteristics?: string;
|
|
54
|
-
"Host OS"?: string;
|
|
55
|
-
Version?: string;
|
|
56
|
-
Volume?: string;
|
|
57
|
-
Offset?: string;
|
|
58
|
-
};
|
|
59
|
-
export declare function listZip(data: {
|
|
60
|
-
command?: string;
|
|
61
|
-
path: string;
|
|
62
|
-
onStream: (item: ListZipStream) => Promise<void>;
|
|
63
|
-
verbose?: boolean;
|
|
64
|
-
}): Promise<void>;
|
|
65
|
-
export type ZipStream = {
|
|
66
|
-
type: "progress";
|
|
67
|
-
data: {
|
|
68
|
-
progress: number;
|
|
69
|
-
files: number;
|
|
70
|
-
path: string;
|
|
71
|
-
};
|
|
72
|
-
} | {
|
|
73
|
-
type: "summary";
|
|
74
|
-
data: {
|
|
75
|
-
folders: number;
|
|
76
|
-
files: number;
|
|
77
|
-
};
|
|
78
|
-
};
|
|
79
|
-
export declare function zip(data: ZipDataType): Promise<{
|
|
80
|
-
folders: number;
|
|
81
|
-
files: number;
|
|
82
|
-
}>;
|
|
83
|
-
export type UnzipStream = {
|
|
84
|
-
type: "progress";
|
|
85
|
-
data: {
|
|
86
|
-
percent: number;
|
|
87
|
-
files: number;
|
|
88
|
-
path: string;
|
|
89
|
-
};
|
|
90
|
-
};
|
|
91
|
-
export declare function unzip(data: UnzipDataType): Promise<{
|
|
92
|
-
files: number;
|
|
93
|
-
stdout: string;
|
|
94
|
-
stderr: string;
|
|
95
|
-
exitCode: number;
|
|
96
|
-
}>;
|
|
97
|
-
export {};
|
package/utils/zip.js
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unzip = exports.zip = exports.listZip = exports.checkSSEOption = exports.buildArguments = void 0;
|
|
4
|
-
const process_1 = require("./process");
|
|
5
|
-
const path_1 = require("path");
|
|
6
|
-
function buildArguments(filters) {
|
|
7
|
-
const args = [];
|
|
8
|
-
for (const item of filters) {
|
|
9
|
-
let filter;
|
|
10
|
-
if (typeof item === "string") {
|
|
11
|
-
filter = {
|
|
12
|
-
recursive: false,
|
|
13
|
-
exclude: false,
|
|
14
|
-
patterns: [item],
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
filter = item;
|
|
19
|
-
}
|
|
20
|
-
args.push(...filter.patterns.map((value) => {
|
|
21
|
-
let option = "-";
|
|
22
|
-
option += filter.exclude ? "x" : "i";
|
|
23
|
-
if (filter.recursive)
|
|
24
|
-
option += "r";
|
|
25
|
-
option += "!";
|
|
26
|
-
option += (0, path_1.normalize)(value);
|
|
27
|
-
return option;
|
|
28
|
-
}));
|
|
29
|
-
}
|
|
30
|
-
return args;
|
|
31
|
-
}
|
|
32
|
-
exports.buildArguments = buildArguments;
|
|
33
|
-
let checkSSEOptionResult;
|
|
34
|
-
async function checkSSEOption(command = "7z") {
|
|
35
|
-
const result = await (0, process_1.exec)(command, [], {}, {
|
|
36
|
-
stdout: {
|
|
37
|
-
save: true,
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
if (typeof checkSSEOptionResult === "boolean")
|
|
41
|
-
return checkSSEOptionResult;
|
|
42
|
-
return (checkSSEOptionResult = result.stdout.includes(" -sse"));
|
|
43
|
-
}
|
|
44
|
-
exports.checkSSEOption = checkSSEOption;
|
|
45
|
-
const listZipLineEqChar = " = ";
|
|
46
|
-
function parseListZipLine(line, buffer) {
|
|
47
|
-
if (buffer.started) {
|
|
48
|
-
if (line === "") {
|
|
49
|
-
if (buffer.opened) {
|
|
50
|
-
const { stream } = buffer;
|
|
51
|
-
buffer.stream = {};
|
|
52
|
-
buffer.opened = false;
|
|
53
|
-
return stream;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
const separator = line.indexOf(listZipLineEqChar);
|
|
58
|
-
const key = line.slice(0, separator);
|
|
59
|
-
const value = line.slice(separator + listZipLineEqChar.length);
|
|
60
|
-
buffer.opened = true;
|
|
61
|
-
buffer.stream[key] = value;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
else if (line.startsWith("----------")) {
|
|
65
|
-
buffer.started = true;
|
|
66
|
-
buffer.stream = {};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
async function listZip(data) {
|
|
70
|
-
const buffer = {};
|
|
71
|
-
await (0, process_1.exec)(data.command ?? "7z", ["l", data.path, "-slt"], {}, {
|
|
72
|
-
log: {
|
|
73
|
-
exec: data.verbose ?? false,
|
|
74
|
-
stderr: data.verbose ?? false,
|
|
75
|
-
stdout: false,
|
|
76
|
-
},
|
|
77
|
-
onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
|
|
78
|
-
stdout: {
|
|
79
|
-
parseLines: true,
|
|
80
|
-
onData: async (line) => {
|
|
81
|
-
const stream = parseListZipLine(line, buffer);
|
|
82
|
-
if (stream) {
|
|
83
|
-
await data.onStream?.(stream);
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
exports.listZip = listZip;
|
|
90
|
-
function parseZipLine(line) {
|
|
91
|
-
let matches = null;
|
|
92
|
-
line = line.trim();
|
|
93
|
-
if (!line.length)
|
|
94
|
-
return;
|
|
95
|
-
if ((matches = /^(\d+)% (\d+ )?\+/.exec(line))) {
|
|
96
|
-
const path = line.slice(line.indexOf("+") + 1).trim();
|
|
97
|
-
const progress = Number(matches[1]);
|
|
98
|
-
const files = matches[2] ? Number(matches[2]) : 1;
|
|
99
|
-
return {
|
|
100
|
-
type: "progress",
|
|
101
|
-
data: { progress, path, files },
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
else if (line.startsWith("Add new data to archive:")) {
|
|
105
|
-
const [, folders] = /(\d+) folders?/i.exec(line) || [, 0];
|
|
106
|
-
const [, files] = /(\d+) files?/i.exec(line) || [, 0];
|
|
107
|
-
return {
|
|
108
|
-
type: "summary",
|
|
109
|
-
data: {
|
|
110
|
-
folders: Number(folders),
|
|
111
|
-
files: Number(files),
|
|
112
|
-
},
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
async function zip(data) {
|
|
117
|
-
let summary = {
|
|
118
|
-
folders: 0,
|
|
119
|
-
files: 0,
|
|
120
|
-
};
|
|
121
|
-
await data.onProgress?.({
|
|
122
|
-
current: 0,
|
|
123
|
-
percent: 0,
|
|
124
|
-
total: 0,
|
|
125
|
-
type: "start",
|
|
126
|
-
});
|
|
127
|
-
await (0, process_1.exec)(data.command ?? "7z", [
|
|
128
|
-
"a",
|
|
129
|
-
// https://sourceforge.net/p/sevenzip/bugs/2099/,
|
|
130
|
-
// https://github.com/mcmilk/7-Zip/commit/87ba6f01ba3c5b2ce3186bddfe3d7d880639193c#diff-779d6b1bfa6196b288478f78ca96c4d4c6d7ac6cf8be15a28a20dabc9137ca36L515
|
|
131
|
-
...((await checkSSEOption(data.command)) ? [] : ["-mmt1"]),
|
|
132
|
-
"-bsp1",
|
|
133
|
-
...(data.deleteOnZip ? ["-sdel"] : []),
|
|
134
|
-
(0, path_1.normalize)(data.output),
|
|
135
|
-
...buildArguments(data.filter ?? []),
|
|
136
|
-
...(data.includeList ? [`@${(0, path_1.normalize)(data.includeList)}`] : []),
|
|
137
|
-
...(data.excludeList ? [`-x@${(0, path_1.normalize)(data.excludeList)}`] : []),
|
|
138
|
-
], {
|
|
139
|
-
cwd: data.path,
|
|
140
|
-
}, {
|
|
141
|
-
log: data.verbose ?? false,
|
|
142
|
-
onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
|
|
143
|
-
stdout: {
|
|
144
|
-
onData: async (lines) => {
|
|
145
|
-
for (const line of lines.replaceAll("\b", "").split(/\r?\n/)) {
|
|
146
|
-
const stream = parseZipLine(line);
|
|
147
|
-
if (stream) {
|
|
148
|
-
if (stream.type === "summary")
|
|
149
|
-
summary = stream.data;
|
|
150
|
-
if (stream.type === "progress") {
|
|
151
|
-
const current = Math.max(0, stream.data.files - 1);
|
|
152
|
-
await data.onProgress?.({
|
|
153
|
-
total: summary.files,
|
|
154
|
-
current,
|
|
155
|
-
path: stream.data.path,
|
|
156
|
-
percent: stream.data.progress,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
await data.onStream?.(stream);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
await data.onProgress?.({
|
|
166
|
-
total: summary.files,
|
|
167
|
-
current: summary.files,
|
|
168
|
-
percent: 100,
|
|
169
|
-
type: "end",
|
|
170
|
-
});
|
|
171
|
-
return summary;
|
|
172
|
-
}
|
|
173
|
-
exports.zip = zip;
|
|
174
|
-
function parseUnzipLine(line) {
|
|
175
|
-
let matches = null;
|
|
176
|
-
if ((matches = /^\s*(?<percent>\d+)%(?: (?<files>\d+))? \-/.exec(line))) {
|
|
177
|
-
const progress = Number(matches.groups["percent"]);
|
|
178
|
-
const files = matches.groups["files"] ? Number(matches[2]) : 1;
|
|
179
|
-
const path = line.slice(line.indexOf("-") + 1).trim();
|
|
180
|
-
return {
|
|
181
|
-
type: "progress",
|
|
182
|
-
data: { percent: progress, path, files },
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
async function unzip(data) {
|
|
187
|
-
let summary = {
|
|
188
|
-
files: 0,
|
|
189
|
-
};
|
|
190
|
-
await data.onProgress?.({
|
|
191
|
-
current: summary.files,
|
|
192
|
-
percent: 0,
|
|
193
|
-
type: "start",
|
|
194
|
-
});
|
|
195
|
-
const result = await (0, process_1.exec)(data.command ?? "7z", [
|
|
196
|
-
"x",
|
|
197
|
-
"-bsp1",
|
|
198
|
-
(0, path_1.normalize)(data.input),
|
|
199
|
-
...buildArguments(data.files ?? []),
|
|
200
|
-
`-o${(0, path_1.normalize)(data.output)}`,
|
|
201
|
-
"-r",
|
|
202
|
-
], {}, {
|
|
203
|
-
log: data.verbose ?? false,
|
|
204
|
-
stderr: { toExitCode: true },
|
|
205
|
-
stdout: {
|
|
206
|
-
...((data.onStream || data.onProgress) && {
|
|
207
|
-
onData: async (chunk) => {
|
|
208
|
-
const lines = chunk.replaceAll("\b", "").split(/\r?\n/);
|
|
209
|
-
for (const line of lines) {
|
|
210
|
-
const stream = parseUnzipLine(line);
|
|
211
|
-
if (stream) {
|
|
212
|
-
if (stream.type === "progress") {
|
|
213
|
-
const current = Math.max(0, stream.data.files - 1);
|
|
214
|
-
summary.files = stream.data.files;
|
|
215
|
-
await data.onProgress?.({
|
|
216
|
-
current,
|
|
217
|
-
percent: stream.data.percent,
|
|
218
|
-
path: stream.data.path,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
await data.onStream?.(stream);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
}),
|
|
226
|
-
},
|
|
227
|
-
});
|
|
228
|
-
await data.onProgress?.({
|
|
229
|
-
current: summary.files,
|
|
230
|
-
percent: 100,
|
|
231
|
-
type: "end",
|
|
232
|
-
});
|
|
233
|
-
return {
|
|
234
|
-
...result,
|
|
235
|
-
...summary,
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
exports.unzip = unzip;
|