@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,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Restic = void 0;
4
+ const async_process_1 = require("./async-process");
4
5
  const fs_1 = require("./fs");
5
- const process_1 = require("./process");
6
6
  const string_1 = require("./string");
7
7
  const promises_1 = require("fs/promises");
8
8
  const path_1 = require("path");
@@ -28,14 +28,11 @@ class Restic {
28
28
  }
29
29
  return `${input.backend}:${(0, string_1.formatUri)({ ...input, password: input.password }, hidePassword)}`;
30
30
  }
31
- async exec(args, settings, options) {
32
- return await (0, process_1.exec)("restic", args, {
31
+ createProcess(args, options) {
32
+ return new async_process_1.AsyncProcess("restic", args, {
33
33
  stdio: ["ignore", "pipe", "pipe"],
34
34
  env: { ...process.env, ...this.options.env },
35
- cwd: options?.cwd,
36
- }, {
37
- stderr: { toExitCode: true },
38
- log: this.options.log
35
+ $log: this.options.log
39
36
  ? {
40
37
  exec: true,
41
38
  stdout: true,
@@ -49,17 +46,22 @@ class Restic {
49
46
  ],
50
47
  }
51
48
  : {},
52
- ...(settings ?? {}),
49
+ ...(options ?? {}),
53
50
  });
54
51
  }
52
+ async exec(args, options) {
53
+ return await this.createProcess(args, options).waitForClose();
54
+ }
55
+ async stdout(args, options) {
56
+ return await this.createProcess(args, options).stdout.fetch();
57
+ }
55
58
  async checkRepository() {
56
- const result = await this.exec(["cat", "config"], {
57
- onExitCodeError: () => false,
58
- });
59
- return result.exitCode === 0;
59
+ return ((await this.exec(["cat", "config"], {
60
+ $exitCode: false,
61
+ })) === 0);
60
62
  }
61
63
  async forget(options) {
62
- const result = await this.exec([
64
+ await this.exec([
63
65
  "forget",
64
66
  ...(options.keepLast ? ["--keep-last", options.keepLast.toString()] : []),
65
67
  ...(options.keepHourly
@@ -87,58 +89,46 @@ class Restic {
87
89
  ...(options.prune ? ["--prune"] : []),
88
90
  ...(options.snapshotId ? [options.snapshotId] : []),
89
91
  ]);
90
- return result.stdout;
91
92
  }
92
93
  async snapshots(options) {
93
- const result = await this.exec([
94
+ const json = await this.stdout([
94
95
  "snapshots",
95
96
  ...(options.tags?.flatMap((tag) => [`--tag`, tag]) ?? []),
96
97
  ...(options.json ? ["--json"] : []),
97
98
  ...(options.paths?.flatMap((path) => ["--path", path]) ?? []),
98
99
  ...(options.latest ? ["--latest", options.latest.toString()] : []),
99
100
  ...(options.snapshotIds || []),
100
- ], {
101
- stdout: { save: true },
102
- });
103
- return JSON.parse(result.stdout);
101
+ ]);
102
+ return JSON.parse(json);
104
103
  }
105
104
  async backup(options) {
106
- const exec = async () => await this.exec([
107
- "backup",
108
- "--json",
109
- ...(options.exclude?.flatMap((v) => ["-e", v]) ?? []),
110
- ...(options.excludeFile?.flatMap((v) => ["--exclude-file", v]) ?? []),
111
- ...(options.tags?.flatMap((v) => ["--tag", v]) ?? []),
112
- ...(options.setPaths?.flatMap((v) => ["--set-path", v]) ?? []),
113
- ...(options.parent ? ["--parent", options.parent] : []),
114
- ...options.paths,
115
- ], {
116
- stderr: {
117
- toExitCode: true,
118
- },
119
- stdout: {
120
- ...(options.onStream && {
121
- onData: (data) => {
122
- for (const rawLine of data.split("\n")) {
123
- const line = rawLine.trim();
124
- if (line.startsWith("{") && line.endsWith("}")) {
125
- let parsedLine;
126
- try {
127
- parsedLine = JSON.parse(line);
128
- }
129
- catch (error) { }
130
- if (parsedLine)
131
- options.onStream?.(parsedLine);
132
- }
133
- }
134
- },
135
- }),
136
- },
137
- }, {
138
- cwd: options.cwd,
139
- });
140
105
  try {
141
- return await exec();
106
+ const backup = this.createProcess([
107
+ "backup",
108
+ "--json",
109
+ ...(options.exclude?.flatMap((v) => ["-e", v]) ?? []),
110
+ ...(options.excludeFile?.flatMap((v) => ["--exclude-file", v]) ?? []),
111
+ ...(options.tags?.flatMap((v) => ["--tag", v]) ?? []),
112
+ ...(options.setPaths?.flatMap((v) => ["--set-path", v]) ?? []),
113
+ ...(options.parent ? ["--parent", options.parent] : []),
114
+ ...options.paths,
115
+ ], { cwd: options.cwd });
116
+ if (options.onStream) {
117
+ await backup.stdout.parseLines((line) => {
118
+ if (line.startsWith("{") && line.endsWith("}")) {
119
+ let parsedLine;
120
+ try {
121
+ parsedLine = JSON.parse(line);
122
+ }
123
+ catch (error) { }
124
+ if (parsedLine)
125
+ options.onStream?.(parsedLine);
126
+ }
127
+ });
128
+ }
129
+ else {
130
+ await backup.waitForClose();
131
+ }
142
132
  }
143
133
  catch (error) {
144
134
  if (options.allowEmptySnapshot &&
@@ -161,20 +151,17 @@ class Restic {
161
151
  }
162
152
  }
163
153
  async copy(options) {
164
- return await this.exec(["copy", "--json", options.id], {
165
- stderr: {
166
- toExitCode: true,
167
- },
168
- stdout: {
169
- ...(options.onStream && {
170
- onData: async (data) => {
171
- if (data.startsWith("{") && data.endsWith("}")) {
172
- await options.onStream?.(JSON.parse(data));
173
- }
174
- },
175
- }),
176
- },
177
- });
154
+ const copy = this.createProcess(["copy", "--json", options.id]);
155
+ if (options.onStream) {
156
+ await copy.stdout.parseLines((line) => {
157
+ if (line.startsWith("{") && line.endsWith("}")) {
158
+ options.onStream?.(JSON.parse(line));
159
+ }
160
+ });
161
+ }
162
+ else {
163
+ await copy.waitForClose();
164
+ }
178
165
  }
179
166
  async restore(options) {
180
167
  let progressTimeout;
@@ -199,20 +186,23 @@ class Restic {
199
186
  if (typeof progressInterval === "number")
200
187
  progressRutine();
201
188
  try {
202
- const result = await this.exec(["restore", "--json", options.id, "--target", options.target], {
203
- stderr: {
204
- toExitCode: true,
205
- },
206
- stdout: {
207
- ...(options.onStream && {
208
- onData: async (data) => {
209
- if (data.startsWith("{") && data.endsWith("}")) {
210
- await options.onStream?.(JSON.parse(data));
211
- }
212
- },
213
- }),
214
- },
215
- });
189
+ const result = this.createProcess([
190
+ "restore",
191
+ "--json",
192
+ options.id,
193
+ "--target",
194
+ options.target,
195
+ ]);
196
+ if (options.onStream) {
197
+ await result.stdout.parseLines((line) => {
198
+ if (line.startsWith("{") && line.endsWith("}")) {
199
+ options.onStream?.(JSON.parse(line));
200
+ }
201
+ });
202
+ }
203
+ else {
204
+ await result.waitForClose();
205
+ }
216
206
  if (snapshots.at(0)?.tags?.includes(emptySnapshotTag))
217
207
  await (0, promises_1.rm)((0, path_1.join)(options.target, `.${emptySnapshotTag}`));
218
208
  return result;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runSpawnSteps = exports.isSpawnStep = void 0;
4
- const process_1 = require("./process");
4
+ const async_process_1 = require("./async-process");
5
5
  const string_1 = require("./string");
6
6
  const temp_1 = require("./temp");
7
7
  const promises_1 = require("fs/promises");
@@ -49,22 +49,21 @@ async function runSpawnSteps(input, options) {
49
49
  : []),
50
50
  ...(step.config.args || []).map((arg) => (0, string_1.render)(arg.toString(), data)),
51
51
  ];
52
- await (0, process_1.exec)(command, args, {
52
+ const p = new async_process_1.AsyncProcess(command, args, {
53
53
  cwd: options.cwd,
54
54
  env: {
55
55
  ...process.env,
56
56
  ...options.env,
57
57
  ...step.config.env,
58
58
  },
59
- }, {
60
- log: options.verbose,
61
- ...(options.onLine && {
62
- stdout: {
63
- parseLines: "skip-empty",
64
- onData: (line) => options.onLine(line),
65
- },
66
- }),
59
+ $log: options.verbose,
67
60
  });
61
+ if (options.onLine) {
62
+ await p.stdout.parseLines(options.onLine);
63
+ }
64
+ else {
65
+ await p.waitForClose();
66
+ }
68
67
  }
69
68
  else {
70
69
  throw new Error(`Invalid step type: ${step.type}`);
@@ -1,7 +1,13 @@
1
1
  /// <reference types="node" />
2
2
  import { Writable } from "stream";
3
- export type Streams = {
3
+ export type StdStreams = {
4
4
  stdout: Writable;
5
5
  stderr: Writable;
6
6
  };
7
- export declare function createStreams(options?: Partial<Streams>): Streams;
7
+ export declare function createStdStreams(options?: Partial<StdStreams>): StdStreams;
8
+ export declare function waitForClose(stream: {
9
+ on(event: "close", cb: (...args: any[]) => any): any;
10
+ } | {
11
+ on(event: "close", cb: (...args: any[]) => any): any;
12
+ on(event: "error", cb: (...args: any[]) => any): any;
13
+ }): Promise<void>;
@@ -1,10 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createStreams = void 0;
4
- function createStreams(options = {}) {
3
+ exports.waitForClose = exports.createStdStreams = void 0;
4
+ function createStdStreams(options = {}) {
5
5
  return {
6
6
  stdout: options.stdout ?? process.stdout,
7
7
  stderr: options.stderr ?? process.stderr,
8
8
  };
9
9
  }
10
- exports.createStreams = createStreams;
10
+ exports.createStdStreams = createStdStreams;
11
+ async function waitForClose(stream) {
12
+ return new Promise((resolve, reject) => {
13
+ stream.on("close", resolve);
14
+ stream.on("error", reject);
15
+ });
16
+ }
17
+ exports.waitForClose = waitForClose;
package/lib/utils/tar.js CHANGED
@@ -1,30 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractTar = exports.normalizeTarPath = exports.createTar = exports.checkPigzLib = exports.listTar = exports.getTarVendor = void 0;
4
+ const async_process_1 = require("./async-process");
4
5
  const cli_1 = require("./cli");
5
6
  const fs_1 = require("./fs");
6
7
  const math_1 = require("./math");
7
- const process_1 = require("./process");
8
8
  const promises_1 = require("fs/promises");
9
9
  const os_1 = require("os");
10
10
  let tarVendor;
11
11
  async function getTarVendor(cache = true, log = false) {
12
12
  if (cache && typeof tarVendor !== "undefined")
13
13
  return tarVendor;
14
- const p = await (0, process_1.exec)("tar", ["--help"], {}, {
15
- log,
16
- stdout: {
17
- save: true,
18
- },
19
- });
14
+ const stdout = await async_process_1.AsyncProcess.stdout("tar", ["--help"], { $log: log });
20
15
  const find = () => {
21
- if (p.stdout.includes("BusyBox")) {
16
+ if (stdout.includes("BusyBox")) {
22
17
  return "busybox";
23
18
  }
24
- else if (p.stdout.includes("bsdtar")) {
19
+ else if (stdout.includes("bsdtar")) {
25
20
  return "bsdtar";
26
21
  }
27
- else if (p.stdout.includes("GNU")) {
22
+ else if (stdout.includes("GNU")) {
28
23
  return "gnu";
29
24
  }
30
25
  else {
@@ -36,22 +31,14 @@ async function getTarVendor(cache = true, log = false) {
36
31
  exports.getTarVendor = getTarVendor;
37
32
  async function listTar(options) {
38
33
  const vendor = await getTarVendor(true, options.verbose);
39
- let total = 0;
40
- await (0, process_1.exec)("tar", [
34
+ const p = new async_process_1.AsyncProcess("tar", [
41
35
  "-tf",
42
36
  toLocalPath(options.input),
43
37
  ...(vendor === "bsdtar" ? [] : ["--force-local"]),
44
- ], {}, {
45
- log: options.verbose,
46
- stdout: {
47
- parseLines: "skip-empty",
48
- onData: (path) => {
49
- options.onEntry?.({ path: normalizeTarPath(path) });
50
- total++;
51
- },
52
- },
38
+ ], { $log: options.verbose });
39
+ return await p.stdout.parseLines((path) => {
40
+ options.onEntry?.({ path: normalizeTarPath(path) });
53
41
  });
54
- return total;
55
42
  }
56
43
  exports.listTar = listTar;
57
44
  let pigzLib;
@@ -59,7 +46,10 @@ async function checkPigzLib(cache = true) {
59
46
  if (cache && pigzLib !== undefined)
60
47
  return pigzLib;
61
48
  try {
62
- return !(await (0, process_1.exec)("pigz", ["-V"])).exitCode;
49
+ const exitCode = await async_process_1.AsyncProcess.exec("pigz", ["-V"], {
50
+ $exitCode: false,
51
+ });
52
+ return !exitCode;
63
53
  }
64
54
  catch {
65
55
  return false;
@@ -105,7 +95,7 @@ async function createTar(options) {
105
95
  },
106
96
  });
107
97
  };
108
- await (0, process_1.exec)("tar", [
98
+ const p = new async_process_1.AsyncProcess("tar", [
109
99
  "--no-recursion",
110
100
  "-C",
111
101
  toLocalPath(options.path),
@@ -139,21 +129,16 @@ async function createTar(options) {
139
129
  ...process.env,
140
130
  ...env,
141
131
  },
142
- }, {
143
- log: options.verbose
132
+ $log: options.verbose
144
133
  ? { envNames: Object.keys(env), exec: true, stderr: true, stdout: true }
145
134
  : false,
146
- ...(vendor === "bsdtar"
147
- ? {
148
- stderr: options.onEntry
149
- ? { toExitCode: true, parseLines: "skip-empty", onData }
150
- : { toExitCode: true },
151
- }
152
- : {
153
- stderr: { toExitCode: true },
154
- stdout: { parseLines: "skip-empty", onData },
155
- }),
156
135
  });
136
+ if (options.onEntry) {
137
+ await p[vendor === "bsdtar" ? "stderr" : "stdout"].parseLines(onData);
138
+ }
139
+ else {
140
+ await p.waitForClose();
141
+ }
157
142
  }
158
143
  exports.createTar = createTar;
159
144
  /**
@@ -197,7 +182,7 @@ async function extractTar(options) {
197
182
  },
198
183
  });
199
184
  };
200
- await (0, process_1.exec)("tar", [
185
+ const p = new async_process_1.AsyncProcess("tar", [
201
186
  decompress?.cores === 1 ? "-xzvpf" : "-xvpf",
202
187
  toLocalPath(options.input),
203
188
  "-C",
@@ -211,18 +196,13 @@ async function extractTar(options) {
211
196
  decompress.cores > 1 && {
212
197
  shell: true,
213
198
  }),
214
- }, {
215
- log: options.verbose,
216
- ...(vendor === "bsdtar"
217
- ? {
218
- stderr: options.onEntry
219
- ? { toExitCode: true, parseLines: "skip-empty", onData }
220
- : { toExitCode: true },
221
- }
222
- : {
223
- stderr: { toExitCode: true },
224
- stdout: { parseLines: "skip-empty", onData },
225
- }),
199
+ $log: options.verbose,
226
200
  });
201
+ if (options.onEntry) {
202
+ await p[vendor === "bsdtar" ? "stderr" : "stdout"].parseLines(onData);
203
+ }
204
+ else {
205
+ await p.waitForClose();
206
+ }
227
207
  }
228
208
  exports.extractTar = extractTar;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.34.0",
3
+ "version": "0.34.2",
4
4
  "description": "Tool for creating and managing backups",
5
5
  "homepage": "https://github.com/swordev/datatruck#readme",
6
6
  "bugs": {
@@ -37,7 +37,7 @@
37
37
  "fast-glob": "^3.3.2",
38
38
  "listr2": "^8.0.1",
39
39
  "micromatch": "^4.0.5",
40
- "mysql2": "^3.6.5",
40
+ "mysql2": "^3.7.0",
41
41
  "tty-table": "^4.2.3",
42
42
  "yaml": "^2.3.4"
43
43
  },