@datatruck/cli 0.34.0 → 0.34.2

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 (51) hide show
  1. package/config.schema.json +337 -72
  2. package/lib/actions/BackupAction.d.ts +4 -4
  3. package/lib/actions/BackupAction.js +2 -2
  4. package/lib/actions/CopyAction.d.ts +3 -3
  5. package/lib/actions/CopyAction.js +2 -2
  6. package/lib/actions/RestoreAction.d.ts +4 -4
  7. package/lib/actions/RestoreAction.js +2 -2
  8. package/lib/commands/CleanCacheCommand.js +2 -2
  9. package/lib/commands/CommandAbstract.d.ts +4 -4
  10. package/lib/commands/CommandAbstract.js +1 -1
  11. package/lib/commands/ConfigCommand.js +2 -2
  12. package/lib/commands/InitCommand.js +2 -2
  13. package/lib/commands/PruneCommand.js +2 -2
  14. package/lib/commands/SnapshotsCommand.js +2 -2
  15. package/lib/repositories/GitRepository.js +6 -6
  16. package/lib/repositories/ResticRepository.d.ts +1 -1
  17. package/lib/repositories/ResticRepository.js +10 -10
  18. package/lib/tasks/GitTask.js +33 -50
  19. package/lib/tasks/MariadbTask.js +43 -56
  20. package/lib/tasks/MssqlTask.js +5 -11
  21. package/lib/tasks/MysqlDumpTask.js +4 -4
  22. package/lib/tasks/PostgresqlDumpTask.d.ts +1 -1
  23. package/lib/tasks/PostgresqlDumpTask.js +9 -32
  24. package/lib/tasks/SqlDumpTaskAbstract.d.ts +1 -2
  25. package/lib/tasks/SqlDumpTaskAbstract.js +1 -1
  26. package/lib/utils/async-process.d.ts +66 -0
  27. package/lib/utils/async-process.js +242 -0
  28. package/lib/utils/async.d.ts +3 -5
  29. package/lib/utils/async.js +2 -2
  30. package/lib/utils/{DataFormat.d.ts → data-format.d.ts} +4 -4
  31. package/lib/utils/{DataFormat.js → data-format.js} +1 -1
  32. package/lib/utils/datatruck/command.d.ts +2 -2
  33. package/lib/utils/datatruck/config-type.d.ts +1 -1
  34. package/lib/utils/datatruck/cron-server.js +2 -2
  35. package/lib/utils/fs.d.ts +1 -2
  36. package/lib/utils/fs.js +3 -10
  37. package/lib/utils/{Git.d.ts → git.d.ts} +9 -7
  38. package/lib/utils/{Git.js → git.js} +30 -29
  39. package/lib/utils/list.d.ts +4 -4
  40. package/lib/utils/list.js +1 -1
  41. package/lib/utils/mysql.d.ts +8 -10
  42. package/lib/utils/mysql.js +60 -79
  43. package/lib/utils/process.d.ts +3 -92
  44. package/lib/utils/process.js +7 -311
  45. package/lib/utils/{Restic.d.ts → restic.d.ts} +10 -9
  46. package/lib/utils/{Restic.js → restic.js} +72 -82
  47. package/lib/utils/spawnSteps.js +9 -10
  48. package/lib/utils/stream.d.ts +8 -2
  49. package/lib/utils/stream.js +10 -3
  50. package/lib/utils/tar.js +29 -49
  51. package/package.json +2 -2
@@ -1,85 +1,15 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="node" />
3
- /// <reference types="node" />
4
- import { SpawnOptions, ChildProcess, ChildProcessByStdio } from "child_process";
5
- import { ReadStream, WriteStream } from "fs";
6
2
  import { Readable, Writable } from "stream";
7
3
  export type ProcessEnv = {
8
4
  [name: string]: string | undefined;
9
5
  };
10
- export type ExecLogSettings = {
11
- colorize?: boolean;
12
- exec?: boolean;
13
- stdout?: boolean;
14
- stderr?: boolean;
15
- allToStderr?: boolean;
16
- envNames?: string[];
17
- };
18
- export interface ExecSettingsInterface {
19
- exec?: boolean;
20
- pipe?: {
21
- stream: WriteStream;
22
- onWriteProgress?: (data: {
23
- totalBytes: number;
24
- }) => void;
25
- } | {
26
- stream: ReadStream;
27
- onReadProgress?: (data: {
28
- totalBytes: number;
29
- currentBytes: number;
30
- progress: number;
31
- }) => void;
32
- } | {
33
- stream: Readable;
34
- };
35
- log?: ExecLogSettings | boolean;
36
- onSpawn?: (p: ChildProcess) => void | undefined;
37
- stdout?: {
38
- save?: boolean;
39
- parseLines?: boolean | "skip-empty";
40
- onData?: (data: string) => void;
41
- };
42
- stderr?: {
43
- save?: boolean;
44
- parseLines?: boolean | "skip-empty";
45
- onData?: (data: string) => void;
46
- toExitCode?: boolean;
47
- };
48
- onExitCodeError?: (data: ExecResult, error: Error) => Error | false;
49
- }
50
- export declare function logExecStdout(input: {
6
+ export declare function logStdout(input: {
51
7
  data: string;
52
8
  colorize?: boolean;
53
9
  stderr?: boolean;
54
10
  lineSalt?: boolean;
55
11
  }): void;
56
- export declare function logExecStderr(data: string, colorize?: boolean): void;
57
- export type ExecResult = {
58
- stdout: string;
59
- stderr: string;
60
- exitCode: number;
61
- };
62
- export type ParseStreamDataOptions<S extends boolean = boolean> = {
63
- save?: S;
64
- parseLines?: boolean;
65
- log?: LogProcessOptions | boolean;
66
- onData?: (data: string) => void;
67
- };
68
- export declare function parseStreamData<S extends boolean>(stream: Readable, options?: ParseStreamDataOptions<S>): Promise<S extends true ? string : undefined>;
69
- type OnExitCode = OnExitCodeValue | ((code: number) => OnExitCodeValue | void | undefined);
70
- type OnExitCodeValue = Error | string | number | boolean;
71
- export declare function waitForClose<O extends boolean, E extends boolean>(p: ChildProcess, options?: {
72
- strict?: boolean;
73
- stdout?: O;
74
- stderr?: E;
75
- onExitCode?: OnExitCode;
76
- }): Promise<{
77
- exitCode: number;
78
- } & (O extends true ? {
79
- stdout: string;
80
- } : {}) & (E extends true ? {
81
- stderr: string;
82
- } : {})>;
12
+ export declare function logStderr(data: string, colorize?: boolean): void;
83
13
  export type LogProcessOptions = {
84
14
  envNames?: string[];
85
15
  env?: Record<string, any>;
@@ -87,23 +17,4 @@ export type LogProcessOptions = {
87
17
  toStderr?: boolean;
88
18
  colorize?: boolean;
89
19
  };
90
- export declare function logProcessExec(command: string, argv: any[], options: LogProcessOptions): Promise<void>;
91
- export type ProcessOptions<O1 extends boolean, O2 extends boolean> = {
92
- $stdout?: Omit<ParseStreamDataOptions<O1>, "log">;
93
- $stderr?: Omit<ParseStreamDataOptions<O2>, "log">;
94
- $onExitCode?: OnExitCode;
95
- $log?: boolean | {
96
- exec?: boolean | LogProcessOptions;
97
- stdout?: boolean | LogProcessOptions;
98
- stderr?: boolean | LogProcessOptions;
99
- };
100
- };
101
- 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<{
102
- exitCode: number;
103
- } & (O1 extends true ? {
104
- stdout: string;
105
- } : {}) & (O2 extends true ? {
106
- stderr: string;
107
- } : {})>;
108
- export declare function exec(command: string, argv?: string[], options?: SpawnOptions | null, settings?: ExecSettingsInterface): Promise<ExecResult>;
109
- export {};
20
+ export declare function logProcess(command: string, argv: any[], options: LogProcessOptions): Promise<void>;
@@ -3,100 +3,22 @@ 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.exec = exports.createProcess = exports.logProcessExec = exports.waitForClose = exports.parseStreamData = exports.logExecStderr = exports.logExecStdout = void 0;
6
+ exports.logProcess = exports.logStderr = exports.logStdout = void 0;
7
7
  const cli_1 = require("./cli");
8
- const fs_1 = require("./fs");
9
- const math_1 = require("./math");
10
8
  const chalk_1 = __importDefault(require("chalk"));
11
- const child_process_1 = require("child_process");
12
- const fs_2 = require("fs");
13
- const promises_1 = require("fs/promises");
14
- const readline_1 = require("readline");
15
9
  const stream_1 = require("stream");
16
- function logExecStdout(input) {
10
+ function logStdout(input) {
17
11
  let text = input.colorize ? chalk_1.default.grey(input.data) : input.data;
18
12
  if (input.lineSalt)
19
13
  text += "\n";
20
14
  input.stderr ? process.stderr.write(text) : process.stdout.write(text);
21
15
  }
22
- exports.logExecStdout = logExecStdout;
23
- function logExecStderr(data, colorize) {
16
+ exports.logStdout = logStdout;
17
+ function logStderr(data, colorize) {
24
18
  process.stdout.write(colorize ? chalk_1.default.red(data) : data);
25
19
  }
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) {
20
+ exports.logStderr = logStderr;
21
+ async function logProcess(command, argv, options) {
100
22
  const logEnv = options.envNames?.reduce((env, key) => {
101
23
  const value = options?.env?.[key];
102
24
  if (typeof value !== "undefined")
@@ -111,230 +33,4 @@ async function logProcessExec(command, argv, options) {
111
33
  ]
112
34
  : argv, logEnv, options.toStderr);
113
35
  }
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;
173
- async function exec(command, argv = [], options = null, settings = {}) {
174
- const pipe = settings.pipe;
175
- let log = {};
176
- if (settings.log === true) {
177
- log.exec = log.stdout = log.stderr = log.allToStderr = log.colorize = true;
178
- }
179
- else if (settings.log) {
180
- log = settings.log;
181
- }
182
- if (log.exec)
183
- logProcessExec(command, argv, {
184
- env: options?.env,
185
- envNames: log.envNames,
186
- pipe: pipe?.stream,
187
- toStderr: log.allToStderr,
188
- });
189
- if (typeof options?.cwd === "string" && !(await (0, fs_1.existsDir)(options.cwd)))
190
- throw new Error(`Current working directory does not exist: ${options.cwd}`);
191
- if (pipe?.stream instanceof fs_2.ReadStream && "onReadProgress" in pipe) {
192
- const fileInfo = await (0, promises_1.stat)(pipe.stream.path);
193
- const totalBytes = fileInfo.size;
194
- let currentBytes = 0;
195
- pipe.stream.on("data", (data) => {
196
- currentBytes += data.length;
197
- pipe.onReadProgress?.({
198
- totalBytes: totalBytes,
199
- currentBytes: currentBytes,
200
- progress: (0, math_1.progressPercent)(totalBytes, currentBytes),
201
- });
202
- });
203
- }
204
- const p = (0, child_process_1.spawn)(command, argv, options ?? {});
205
- settings.onSpawn?.(p);
206
- let spawnError;
207
- const spawnData = {
208
- stdout: "",
209
- stderr: "",
210
- exitCode: 0,
211
- };
212
- let finishListeners = 1;
213
- if (pipe?.stream instanceof fs_2.WriteStream)
214
- finishListeners++;
215
- if (settings.stdout?.parseLines)
216
- finishListeners++;
217
- if (settings.stderr?.parseLines)
218
- finishListeners++;
219
- let streamError;
220
- return new Promise((resolve, reject) => {
221
- const tryFinish = () => {
222
- if (!--finishListeners)
223
- finish();
224
- };
225
- const finish = () => {
226
- if (spawnData.exitCode) {
227
- let exitCodeError;
228
- if (settings.stderr?.toExitCode) {
229
- exitCodeError = new Error(`Exit code ${spawnData.exitCode}: ${command} ${argv.join(" ")} | ${spawnData.stderr
230
- .split(/\r?\n/g)
231
- .filter((v) => !!v.length)
232
- .join(" | ")}`);
233
- }
234
- else {
235
- exitCodeError = new Error(`Exit code ${spawnData.exitCode}: ${command} ${argv.join(" ")}`);
236
- }
237
- const exitCodeErrorResult = settings.onExitCodeError?.(spawnData, exitCodeError);
238
- if (exitCodeErrorResult instanceof Error) {
239
- return reject(exitCodeErrorResult);
240
- }
241
- else if (exitCodeErrorResult !== false) {
242
- return reject(exitCodeError);
243
- }
244
- }
245
- if (streamError) {
246
- reject(streamError);
247
- }
248
- else if (spawnError) {
249
- reject(spawnError);
250
- }
251
- else {
252
- resolve(spawnData);
253
- }
254
- };
255
- if (pipe) {
256
- pipe.stream.on("error", (error) => {
257
- streamError = error;
258
- tryFinish();
259
- });
260
- if (pipe.stream instanceof fs_2.WriteStream) {
261
- if (!p.stdout)
262
- throw new Error(`stdout is not defined`);
263
- if (!p.stderr)
264
- throw new Error(`stderr is not defined`);
265
- if ("onWriteProgress" in pipe && pipe.onWriteProgress) {
266
- let totalBytes = 0;
267
- p.stdout.on("data", (chunk) => {
268
- totalBytes += chunk.length;
269
- pipe.onWriteProgress({ totalBytes });
270
- });
271
- p.stderr.on("data", (chunk) => {
272
- totalBytes += chunk.length;
273
- pipe.onWriteProgress({ totalBytes });
274
- });
275
- }
276
- p.stdout.pipe(pipe.stream, { end: false });
277
- p.stderr.pipe(pipe.stream, { end: false });
278
- p.on("close", tryFinish);
279
- }
280
- else if (pipe.stream instanceof stream_1.Readable) {
281
- if (!p.stdin)
282
- throw new Error(`stdin is not defined`);
283
- pipe.stream.pipe(p.stdin);
284
- }
285
- }
286
- const stdConfig = {
287
- stdout: { log: log.stdout, settings: settings.stdout },
288
- stderr: { log: log.stderr, settings: settings.stderr },
289
- };
290
- for (const inType in stdConfig) {
291
- const type = inType;
292
- const enabled = log[type] || settings[type];
293
- if (!enabled)
294
- continue;
295
- if (!p[type])
296
- throw new Error(`${type} is not defined`);
297
- const parseLines = settings[type]?.parseLines;
298
- const skipEmptyLines = parseLines === "skip-empty";
299
- const onData = (inData) => {
300
- let data = inData.toString();
301
- if (parseLines) {
302
- if (skipEmptyLines && !data.trim().length)
303
- return;
304
- data = `${inData}\n`;
305
- }
306
- if (log[type])
307
- logExecStdout({
308
- data,
309
- stderr: log.allToStderr,
310
- colorize: log.colorize,
311
- });
312
- if (settings[type]?.save ||
313
- (type === "stderr" && settings[type]?.toExitCode))
314
- spawnData[type] += data;
315
- if (settings[type]?.onData)
316
- settings[type].onData(inData.toString());
317
- };
318
- if (parseLines) {
319
- const rl = (0, readline_1.createInterface)({
320
- input: p[type],
321
- });
322
- rl.on("line", onData);
323
- rl.on("close", tryFinish);
324
- }
325
- else if (log[type] ||
326
- settings[type]?.save ||
327
- settings[type]?.onData ||
328
- (type === "stderr" && settings[type]?.toExitCode)) {
329
- p[type].on("data", onData);
330
- }
331
- }
332
- p.on("error", (error) => (spawnError = error)).on("close", (exitCode) => {
333
- spawnData.exitCode = exitCode ?? 0;
334
- if (pipe?.stream instanceof fs_2.WriteStream)
335
- pipe.stream.end();
336
- tryFinish();
337
- });
338
- });
339
- }
340
- exports.exec = exec;
36
+ exports.logProcess = logProcess;
@@ -1,4 +1,5 @@
1
- import { ExecResult, ExecSettingsInterface, ProcessEnv } from "./process";
1
+ import { AsyncProcess, AsyncProcessOptions } from "./async-process";
2
+ import { ProcessEnv } from "./process";
2
3
  import { Uri } from "./string";
3
4
  export type ResticRepositoryUri = {
4
5
  name?: string;
@@ -46,9 +47,9 @@ export declare class Restic {
46
47
  env: Record<string, string>;
47
48
  });
48
49
  static formatRepository(input: ResticRepositoryUri, hidePassword?: boolean): Promise<string>;
49
- exec(args: string[], settings?: ExecSettingsInterface, options?: {
50
- cwd?: string;
51
- }): Promise<ExecResult>;
50
+ private createProcess;
51
+ exec(args: string[], options?: AsyncProcessOptions): Promise<number>;
52
+ private stdout;
52
53
  checkRepository(): Promise<boolean>;
53
54
  forget(options: {
54
55
  snapshotId?: string;
@@ -62,7 +63,7 @@ export declare class Restic {
62
63
  keepTag?: string[];
63
64
  tag?: string[];
64
65
  prune?: boolean;
65
- }): Promise<string>;
66
+ }): Promise<void>;
66
67
  snapshots(options: {
67
68
  tags?: string[];
68
69
  paths?: string[];
@@ -91,11 +92,11 @@ export declare class Restic {
91
92
  allowEmptySnapshot?: boolean;
92
93
  onStream?: (data: ResticBackupStream) => void;
93
94
  createEmptyDir?: () => Promise<string>;
94
- }): Promise<ExecResult>;
95
+ }): Promise<void>;
95
96
  copy(options: {
96
97
  id: string;
97
98
  onStream?: (data: ResticBackupStream) => void;
98
- }): Promise<ExecResult>;
99
+ }): Promise<void>;
99
100
  restore(options: {
100
101
  id: string;
101
102
  target: string;
@@ -103,6 +104,6 @@ export declare class Restic {
103
104
  * @default 30_000
104
105
  */
105
106
  progressInterval?: number | false;
106
- onStream?: (data: ResticBackupStream) => Promise<void>;
107
- }): Promise<ExecResult>;
107
+ onStream?: (data: ResticBackupStream) => void;
108
+ }): Promise<AsyncProcess>;
108
109
  }