@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.
- package/Action/BackupAction.js +7 -19
- package/Action/RestoreAction.js +4 -12
- package/Command/BackupCommand.js +2 -1
- package/Command/BackupSessionsCommand.js +1 -0
- package/Command/RestoreCommand.js +1 -1
- package/Command/RestoreSessionsCommand.js +1 -0
- package/Entity/StateEntityAbstract.d.ts +2 -5
- package/Error/AppError.d.ts +1 -0
- package/Error/AppError.js +4 -0
- package/Repository/DatatruckRepository.d.ts +2 -0
- package/Repository/DatatruckRepository.js +234 -123
- package/Repository/RepositoryAbstract.d.ts +4 -10
- package/Repository/ResticRepository.js +34 -17
- package/SessionDriver/ConsoleSessionDriver.d.ts +2 -7
- package/SessionDriver/ConsoleSessionDriver.js +51 -24
- package/SessionDriver/SqliteSessionDriver.js +5 -0
- package/SessionManager/BackupSessionManager.d.ts +12 -11
- package/SessionManager/BackupSessionManager.js +20 -5
- package/SessionManager/RestoreSessionManager.d.ts +14 -11
- package/SessionManager/RestoreSessionManager.js +20 -5
- package/SessionManager/SessionManagerAbstract.d.ts +18 -0
- package/SessionManager/SessionManagerAbstract.js +32 -0
- package/Task/GitTask.js +22 -14
- package/Task/MariadbTask.js +9 -4
- package/Task/MysqlDumpTask.d.ts +3 -1
- package/Task/MysqlDumpTask.js +5 -2
- package/Task/PostgresqlDumpTask.d.ts +3 -1
- package/Task/PostgresqlDumpTask.js +2 -2
- package/Task/SqlDumpTaskAbstract.d.ts +3 -1
- package/Task/SqlDumpTaskAbstract.js +55 -13
- package/Task/TaskAbstract.d.ts +3 -9
- package/cli.js +1 -1
- package/config.schema.json +3 -0
- package/migrations/001-initial.sql +6 -30
- package/package.json +1 -1
- package/util/cli-util.d.ts +1 -1
- package/util/cli-util.js +17 -2
- package/util/fs-util.d.ts +25 -21
- package/util/fs-util.js +60 -93
- package/util/math-util.js +2 -0
- package/util/process-util.d.ts +4 -0
- package/util/process-util.js +31 -4
- package/util/progress.d.ts +12 -0
- package/util/progress.js +2 -0
- package/util/string-util.d.ts +1 -0
- package/util/string-util.js +8 -1
- package/util/zip-util.d.ts +64 -20
- package/util/zip-util.js +153 -59
package/util/process-util.js
CHANGED
|
@@ -11,6 +11,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
11
11
|
const child_process_1 = require("child_process");
|
|
12
12
|
const fs_1 = require("fs");
|
|
13
13
|
const promises_1 = require("fs/promises");
|
|
14
|
+
const readline_1 = require("readline");
|
|
14
15
|
function logExecStdout(input) {
|
|
15
16
|
let text = input.colorize ? chalk_1.default.grey(input.data) : input.data;
|
|
16
17
|
if (input.lineSalt)
|
|
@@ -70,7 +71,11 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
70
71
|
stderr: "",
|
|
71
72
|
exitCode: 0,
|
|
72
73
|
};
|
|
73
|
-
let finishListeners =
|
|
74
|
+
let finishListeners = 1;
|
|
75
|
+
if (pipe?.stream instanceof fs_1.WriteStream)
|
|
76
|
+
finishListeners++;
|
|
77
|
+
if (settings.stdout?.parseLines)
|
|
78
|
+
finishListeners++;
|
|
74
79
|
let streamError;
|
|
75
80
|
const tryFinish = () => {
|
|
76
81
|
if (!--finishListeners)
|
|
@@ -116,6 +121,17 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
116
121
|
throw new Error(`stdout is not defined`);
|
|
117
122
|
if (!p.stderr)
|
|
118
123
|
throw new Error(`stderr is not defined`);
|
|
124
|
+
if (pipe.onWriteProgress) {
|
|
125
|
+
let totalBytes = 0;
|
|
126
|
+
p.stdout.on("data", (chunk) => {
|
|
127
|
+
totalBytes += chunk.length;
|
|
128
|
+
pipe.onWriteProgress({ totalBytes });
|
|
129
|
+
});
|
|
130
|
+
p.stderr.on("data", (chunk) => {
|
|
131
|
+
totalBytes += chunk.length;
|
|
132
|
+
pipe.onWriteProgress({ totalBytes });
|
|
133
|
+
});
|
|
134
|
+
}
|
|
119
135
|
p.stdout.pipe(pipe.stream, { end: false });
|
|
120
136
|
p.stderr.pipe(pipe.stream, { end: false });
|
|
121
137
|
p.on("close", tryFinish);
|
|
@@ -129,10 +145,11 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
129
145
|
if (log.stdout || settings.stdout) {
|
|
130
146
|
if (!p.stdout)
|
|
131
147
|
throw new Error(`stdout is not defined`);
|
|
132
|
-
|
|
148
|
+
const parseLines = settings.stdout?.parseLines;
|
|
149
|
+
const onData = (data) => {
|
|
133
150
|
if (log.stdout)
|
|
134
151
|
logExecStdout({
|
|
135
|
-
data: data.toString(),
|
|
152
|
+
data: parseLines ? `${data}\n` : data.toString(),
|
|
136
153
|
stderr: log.allToStderr,
|
|
137
154
|
colorize: log.colorize,
|
|
138
155
|
});
|
|
@@ -140,7 +157,17 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
140
157
|
spawnData.stdout += data.toString();
|
|
141
158
|
if (settings.stdout?.onData)
|
|
142
159
|
settings.stdout.onData(data.toString());
|
|
143
|
-
}
|
|
160
|
+
};
|
|
161
|
+
if (parseLines) {
|
|
162
|
+
const rl = (0, readline_1.createInterface)({
|
|
163
|
+
input: p.stdout,
|
|
164
|
+
});
|
|
165
|
+
rl.on("line", onData);
|
|
166
|
+
rl.on("close", tryFinish);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
p.stdout.on("data", onData);
|
|
170
|
+
}
|
|
144
171
|
}
|
|
145
172
|
if (log.stderr || settings.stderr) {
|
|
146
173
|
if (!p.stderr)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare type ProgressStats = {
|
|
2
|
+
percent?: number;
|
|
3
|
+
total?: number;
|
|
4
|
+
current?: number;
|
|
5
|
+
description?: string;
|
|
6
|
+
payload?: string;
|
|
7
|
+
format?: "amount" | "size";
|
|
8
|
+
};
|
|
9
|
+
export declare type Progress = {
|
|
10
|
+
absolute?: ProgressStats;
|
|
11
|
+
relative?: ProgressStats;
|
|
12
|
+
};
|
package/util/progress.js
ADDED
package/util/string-util.d.ts
CHANGED
|
@@ -15,5 +15,6 @@ export declare type UriType = {
|
|
|
15
15
|
export declare function formatUri(input: UriType, hidePassword?: boolean): string;
|
|
16
16
|
export declare function formatSeconds(seconds: number): string;
|
|
17
17
|
export declare function makePathPatterns(values: string[] | undefined): string[] | undefined;
|
|
18
|
+
export declare function checkPath(path: string, include: string[], exclude?: string[]): boolean;
|
|
18
19
|
export declare function checkMatch(subject: string | undefined, patterns: string[]): boolean;
|
|
19
20
|
export declare function formatDateTime(datetime: string): string;
|
package/util/string-util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatDateTime = exports.checkMatch = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.lcfirst = exports.ucfirst = exports.serialize = void 0;
|
|
3
|
+
exports.formatDateTime = exports.checkMatch = exports.checkPath = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.lcfirst = exports.ucfirst = 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) {
|
|
@@ -99,6 +99,13 @@ function makePathPatterns(values) {
|
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
exports.makePathPatterns = makePathPatterns;
|
|
102
|
+
function checkPath(path, include, exclude) {
|
|
103
|
+
return ((0, micromatch_1.isMatch)(path, include, {
|
|
104
|
+
dot: true,
|
|
105
|
+
}) &&
|
|
106
|
+
(!exclude || !(0, micromatch_1.isMatch)(path, exclude, { dot: true })));
|
|
107
|
+
}
|
|
108
|
+
exports.checkPath = checkPath;
|
|
102
109
|
function checkMatch(subject, patterns) {
|
|
103
110
|
if (!subject?.length)
|
|
104
111
|
subject = "<empty>";
|
package/util/zip-util.d.ts
CHANGED
|
@@ -3,20 +3,6 @@ export interface ZipDataFilterType {
|
|
|
3
3
|
exclude?: boolean;
|
|
4
4
|
patterns: string[];
|
|
5
5
|
}
|
|
6
|
-
export declare type ZipStreamDataType = {
|
|
7
|
-
type: "progress";
|
|
8
|
-
data: {
|
|
9
|
-
progress: number;
|
|
10
|
-
files: number;
|
|
11
|
-
path: string;
|
|
12
|
-
};
|
|
13
|
-
} | {
|
|
14
|
-
type: "summary";
|
|
15
|
-
data: {
|
|
16
|
-
folders: number;
|
|
17
|
-
files: number;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
6
|
export interface ZipDataType {
|
|
21
7
|
command?: string;
|
|
22
8
|
path: string;
|
|
@@ -26,7 +12,14 @@ export interface ZipDataType {
|
|
|
26
12
|
includeList?: string;
|
|
27
13
|
excludeList?: string;
|
|
28
14
|
verbose?: boolean;
|
|
29
|
-
|
|
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>;
|
|
30
23
|
}
|
|
31
24
|
export interface UnzipDataType {
|
|
32
25
|
command?: string;
|
|
@@ -34,20 +27,71 @@ export interface UnzipDataType {
|
|
|
34
27
|
files?: (ZipDataFilterType | string)[];
|
|
35
28
|
output: string;
|
|
36
29
|
verbose?: boolean;
|
|
37
|
-
|
|
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>;
|
|
38
37
|
}
|
|
39
|
-
export declare
|
|
38
|
+
export declare function buildArguments(filters: (ZipDataFilterType | string)[]): string[];
|
|
39
|
+
export declare function checkSSEOption(command?: string): Promise<boolean>;
|
|
40
|
+
declare 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 declare type ZipStream = {
|
|
40
66
|
type: "progress";
|
|
41
67
|
data: {
|
|
42
68
|
progress: number;
|
|
43
69
|
files: number;
|
|
44
70
|
path: string;
|
|
45
71
|
};
|
|
72
|
+
} | {
|
|
73
|
+
type: "summary";
|
|
74
|
+
data: {
|
|
75
|
+
folders: number;
|
|
76
|
+
files: number;
|
|
77
|
+
};
|
|
46
78
|
};
|
|
47
|
-
export declare function buildArguments(filters: (ZipDataFilterType | string)[]): string[];
|
|
48
|
-
export declare function checkSSEOption(command?: string): Promise<boolean>;
|
|
49
79
|
export declare function zip(data: ZipDataType): Promise<{
|
|
50
80
|
folders: number;
|
|
51
81
|
files: number;
|
|
52
82
|
}>;
|
|
53
|
-
export declare
|
|
83
|
+
export declare 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/util/zip-util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unzip = exports.zip = exports.checkSSEOption = exports.buildArguments = void 0;
|
|
3
|
+
exports.unzip = exports.zip = exports.listZip = exports.checkSSEOption = exports.buildArguments = void 0;
|
|
4
4
|
const process_util_1 = require("./process-util");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
function buildArguments(filters) {
|
|
@@ -30,50 +30,100 @@ function buildArguments(filters) {
|
|
|
30
30
|
return args;
|
|
31
31
|
}
|
|
32
32
|
exports.buildArguments = buildArguments;
|
|
33
|
-
function parseZipStream(chunk, buffer, cb) {
|
|
34
|
-
const lines = chunk.replaceAll("\b", "").trim().split(/\r?\n/);
|
|
35
|
-
for (const line of lines) {
|
|
36
|
-
let matches = null;
|
|
37
|
-
if ((matches = /^(\d+)% (\d+ )?\+/.exec(line))) {
|
|
38
|
-
const path = line.slice(line.indexOf("+") + 1).trim();
|
|
39
|
-
const progress = Number(matches[1]);
|
|
40
|
-
if (!buffer.currentPaths)
|
|
41
|
-
buffer.currentPaths = 0;
|
|
42
|
-
if (path !== buffer.lastPath)
|
|
43
|
-
buffer.currentPaths++;
|
|
44
|
-
buffer.lastPath = path;
|
|
45
|
-
cb({
|
|
46
|
-
type: "progress",
|
|
47
|
-
data: { progress, path, files: buffer.currentPaths },
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
else if (line.startsWith("Add new data to archive:")) {
|
|
51
|
-
const [, folders] = /(\d+) folders?/i.exec(line) || [, 0];
|
|
52
|
-
const [, files] = /(\d+) files?/i.exec(line) || [, 0];
|
|
53
|
-
cb({
|
|
54
|
-
type: "summary",
|
|
55
|
-
data: {
|
|
56
|
-
folders: Number(folders),
|
|
57
|
-
files: Number(files),
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
33
|
let checkSSEOptionResult;
|
|
64
34
|
async function checkSSEOption(command = "7z") {
|
|
65
|
-
const result = await (0, process_util_1.exec)(command
|
|
35
|
+
const result = await (0, process_util_1.exec)(command, [], {}, {
|
|
36
|
+
stdout: {
|
|
37
|
+
save: true,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
66
40
|
if (typeof checkSSEOptionResult === "boolean")
|
|
67
41
|
return checkSSEOptionResult;
|
|
68
42
|
return (checkSSEOptionResult = result.stdout.includes(" -sse"));
|
|
69
43
|
}
|
|
70
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_util_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
|
+
}
|
|
71
116
|
async function zip(data) {
|
|
72
|
-
let
|
|
117
|
+
let summary = {
|
|
73
118
|
folders: 0,
|
|
74
119
|
files: 0,
|
|
75
120
|
};
|
|
76
|
-
|
|
121
|
+
await data.onProgress?.({
|
|
122
|
+
current: 0,
|
|
123
|
+
percent: 0,
|
|
124
|
+
total: 0,
|
|
125
|
+
type: "start",
|
|
126
|
+
});
|
|
77
127
|
await (0, process_util_1.exec)(data.command ?? "7z", [
|
|
78
128
|
"a",
|
|
79
129
|
// https://sourceforge.net/p/sevenzip/bugs/2099/,
|
|
@@ -91,35 +141,58 @@ async function zip(data) {
|
|
|
91
141
|
log: data.verbose ?? false,
|
|
92
142
|
onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
|
|
93
143
|
stdout: {
|
|
94
|
-
onData: (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (stream
|
|
98
|
-
|
|
99
|
-
|
|
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
|
+
}
|
|
100
162
|
},
|
|
101
163
|
},
|
|
102
164
|
});
|
|
103
|
-
|
|
165
|
+
await data.onProgress?.({
|
|
166
|
+
total: summary.files,
|
|
167
|
+
current: summary.files,
|
|
168
|
+
percent: 100,
|
|
169
|
+
type: "end",
|
|
170
|
+
});
|
|
171
|
+
return summary;
|
|
104
172
|
}
|
|
105
173
|
exports.zip = zip;
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
data: { progress, path, files },
|
|
117
|
-
});
|
|
118
|
-
}
|
|
174
|
+
function parseUnzipLine(line) {
|
|
175
|
+
let matches = null;
|
|
176
|
+
if ((matches = /^\s*(\d+)% (\d+) \-/.exec(line))) {
|
|
177
|
+
const progress = Number(matches[1]);
|
|
178
|
+
const files = Number(matches[2]);
|
|
179
|
+
const path = line.slice(line.indexOf("-") + 1).trim();
|
|
180
|
+
return {
|
|
181
|
+
type: "progress",
|
|
182
|
+
data: { percent: progress, path, files },
|
|
183
|
+
};
|
|
119
184
|
}
|
|
120
185
|
}
|
|
121
186
|
async function unzip(data) {
|
|
122
|
-
|
|
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_util_1.exec)(data.command ?? "7z", [
|
|
123
196
|
"x",
|
|
124
197
|
"-bsp1",
|
|
125
198
|
(0, path_1.normalize)(data.input),
|
|
@@ -130,13 +203,34 @@ async function unzip(data) {
|
|
|
130
203
|
log: data.verbose ?? false,
|
|
131
204
|
stderr: { toExitCode: true },
|
|
132
205
|
stdout: {
|
|
133
|
-
...(data.onStream && {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
206
|
+
...((data.onStream || data.onProgress) && {
|
|
207
|
+
parseLines: true,
|
|
208
|
+
onData: async (line) => {
|
|
209
|
+
const stream = parseUnzipLine(line);
|
|
210
|
+
if (stream) {
|
|
211
|
+
if (stream.type === "progress") {
|
|
212
|
+
const current = Math.max(0, stream.data.files - 1);
|
|
213
|
+
summary.files = stream.data.files;
|
|
214
|
+
await data.onProgress?.({
|
|
215
|
+
current,
|
|
216
|
+
percent: stream.data.percent,
|
|
217
|
+
path: stream.data.path,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
await data.onStream?.(stream);
|
|
221
|
+
}
|
|
137
222
|
},
|
|
138
223
|
}),
|
|
139
224
|
},
|
|
140
225
|
});
|
|
226
|
+
await data.onProgress?.({
|
|
227
|
+
current: summary.files,
|
|
228
|
+
percent: 100,
|
|
229
|
+
type: "end",
|
|
230
|
+
});
|
|
231
|
+
return {
|
|
232
|
+
...result,
|
|
233
|
+
...summary,
|
|
234
|
+
};
|
|
141
235
|
}
|
|
142
236
|
exports.unzip = unzip;
|