@datatruck/cli 0.17.2 → 0.19.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 +4 -2
- 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 -14
- package/Repository/DatatruckRepository.js +115 -298
- 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 +1 -0
- package/Task/MariadbTask.d.ts +11 -0
- package/Task/MariadbTask.js +234 -51
- package/Task/MssqlTask.js +2 -1
- package/Task/ScriptTask.js +1 -0
- package/Task/SqlDumpTaskAbstract.js +1 -0
- package/Task/TaskAbstract.js +2 -1
- package/config.schema.json +67 -37
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +10 -9
- package/utils/DataFormat.js +1 -0
- package/utils/Git.js +1 -0
- package/utils/ObjectVault.js +3 -5
- package/utils/Restic.js +1 -0
- package/utils/datatruck/config.d.ts +1 -1
- package/utils/fs.d.ts +17 -2
- package/utils/fs.js +58 -7
- package/utils/process.d.ts +55 -3
- package/utils/process.js +159 -19
- package/utils/tar.d.ts +32 -0
- package/utils/tar.js +92 -0
- package/utils/zip.d.ts +0 -97
- package/utils/zip.js +0 -238
package/utils/fs.js
CHANGED
|
@@ -3,8 +3,9 @@ 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.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = exports.tmpDir = exports.rmTmpDir = exports.isTmpDir = 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;
|
|
6
|
+
exports.createFileScanner = 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.rmTmpDir = exports.isTmpDir = 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
|
+
const math_1 = require("./math");
|
|
8
9
|
const path_1 = require("./path");
|
|
9
10
|
const async_1 = require("async");
|
|
10
11
|
const crypto_1 = require("crypto");
|
|
@@ -66,12 +67,9 @@ async function isDirEmpty(path) {
|
|
|
66
67
|
}
|
|
67
68
|
exports.isDirEmpty = isDirEmpty;
|
|
68
69
|
async function mkdirIfNotExists(path) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
catch (e) { }
|
|
70
|
+
await (0, promises_1.mkdir)(path, {
|
|
71
|
+
recursive: true,
|
|
72
|
+
});
|
|
75
73
|
return path;
|
|
76
74
|
}
|
|
77
75
|
exports.mkdirIfNotExists = mkdirIfNotExists;
|
|
@@ -458,3 +456,56 @@ async function cpy(options) {
|
|
|
458
456
|
return stats;
|
|
459
457
|
}
|
|
460
458
|
exports.cpy = cpy;
|
|
459
|
+
async function createFileScanner(options) {
|
|
460
|
+
const object = {
|
|
461
|
+
disposed: false,
|
|
462
|
+
total: 0,
|
|
463
|
+
current: 0,
|
|
464
|
+
progress: async (description, path) => {
|
|
465
|
+
if (object.disposed)
|
|
466
|
+
return;
|
|
467
|
+
if (path)
|
|
468
|
+
object.current++;
|
|
469
|
+
await options.onProgress({
|
|
470
|
+
relative: {
|
|
471
|
+
description,
|
|
472
|
+
payload: path,
|
|
473
|
+
},
|
|
474
|
+
absolute: {
|
|
475
|
+
total: object.total,
|
|
476
|
+
current: object.current,
|
|
477
|
+
percent: (0, math_1.progressPercent)(object.total, object.current),
|
|
478
|
+
},
|
|
479
|
+
});
|
|
480
|
+
},
|
|
481
|
+
end: async () => {
|
|
482
|
+
if (!object.disposed)
|
|
483
|
+
await object.progress("Finished");
|
|
484
|
+
object.disposed = true;
|
|
485
|
+
},
|
|
486
|
+
start: async (cb) => {
|
|
487
|
+
let lastTime = performance.now();
|
|
488
|
+
await object.progress("Scanning files");
|
|
489
|
+
for await (const entry of pathIterator(stream)) {
|
|
490
|
+
if (cb) {
|
|
491
|
+
if (await cb(entry))
|
|
492
|
+
object.total++;
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
object.total++;
|
|
496
|
+
}
|
|
497
|
+
if (lastTime - performance.now() > 500)
|
|
498
|
+
await object.progress("Scanning files");
|
|
499
|
+
}
|
|
500
|
+
await object.progress("Scanned files");
|
|
501
|
+
},
|
|
502
|
+
};
|
|
503
|
+
const stream = fast_glob_1.default.stream(options.glob.include, {
|
|
504
|
+
dot: true,
|
|
505
|
+
markDirectories: true,
|
|
506
|
+
stats: true,
|
|
507
|
+
...options.glob,
|
|
508
|
+
});
|
|
509
|
+
return object;
|
|
510
|
+
}
|
|
511
|
+
exports.createFileScanner = createFileScanner;
|
package/utils/process.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
import { SpawnOptions, ChildProcess, ChildProcessByStdio } from "child_process";
|
|
4
5
|
import { ReadStream, WriteStream } from "fs";
|
|
6
|
+
import { Readable, Writable } from "stream";
|
|
5
7
|
export type ExecLogSettingsType = {
|
|
6
8
|
colorize?: boolean;
|
|
7
9
|
exec?: boolean;
|
|
@@ -13,18 +15,22 @@ export type ExecLogSettingsType = {
|
|
|
13
15
|
export interface ExecSettingsInterface {
|
|
14
16
|
exec?: boolean;
|
|
15
17
|
pipe?: {
|
|
16
|
-
stream: WriteStream
|
|
18
|
+
stream: WriteStream;
|
|
17
19
|
onWriteProgress?: (data: {
|
|
18
20
|
totalBytes: number;
|
|
19
21
|
}) => void;
|
|
22
|
+
} | {
|
|
23
|
+
stream: ReadStream;
|
|
20
24
|
onReadProgress?: (data: {
|
|
21
25
|
totalBytes: number;
|
|
22
26
|
currentBytes: number;
|
|
23
27
|
progress: number;
|
|
24
28
|
}) => void;
|
|
29
|
+
} | {
|
|
30
|
+
stream: Readable;
|
|
25
31
|
};
|
|
26
32
|
log?: ExecLogSettingsType | boolean;
|
|
27
|
-
onSpawn?: (p: ChildProcess) =>
|
|
33
|
+
onSpawn?: (p: ChildProcess) => any;
|
|
28
34
|
stdout?: {
|
|
29
35
|
save?: boolean;
|
|
30
36
|
parseLines?: boolean;
|
|
@@ -49,6 +55,52 @@ export type ExecResultType = {
|
|
|
49
55
|
stderr: string;
|
|
50
56
|
exitCode: number;
|
|
51
57
|
};
|
|
58
|
+
export type ParseStreamDataOptions<S extends boolean = boolean> = {
|
|
59
|
+
save?: S;
|
|
60
|
+
parseLines?: boolean;
|
|
61
|
+
log?: LogProcessOptions | boolean;
|
|
62
|
+
onData?: (data: string) => void;
|
|
63
|
+
};
|
|
64
|
+
export declare function parseStreamData<S extends boolean>(stream: Readable, options?: ParseStreamDataOptions<S>): Promise<S extends true ? string : undefined>;
|
|
65
|
+
type OnExitCode = OnExitCodeValue | ((code: number) => OnExitCodeValue | void | undefined);
|
|
66
|
+
type OnExitCodeValue = Error | string | number | boolean;
|
|
67
|
+
export declare function waitForClose<O extends boolean, E extends boolean>(p: ChildProcess, options?: {
|
|
68
|
+
strict?: boolean;
|
|
69
|
+
stdout?: O;
|
|
70
|
+
stderr?: E;
|
|
71
|
+
onExitCode?: OnExitCode;
|
|
72
|
+
}): Promise<{
|
|
73
|
+
exitCode: number;
|
|
74
|
+
} & (O extends true ? {
|
|
75
|
+
stdout: string;
|
|
76
|
+
} : {}) & (E extends true ? {
|
|
77
|
+
stderr: string;
|
|
78
|
+
} : {})>;
|
|
79
|
+
export type LogProcessOptions = {
|
|
80
|
+
envNames?: string[];
|
|
81
|
+
env?: Record<string, any>;
|
|
82
|
+
pipe?: Readable | Writable;
|
|
83
|
+
toStderr?: boolean;
|
|
84
|
+
colorize?: boolean;
|
|
85
|
+
};
|
|
86
|
+
export declare function logProcessExec(command: string, argv: any[], options: LogProcessOptions): Promise<void>;
|
|
87
|
+
export type ProcessOptions<O1 extends boolean, O2 extends boolean> = {
|
|
88
|
+
$stdout?: Omit<ParseStreamDataOptions<O1>, "log">;
|
|
89
|
+
$stderr?: Omit<ParseStreamDataOptions<O2>, "log">;
|
|
90
|
+
$onExitCode?: OnExitCode;
|
|
91
|
+
$log?: boolean | {
|
|
92
|
+
exec?: boolean | LogProcessOptions;
|
|
93
|
+
stdout?: boolean | LogProcessOptions;
|
|
94
|
+
stderr?: boolean | LogProcessOptions;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
export declare function createProcess<O1 extends boolean, O2 extends boolean>(command: string, argv?: (string | number)[], options?: SpawnOptions & ProcessOptions<O1, O2>): ChildProcessByStdio<Writable, Readable, Readable> & PromiseLike<{
|
|
98
|
+
exitCode: number;
|
|
99
|
+
} & (O1 extends true ? {
|
|
100
|
+
stdout: string;
|
|
101
|
+
} : {}) & (O2 extends true ? {
|
|
102
|
+
stderr: string;
|
|
103
|
+
} : {})>;
|
|
52
104
|
export declare function exec(command: string, argv?: string[], options?: SpawnOptions | null, settings?: ExecSettingsInterface): Promise<ExecResultType>;
|
|
53
105
|
type EventNameType = "exit" | "SIGINT" | "SIGUSR1" | "SIGUSR2" | "SIGTERM" | "uncaughtException";
|
|
54
106
|
export declare function onExit(cb: (eventName: EventNameType, ...args: any[]) => void): void;
|
package/utils/process.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.onExit = exports.exec = exports.logExecStderr = exports.logExecStdout = void 0;
|
|
6
|
+
exports.onExit = exports.exec = exports.createProcess = exports.logProcessExec = exports.waitForClose = exports.parseStreamData = exports.logExecStderr = exports.logExecStdout = void 0;
|
|
7
7
|
const cli_1 = require("./cli");
|
|
8
8
|
const fs_1 = require("./fs");
|
|
9
9
|
const math_1 = require("./math");
|
|
@@ -12,6 +12,7 @@ const child_process_1 = require("child_process");
|
|
|
12
12
|
const fs_2 = require("fs");
|
|
13
13
|
const promises_1 = require("fs/promises");
|
|
14
14
|
const readline_1 = require("readline");
|
|
15
|
+
const stream_1 = require("stream");
|
|
15
16
|
function logExecStdout(input) {
|
|
16
17
|
let text = input.colorize ? chalk_1.default.grey(input.data) : input.data;
|
|
17
18
|
if (input.lineSalt)
|
|
@@ -23,6 +24,152 @@ function logExecStderr(data, colorize) {
|
|
|
23
24
|
process.stdout.write(colorize ? chalk_1.default.red(data) : data);
|
|
24
25
|
}
|
|
25
26
|
exports.logExecStderr = logExecStderr;
|
|
27
|
+
function parseStreamData(stream, options = {}) {
|
|
28
|
+
const log = options.log === true ? {} : options.log;
|
|
29
|
+
let result;
|
|
30
|
+
if (options.save)
|
|
31
|
+
result = "";
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const lines = options.parseLines;
|
|
34
|
+
const onData = (data) => {
|
|
35
|
+
if (options.onData)
|
|
36
|
+
options.onData(data.toString());
|
|
37
|
+
if (log)
|
|
38
|
+
logExecStdout({
|
|
39
|
+
data: lines ? `${data}\n` : data.toString(),
|
|
40
|
+
stderr: log.toStderr,
|
|
41
|
+
colorize: log.colorize,
|
|
42
|
+
});
|
|
43
|
+
if (options?.save)
|
|
44
|
+
result += data.toString();
|
|
45
|
+
};
|
|
46
|
+
if (lines) {
|
|
47
|
+
const rl = (0, readline_1.createInterface)({
|
|
48
|
+
input: stream,
|
|
49
|
+
});
|
|
50
|
+
rl.on("line", onData).on("close", () => resolve(result));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
stream
|
|
54
|
+
.on("data", onData)
|
|
55
|
+
.on("error", reject)
|
|
56
|
+
.once("close", () => resolve(result));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
exports.parseStreamData = parseStreamData;
|
|
61
|
+
function waitForClose(p, options = {}) {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
let result = {
|
|
64
|
+
exitCode: 1,
|
|
65
|
+
};
|
|
66
|
+
if (options.stdout) {
|
|
67
|
+
result.stdout = "";
|
|
68
|
+
p.stdout.on("data", (data) => (result.stdout += data.toString()));
|
|
69
|
+
}
|
|
70
|
+
p.once("error", reject).once("close", (exitCode) => {
|
|
71
|
+
if (exitCode) {
|
|
72
|
+
let onExitCode = options.onExitCode ?? true;
|
|
73
|
+
if (typeof onExitCode === "function") {
|
|
74
|
+
onExitCode = onExitCode(exitCode);
|
|
75
|
+
}
|
|
76
|
+
if (typeof onExitCode === "string") {
|
|
77
|
+
reject(new Error(onExitCode));
|
|
78
|
+
}
|
|
79
|
+
else if (typeof onExitCode === "number") {
|
|
80
|
+
reject(new Error(`Exit code: ${onExitCode}`));
|
|
81
|
+
}
|
|
82
|
+
else if (onExitCode instanceof Error) {
|
|
83
|
+
reject(onExitCode);
|
|
84
|
+
}
|
|
85
|
+
else if (onExitCode === false) {
|
|
86
|
+
resolve({ ...result, exitCode: exitCode });
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
reject(new Error(`Exit code: ${exitCode}`));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
resolve({ ...result, exitCode: exitCode });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
exports.waitForClose = waitForClose;
|
|
99
|
+
async function logProcessExec(command, argv, options) {
|
|
100
|
+
const logEnv = options.envNames?.reduce((env, key) => {
|
|
101
|
+
const value = options?.env?.[key];
|
|
102
|
+
if (typeof value !== "undefined")
|
|
103
|
+
env[key] = value;
|
|
104
|
+
return env;
|
|
105
|
+
}, {});
|
|
106
|
+
(0, cli_1.logExec)(command, options.pipe
|
|
107
|
+
? [
|
|
108
|
+
...argv,
|
|
109
|
+
options.pipe instanceof stream_1.Readable ? "<" : ">",
|
|
110
|
+
"path" in options.pipe ? String(options.pipe.path) : "[stream]",
|
|
111
|
+
]
|
|
112
|
+
: argv, logEnv, options.toStderr);
|
|
113
|
+
}
|
|
114
|
+
exports.logProcessExec = logProcessExec;
|
|
115
|
+
function createProcess(command, argv = [], options = {}) {
|
|
116
|
+
const $log = options.$log === true
|
|
117
|
+
? { exec: {}, stdout: {}, stderr: {} }
|
|
118
|
+
: options.$log || {};
|
|
119
|
+
if ($log.exec)
|
|
120
|
+
logProcessExec(command, argv, $log.exec === true ? {} : $log.exec);
|
|
121
|
+
if (typeof options.cwd === "string") {
|
|
122
|
+
let isDir = false;
|
|
123
|
+
try {
|
|
124
|
+
isDir = (0, fs_2.statSync)(options.cwd).isDirectory();
|
|
125
|
+
}
|
|
126
|
+
catch (error) { }
|
|
127
|
+
if (!isDir)
|
|
128
|
+
throw new Error(`Current working directory does not exist: ${options.cwd}`);
|
|
129
|
+
}
|
|
130
|
+
const handler = (0, child_process_1.spawn)(command, argv.map((v) => (typeof v === "number" ? v.toString() : v)), options ?? {});
|
|
131
|
+
const { $stdout, $stderr, $onExitCode } = options;
|
|
132
|
+
async function exec() {
|
|
133
|
+
const [stdout, stderr, result] = await Promise.all([
|
|
134
|
+
(!!$log.stdout || !!$stdout) &&
|
|
135
|
+
parseStreamData(handler.stdout, {
|
|
136
|
+
log: $log.stdout,
|
|
137
|
+
...$stdout,
|
|
138
|
+
}),
|
|
139
|
+
(!!$log.stderr || !!$stderr) &&
|
|
140
|
+
parseStreamData(handler.stderr, {
|
|
141
|
+
log: $log.stderr,
|
|
142
|
+
...$stderr,
|
|
143
|
+
}),
|
|
144
|
+
waitForClose(handler, {
|
|
145
|
+
onExitCode: $onExitCode,
|
|
146
|
+
}),
|
|
147
|
+
]);
|
|
148
|
+
const endResult = {
|
|
149
|
+
exitCode: result.exitCode,
|
|
150
|
+
};
|
|
151
|
+
if (typeof stdout === "string")
|
|
152
|
+
endResult.stdout = stdout;
|
|
153
|
+
if (typeof stderr === "string")
|
|
154
|
+
endResult.stderr = stderr;
|
|
155
|
+
return endResult;
|
|
156
|
+
}
|
|
157
|
+
const promise = {
|
|
158
|
+
[Symbol.toStringTag]: "process",
|
|
159
|
+
then: function (onfulfilled, onrejected) {
|
|
160
|
+
return exec().then(onfulfilled, onrejected);
|
|
161
|
+
},
|
|
162
|
+
catch: function (onrejected) {
|
|
163
|
+
return exec().catch(onrejected);
|
|
164
|
+
},
|
|
165
|
+
finally: function (onfinally) {
|
|
166
|
+
return exec().finally(onfinally);
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
Object.assign(handler, promise);
|
|
170
|
+
return handler;
|
|
171
|
+
}
|
|
172
|
+
exports.createProcess = createProcess;
|
|
26
173
|
async function exec(command, argv = [], options = null, settings = {}) {
|
|
27
174
|
const pipe = settings.pipe;
|
|
28
175
|
let log = {};
|
|
@@ -34,23 +181,16 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
34
181
|
}
|
|
35
182
|
return new Promise(async (resolve, reject) => {
|
|
36
183
|
if (log.exec) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
(0, cli_1.logExec)(command, pipe
|
|
44
|
-
? [
|
|
45
|
-
...argv,
|
|
46
|
-
pipe.stream instanceof fs_2.ReadStream ? "<" : ">",
|
|
47
|
-
String(pipe.stream.path),
|
|
48
|
-
]
|
|
49
|
-
: argv, logEnv, log.allToStderr);
|
|
184
|
+
logProcessExec(command, argv, {
|
|
185
|
+
env: options?.env,
|
|
186
|
+
envNames: log.envNames,
|
|
187
|
+
pipe: pipe?.stream,
|
|
188
|
+
toStderr: log.allToStderr,
|
|
189
|
+
});
|
|
50
190
|
}
|
|
51
191
|
if (typeof options?.cwd === "string" && !(await (0, fs_1.checkDir)(options.cwd)))
|
|
52
|
-
|
|
53
|
-
if (pipe?.
|
|
192
|
+
throw new Error(`Current working directory does not exist: ${options.cwd}`);
|
|
193
|
+
if (pipe?.stream instanceof fs_2.ReadStream && "onReadProgress" in pipe) {
|
|
54
194
|
const fileInfo = await (0, promises_1.stat)(pipe.stream.path);
|
|
55
195
|
const totalBytes = fileInfo.size;
|
|
56
196
|
let currentBytes = 0;
|
|
@@ -64,7 +204,7 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
64
204
|
});
|
|
65
205
|
}
|
|
66
206
|
const p = (0, child_process_1.spawn)(command, argv, options ?? {});
|
|
67
|
-
settings.onSpawn?.(p);
|
|
207
|
+
await settings.onSpawn?.(p);
|
|
68
208
|
let spawnError;
|
|
69
209
|
const spawnData = {
|
|
70
210
|
stdout: "",
|
|
@@ -121,7 +261,7 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
121
261
|
throw new Error(`stdout is not defined`);
|
|
122
262
|
if (!p.stderr)
|
|
123
263
|
throw new Error(`stderr is not defined`);
|
|
124
|
-
if (pipe.onWriteProgress) {
|
|
264
|
+
if ("onWriteProgress" in pipe && pipe.onWriteProgress) {
|
|
125
265
|
let totalBytes = 0;
|
|
126
266
|
p.stdout.on("data", (chunk) => {
|
|
127
267
|
totalBytes += chunk.length;
|
|
@@ -136,7 +276,7 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
136
276
|
p.stderr.pipe(pipe.stream, { end: false });
|
|
137
277
|
p.on("close", tryFinish);
|
|
138
278
|
}
|
|
139
|
-
else if (pipe.stream instanceof
|
|
279
|
+
else if (pipe.stream instanceof stream_1.Readable) {
|
|
140
280
|
if (!p.stdin)
|
|
141
281
|
throw new Error(`stdin is not defined`);
|
|
142
282
|
pipe.stream.pipe(p.stdin);
|
package/utils/tar.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
include: string[];
|
|
15
|
+
compress?: boolean;
|
|
16
|
+
onEntry?: (entry: TarEntry) => void;
|
|
17
|
+
}
|
|
18
|
+
export interface ExtractOptions {
|
|
19
|
+
input: string;
|
|
20
|
+
output: string;
|
|
21
|
+
verbose?: boolean;
|
|
22
|
+
total?: number;
|
|
23
|
+
onEntry?: (entry: TarEntry) => void;
|
|
24
|
+
}
|
|
25
|
+
export type ListTarOptions = {
|
|
26
|
+
input: string;
|
|
27
|
+
onEntry?: (entry: Pick<TarEntry, "path">) => void;
|
|
28
|
+
verbose?: boolean;
|
|
29
|
+
};
|
|
30
|
+
export declare function listTar(options: ListTarOptions): Promise<number>;
|
|
31
|
+
export declare function createTar(options: CreateTarOptions): Promise<void>;
|
|
32
|
+
export declare function extractTar(options: ExtractOptions): Promise<void>;
|
package/utils/tar.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.extractTar = exports.createTar = exports.listTar = void 0;
|
|
7
|
+
const cli_1 = require("./cli");
|
|
8
|
+
const fs_1 = require("./fs");
|
|
9
|
+
const math_1 = require("./math");
|
|
10
|
+
const fs_2 = require("fs");
|
|
11
|
+
const promises_1 = require("fs/promises");
|
|
12
|
+
const tar_1 = __importDefault(require("tar"));
|
|
13
|
+
async function listTar(options) {
|
|
14
|
+
if (options.verbose)
|
|
15
|
+
(0, cli_1.logExec)("tar", ["-ztvf", options.input]);
|
|
16
|
+
let total = 0;
|
|
17
|
+
await tar_1.default.list({
|
|
18
|
+
file: options.input,
|
|
19
|
+
onentry(entry) {
|
|
20
|
+
options.onEntry?.({ path: entry.path });
|
|
21
|
+
total++;
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
return total;
|
|
25
|
+
}
|
|
26
|
+
exports.listTar = listTar;
|
|
27
|
+
async function createTar(options) {
|
|
28
|
+
if (options.verbose)
|
|
29
|
+
(0, cli_1.logExec)("tar", [
|
|
30
|
+
options.compress ? "-czvf" : "-cvf",
|
|
31
|
+
options.output,
|
|
32
|
+
options.path,
|
|
33
|
+
]);
|
|
34
|
+
let total = options.include.length;
|
|
35
|
+
if (!total)
|
|
36
|
+
throw new Error("'include' option is empty");
|
|
37
|
+
let current = 0;
|
|
38
|
+
let progressPromise;
|
|
39
|
+
const inStream = tar_1.default.create({
|
|
40
|
+
gzip: options.compress,
|
|
41
|
+
cwd: options.path,
|
|
42
|
+
filter(path) {
|
|
43
|
+
current++;
|
|
44
|
+
options.onEntry?.({
|
|
45
|
+
path: path,
|
|
46
|
+
progress: {
|
|
47
|
+
total,
|
|
48
|
+
current,
|
|
49
|
+
percent: (0, math_1.progressPercent)(total, current),
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
return true;
|
|
53
|
+
},
|
|
54
|
+
}, options.include);
|
|
55
|
+
const outStream = (0, fs_2.createWriteStream)(options.output);
|
|
56
|
+
await new Promise((resolve, reject) => {
|
|
57
|
+
inStream.on("error", reject);
|
|
58
|
+
outStream.on("error", reject);
|
|
59
|
+
inStream.pipe(outStream);
|
|
60
|
+
outStream.on("close", resolve);
|
|
61
|
+
});
|
|
62
|
+
await progressPromise;
|
|
63
|
+
}
|
|
64
|
+
exports.createTar = createTar;
|
|
65
|
+
async function extractTar(options) {
|
|
66
|
+
let total = options.total ??
|
|
67
|
+
(await listTar({ input: options.input, verbose: options.verbose }));
|
|
68
|
+
if (options.verbose) {
|
|
69
|
+
(0, cli_1.logExec)("tar", ["-xzvfp", options.input, "-C", options.output]);
|
|
70
|
+
(0, cli_1.logExec)("mkdir", ["-p", options.output]);
|
|
71
|
+
}
|
|
72
|
+
let current = 0;
|
|
73
|
+
await (0, promises_1.mkdir)(options.output, { recursive: true });
|
|
74
|
+
await (0, fs_1.ensureEmptyDir)(options.output);
|
|
75
|
+
await tar_1.default.extract({
|
|
76
|
+
file: options.input,
|
|
77
|
+
cwd: options.output,
|
|
78
|
+
preserveOwner: true,
|
|
79
|
+
onentry(entry) {
|
|
80
|
+
current++;
|
|
81
|
+
options.onEntry?.({
|
|
82
|
+
path: entry.path,
|
|
83
|
+
progress: {
|
|
84
|
+
total,
|
|
85
|
+
current,
|
|
86
|
+
percent: (0, math_1.progressPercent)(total, current),
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
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 {};
|