@datatruck/cli 0.26.2 → 0.28.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.
Files changed (152) hide show
  1. package/Action/BackupAction.d.ts +69 -34
  2. package/Action/BackupAction.js +284 -244
  3. package/Action/CleanCacheAction.d.ts +8 -4
  4. package/Action/CleanCacheAction.js +8 -5
  5. package/Action/ConfigAction.d.ts +12 -5
  6. package/Action/ConfigAction.js +14 -18
  7. package/Action/CopyAction.d.ts +49 -0
  8. package/Action/CopyAction.js +144 -0
  9. package/Action/InitAction.d.ts +3 -3
  10. package/Action/InitAction.js +9 -9
  11. package/Action/PruneAction.d.ts +9 -9
  12. package/Action/PruneAction.js +39 -23
  13. package/Action/RestoreAction.d.ts +48 -23
  14. package/Action/RestoreAction.js +158 -195
  15. package/Action/SnapshotsAction.d.ts +8 -8
  16. package/Action/SnapshotsAction.js +8 -8
  17. package/CHANGELOG.md +495 -0
  18. package/Command/BackupCommand.d.ts +6 -4
  19. package/Command/BackupCommand.js +9 -26
  20. package/Command/CleanCacheCommand.d.ts +4 -4
  21. package/Command/CleanCacheCommand.js +26 -5
  22. package/Command/CommandAbstract.d.ts +10 -7
  23. package/Command/CommandAbstract.js +4 -1
  24. package/Command/ConfigCommand.d.ts +6 -9
  25. package/Command/ConfigCommand.js +13 -8
  26. package/Command/CopyCommand.d.ts +15 -0
  27. package/Command/CopyCommand.js +61 -0
  28. package/Command/InitCommand.d.ts +4 -4
  29. package/Command/InitCommand.js +11 -15
  30. package/Command/PruneCommand.d.ts +3 -3
  31. package/Command/PruneCommand.js +13 -12
  32. package/Command/RestoreCommand.js +9 -17
  33. package/Command/SnapshotsCommand.d.ts +4 -4
  34. package/Command/SnapshotsCommand.js +16 -15
  35. package/Command/StartServerCommand.d.ts +6 -0
  36. package/Command/StartServerCommand.js +24 -0
  37. package/Config/Config.d.ts +11 -0
  38. package/Config/Config.js +43 -0
  39. package/Config/PrunePolicyConfig.d.ts +2 -2
  40. package/Factory/CommandFactory.d.ts +29 -33
  41. package/Factory/CommandFactory.js +32 -53
  42. package/Factory/RepositoryFactory.d.ts +1 -1
  43. package/Factory/RepositoryFactory.js +3 -3
  44. package/Factory/TaskFactory.d.ts +1 -1
  45. package/Factory/TaskFactory.js +3 -3
  46. package/Repository/DatatruckRepository.d.ts +17 -16
  47. package/Repository/DatatruckRepository.js +131 -149
  48. package/Repository/GitRepository.d.ts +9 -8
  49. package/Repository/GitRepository.js +22 -25
  50. package/Repository/RepositoryAbstract.d.ts +39 -37
  51. package/Repository/RepositoryAbstract.js +4 -5
  52. package/Repository/ResticRepository.d.ts +9 -8
  53. package/Repository/ResticRepository.js +30 -28
  54. package/Task/GitTask.d.ts +6 -7
  55. package/Task/GitTask.js +24 -30
  56. package/Task/MariadbTask.d.ts +4 -5
  57. package/Task/MariadbTask.js +26 -32
  58. package/Task/MssqlTask.d.ts +5 -3
  59. package/Task/MssqlTask.js +11 -12
  60. package/Task/MysqlDumpTask.d.ts +10 -3
  61. package/Task/MysqlDumpTask.js +107 -31
  62. package/Task/ScriptTask.d.ts +23 -18
  63. package/Task/ScriptTask.js +34 -24
  64. package/Task/SqlDumpTaskAbstract.d.ts +8 -3
  65. package/Task/SqlDumpTaskAbstract.js +31 -19
  66. package/Task/TaskAbstract.d.ts +24 -25
  67. package/Task/TaskAbstract.js +6 -10
  68. package/cli.js +14 -5
  69. package/config.schema.json +124 -3
  70. package/package.json +4 -5
  71. package/utils/DataFormat.d.ts +23 -12
  72. package/utils/DataFormat.js +36 -14
  73. package/utils/cli.d.ts +2 -9
  74. package/utils/cli.js +9 -52
  75. package/utils/datatruck/client.d.ts +24 -0
  76. package/utils/datatruck/client.js +99 -0
  77. package/utils/datatruck/config.d.ts +8 -6
  78. package/utils/datatruck/config.js +18 -3
  79. package/utils/datatruck/paths.d.ts +5 -9
  80. package/utils/datatruck/paths.js +2 -2
  81. package/utils/datatruck/server.d.ts +21 -0
  82. package/utils/datatruck/server.js +96 -0
  83. package/utils/datatruck/snapshot.d.ts +2 -2
  84. package/utils/date.d.ts +7 -3
  85. package/utils/date.js +22 -14
  86. package/utils/fs.d.ts +27 -15
  87. package/utils/fs.js +110 -62
  88. package/utils/http.d.ts +21 -0
  89. package/utils/http.js +154 -0
  90. package/utils/list.d.ts +64 -0
  91. package/utils/list.js +145 -0
  92. package/utils/mysql.d.ts +2 -0
  93. package/utils/mysql.js +21 -2
  94. package/utils/process.d.ts +1 -0
  95. package/utils/process.js +24 -31
  96. package/utils/progress.d.ts +33 -0
  97. package/utils/progress.js +113 -0
  98. package/utils/steps.d.ts +11 -0
  99. package/utils/steps.js +22 -10
  100. package/utils/stream.d.ts +7 -0
  101. package/utils/stream.js +10 -0
  102. package/utils/string.d.ts +0 -1
  103. package/utils/string.js +1 -13
  104. package/utils/tar.d.ts +10 -3
  105. package/utils/tar.js +70 -44
  106. package/utils/temp.d.ts +26 -0
  107. package/utils/temp.js +133 -0
  108. package/utils/virtual-fs.d.ts +37 -0
  109. package/utils/virtual-fs.js +65 -0
  110. package/Action/BackupSessionsAction.d.ts +0 -13
  111. package/Action/BackupSessionsAction.js +0 -18
  112. package/Action/RestoreSessionsAction.d.ts +0 -13
  113. package/Action/RestoreSessionsAction.js +0 -18
  114. package/Command/BackupSessionsCommand.d.ts +0 -12
  115. package/Command/BackupSessionsCommand.js +0 -92
  116. package/Command/RestoreSessionsCommand.d.ts +0 -12
  117. package/Command/RestoreSessionsCommand.js +0 -91
  118. package/Decorator/EntityDecorator.d.ts +0 -11
  119. package/Decorator/EntityDecorator.js +0 -17
  120. package/Entity/BackupSessionEntity.d.ts +0 -6
  121. package/Entity/BackupSessionEntity.js +0 -25
  122. package/Entity/BackupSessionRepositoryEntity.d.ts +0 -6
  123. package/Entity/BackupSessionRepositoryEntity.js +0 -25
  124. package/Entity/BackupSessionTaskEntity.d.ts +0 -5
  125. package/Entity/BackupSessionTaskEntity.js +0 -24
  126. package/Entity/CrudEntityAbstract.d.ts +0 -5
  127. package/Entity/CrudEntityAbstract.js +0 -9
  128. package/Entity/RestoreSessionEntity.d.ts +0 -5
  129. package/Entity/RestoreSessionEntity.js +0 -24
  130. package/Entity/RestoreSessionRepositoryEntity.d.ts +0 -6
  131. package/Entity/RestoreSessionRepositoryEntity.js +0 -25
  132. package/Entity/RestoreSessionTaskEntity.d.ts +0 -5
  133. package/Entity/RestoreSessionTaskEntity.js +0 -24
  134. package/Entity/StateEntityAbstract.d.ts +0 -9
  135. package/Entity/StateEntityAbstract.js +0 -12
  136. package/Factory/EntityFactory.d.ts +0 -6
  137. package/Factory/EntityFactory.js +0 -40
  138. package/SessionDriver/ConsoleSessionDriver.d.ts +0 -42
  139. package/SessionDriver/ConsoleSessionDriver.js +0 -208
  140. package/SessionDriver/SessionDriverAbstract.d.ts +0 -77
  141. package/SessionDriver/SessionDriverAbstract.js +0 -28
  142. package/SessionDriver/SqliteSessionDriver.d.ts +0 -20
  143. package/SessionDriver/SqliteSessionDriver.js +0 -173
  144. package/SessionManager/BackupSessionManager.d.ts +0 -45
  145. package/SessionManager/BackupSessionManager.js +0 -218
  146. package/SessionManager/RestoreSessionManager.d.ts +0 -47
  147. package/SessionManager/RestoreSessionManager.js +0 -218
  148. package/SessionManager/SessionManagerAbstract.d.ts +0 -18
  149. package/SessionManager/SessionManagerAbstract.js +0 -36
  150. package/migrations/001-initial.sql +0 -98
  151. package/utils/entity.d.ts +0 -4
  152. package/utils/entity.js +0 -10
package/utils/list.js ADDED
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Listr3 = exports.List3Logger = void 0;
4
+ const date_1 = require("./date");
5
+ const stream_1 = require("./stream");
6
+ const listr2_1 = require("listr2");
7
+ class List3Logger extends listr2_1.ListrLogger {
8
+ constructor(options = {}) {
9
+ const streams = (0, stream_1.createStreams)(options.streams);
10
+ super({
11
+ processOutput: new listr2_1.ProcessOutput(streams.stdout, streams.stderr),
12
+ });
13
+ }
14
+ }
15
+ exports.List3Logger = List3Logger;
16
+ class Listr3 extends listr2_1.Listr {
17
+ $options;
18
+ resultMap = {};
19
+ resultList = [];
20
+ execTimer;
21
+ constructor($options) {
22
+ super([], {
23
+ renderer: "default",
24
+ collectErrors: "minimal",
25
+ ...($options.progressManager && {
26
+ fallbackRendererCondition: () => !$options.progressManager.tty,
27
+ }),
28
+ fallbackRenderer: "simple",
29
+ fallbackRendererOptions: {
30
+ logger: new List3Logger(),
31
+ timestamp: listr2_1.PRESET_TIMESTAMP,
32
+ timer: listr2_1.PRESET_TIMER,
33
+ },
34
+ rendererOptions: {
35
+ logger: new List3Logger(),
36
+ collapseSubtasks: false,
37
+ collapseErrors: false,
38
+ timer: listr2_1.PRESET_TIMER,
39
+ },
40
+ });
41
+ this.$options = $options;
42
+ this.execTimer = (0, date_1.createTimer)();
43
+ }
44
+ serializeKeyIndex(keyIndex) {
45
+ return keyIndex
46
+ ? Array.isArray(keyIndex)
47
+ ? keyIndex.map((k) => k.toString())
48
+ : [keyIndex.toString()]
49
+ : [];
50
+ }
51
+ createResultIndex(key, keyIndex) {
52
+ return [key, ...this.serializeKeyIndex(keyIndex)].join(".");
53
+ }
54
+ result(key, keyIndex) {
55
+ const index = this.createResultIndex(key, keyIndex);
56
+ const result = this.resultMap[index];
57
+ if (!result)
58
+ throw new Error(`Task result not found: ${index}`);
59
+ return result;
60
+ }
61
+ $task(item) {
62
+ const index = this.createResultIndex(item.key, item.keyIndex);
63
+ if (this.resultMap[index])
64
+ throw new Error(`Duplicated task index: ${index}`);
65
+ this.resultMap[index] = {
66
+ key: item.key,
67
+ keyIndex: item.keyIndex
68
+ ? this.serializeKeyIndex(item.keyIndex).join(".")
69
+ : undefined,
70
+ elapsed: 0,
71
+ error: undefined,
72
+ data: item.data,
73
+ };
74
+ this.resultList.push(this.resultMap[index]);
75
+ const title = typeof item.title === "string" ? { initial: item.title } : item.title;
76
+ return {
77
+ title: title.initial,
78
+ exitOnError: item.exitOnError,
79
+ enabled: item.enabled,
80
+ skip: item.skip,
81
+ task: async (_, task) => {
82
+ const result = this.result(item.key, item.keyIndex);
83
+ if (title.started)
84
+ task.title = title.started;
85
+ const timer = (0, date_1.createTimer)();
86
+ if (title)
87
+ try {
88
+ const runResult = item.runWrapper
89
+ ? await item.runWrapper(async () => await item.run(task, result.data))
90
+ : await item.run(task, result.data);
91
+ if (title.completed)
92
+ task.title = title.completed;
93
+ return Array.isArray(runResult)
94
+ ? task.newListr(runResult)
95
+ : runResult;
96
+ }
97
+ catch (error) {
98
+ result.error = error;
99
+ if (title.failed)
100
+ task.title = title.failed;
101
+ throw error;
102
+ }
103
+ finally {
104
+ result.elapsed = timer.elapsed();
105
+ }
106
+ },
107
+ };
108
+ }
109
+ $tasks(...items) {
110
+ return items
111
+ .map((item) => (item ? ("key" in item ? this.$task(item) : item) : null))
112
+ .filter(Boolean);
113
+ }
114
+ add(tasks) {
115
+ super.add(tasks);
116
+ return this;
117
+ }
118
+ getSummaryResult() {
119
+ return {
120
+ key: "summary",
121
+ elapsed: this.execTimer.elapsed(),
122
+ data: {
123
+ errors: this.resultList.filter((i) => i.error).length,
124
+ },
125
+ };
126
+ }
127
+ getResult() {
128
+ return [...this.resultList, this.getSummaryResult()];
129
+ }
130
+ async exec() {
131
+ try {
132
+ this.$options.progressManager?.start();
133
+ this.execTimer.reset();
134
+ await super.run();
135
+ return this.getResult();
136
+ }
137
+ catch (error) {
138
+ throw error;
139
+ }
140
+ finally {
141
+ this.$options.progressManager?.dispose();
142
+ }
143
+ }
144
+ }
145
+ exports.Listr3 = Listr3;
package/utils/mysql.d.ts CHANGED
@@ -9,6 +9,7 @@ export type MysqlCliOptions = {
9
9
  verbose?: boolean;
10
10
  database?: string;
11
11
  };
12
+ export declare function assertDumpFile(path: string): Promise<void>;
12
13
  export declare function createMysqlCli(options: MysqlCliOptions): Promise<{
13
14
  options: MysqlCliOptions;
14
15
  initSharedDir: (sharedDir?: string) => Promise<string>;
@@ -28,6 +29,7 @@ export declare function createMysqlCli(options: MysqlCliOptions): Promise<{
28
29
  totalBytes: number;
29
30
  }) => void) | undefined;
30
31
  }) => Promise<[void, import("./process").ExecResultType]>;
32
+ assertDumpFile: typeof assertDumpFile;
31
33
  fetchTableNames: (database: string, include?: string[], exclude?: string[]) => Promise<string[]>;
32
34
  importFile: (input: {
33
35
  path: string;
package/utils/mysql.js CHANGED
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createMysqlCli = void 0;
3
+ exports.createMysqlCli = exports.assertDumpFile = void 0;
4
4
  const AppError_1 = require("../Error/AppError");
5
5
  const cli_1 = require("./cli");
6
6
  const fs_1 = require("./fs");
7
7
  const process_1 = require("./process");
8
8
  const string_1 = require("./string");
9
+ const temp_1 = require("./temp");
9
10
  const crypto_1 = require("crypto");
10
11
  const fs_2 = require("fs");
11
12
  const promises_1 = require("fs/promises");
@@ -22,6 +23,23 @@ function flatQuery(query, params) {
22
23
  })
23
24
  : query;
24
25
  }
26
+ async function assertDumpFile(path) {
27
+ const headerContents = await (0, fs_1.readPartialFile)(path, [0, 100]);
28
+ const footerContents = await (0, fs_1.readPartialFile)(path, [-100]);
29
+ const successHeader = headerContents.split(/\r?\n/).some((line) => {
30
+ const firstLine = line.trim().toLowerCase();
31
+ return (firstLine.startsWith("-- mysql dump") ||
32
+ firstLine.startsWith("-- mariadb dump"));
33
+ });
34
+ if (!successHeader)
35
+ throw new AppError_1.AppError("No start line found");
36
+ const successFooter = footerContents
37
+ .split(/\r?\n/)
38
+ .some((line) => line.trim().toLowerCase().startsWith("-- dump completed"));
39
+ if (!successFooter)
40
+ throw new AppError_1.AppError("No end line found (incomplete backup)");
41
+ }
42
+ exports.assertDumpFile = assertDumpFile;
25
43
  async function createMysqlCli(options) {
26
44
  let sqlConfigPath;
27
45
  const password = (await (0, fs_1.fetchData)(options.password, (p) => p.path)) ?? "";
@@ -35,7 +53,7 @@ async function createMysqlCli(options) {
35
53
  async function createSqlConfig() {
36
54
  if (sqlConfigPath)
37
55
  return sqlConfigPath;
38
- const dir = await (0, fs_1.mkTmpDir)("mysql-cli");
56
+ const dir = await (0, temp_1.mkTmpDir)("mysql", "config");
39
57
  const password = await (0, fs_1.fetchData)(options.password, (p) => p.path);
40
58
  const data = [
41
59
  `[client]`,
@@ -266,6 +284,7 @@ async function createMysqlCli(options) {
266
284
  changeDatabase,
267
285
  fetchAll,
268
286
  dump,
287
+ assertDumpFile,
269
288
  fetchTableNames,
270
289
  importFile,
271
290
  isDatabaseEmpty,
@@ -38,6 +38,7 @@ export interface ExecSettingsInterface {
38
38
  };
39
39
  stderr?: {
40
40
  save?: boolean;
41
+ parseLines?: boolean | "skip-empty";
41
42
  onData?: (data: string) => void;
42
43
  toExitCode?: boolean;
43
44
  };
package/utils/process.js CHANGED
@@ -189,7 +189,7 @@ async function exec(command, argv = [], options = null, settings = {}) {
189
189
  });
190
190
  }
191
191
  if (typeof options?.cwd === "string" && !(await (0, fs_1.existsDir)(options.cwd)))
192
- throw new Error(`Current working directory does not exist: ${options.cwd}`);
192
+ return reject(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);
195
195
  const totalBytes = fileInfo.size;
@@ -216,6 +216,8 @@ async function exec(command, argv = [], options = null, settings = {}) {
216
216
  finishListeners++;
217
217
  if (settings.stdout?.parseLines)
218
218
  finishListeners++;
219
+ if (settings.stderr?.parseLines)
220
+ finishListeners++;
219
221
  let streamError;
220
222
  const tryFinish = () => {
221
223
  if (!--finishListeners)
@@ -282,10 +284,18 @@ async function exec(command, argv = [], options = null, settings = {}) {
282
284
  pipe.stream.pipe(p.stdin);
283
285
  }
284
286
  }
285
- if (log.stdout || settings.stdout) {
286
- if (!p.stdout)
287
- throw new Error(`stdout is not defined`);
288
- const parseLines = settings.stdout?.parseLines;
287
+ const stdConfig = {
288
+ stdout: { log: log.stdout, settings: settings.stdout },
289
+ stderr: { log: log.stderr, settings: settings.stderr },
290
+ };
291
+ for (const inType in stdConfig) {
292
+ const type = inType;
293
+ const enabled = log[type] || settings[type];
294
+ if (!enabled)
295
+ continue;
296
+ if (!p[type])
297
+ throw new Error(`${type} is not defined`);
298
+ const parseLines = settings[type]?.parseLines;
289
299
  const skipEmptyLines = parseLines === "skip-empty";
290
300
  const onData = (inData) => {
291
301
  let data = inData.toString();
@@ -294,46 +304,29 @@ async function exec(command, argv = [], options = null, settings = {}) {
294
304
  return;
295
305
  data = `${inData}\n`;
296
306
  }
297
- if (log.stdout)
307
+ if (log[type])
298
308
  logExecStdout({
299
309
  data,
300
310
  stderr: log.allToStderr,
301
311
  colorize: log.colorize,
302
312
  });
303
- if (settings.stdout?.save)
304
- spawnData.stdout += data;
305
- if (settings.stdout?.onData)
306
- settings.stdout.onData(inData.toString());
313
+ if (settings[type]?.save ||
314
+ (type === "stderr" && settings[type]?.toExitCode))
315
+ spawnData[type] += data;
316
+ if (settings[type]?.onData)
317
+ settings[type].onData(inData.toString());
307
318
  };
308
319
  if (parseLines) {
309
320
  const rl = (0, readline_1.createInterface)({
310
- input: p.stdout,
321
+ input: p[type],
311
322
  });
312
323
  rl.on("line", onData);
313
324
  rl.on("close", tryFinish);
314
325
  }
315
- else if (log.stdout ||
316
- settings.stdout?.save ||
317
- settings.stdout?.onData) {
318
- p.stdout.on("data", onData);
326
+ else if (log[type] || settings[type]?.save || settings[type]?.onData) {
327
+ p[type].on("data", onData);
319
328
  }
320
329
  }
321
- if (log.stderr || settings.stderr) {
322
- if (!p.stderr)
323
- throw new Error(`stderr is not defined`);
324
- p.stderr.on("data", (data) => {
325
- if (log.stderr)
326
- logExecStdout({
327
- data: data.toString(),
328
- stderr: log.allToStderr,
329
- colorize: log.colorize,
330
- });
331
- if (settings.stderr?.save || settings.stderr?.toExitCode)
332
- spawnData.stderr += data.toString();
333
- if (settings.stderr?.onData)
334
- settings.stderr.onData(data.toString());
335
- });
336
- }
337
330
  p.on("error", (error) => (spawnError = error)).on("close", (exitCode) => {
338
331
  spawnData.exitCode = exitCode ?? 0;
339
332
  if (pipe?.stream instanceof fs_2.WriteStream)
@@ -1,3 +1,5 @@
1
+ /// <reference types="node" />
2
+ import { Timer } from "./date";
1
3
  export type ProgressStats = {
2
4
  percent?: number;
3
5
  total?: number;
@@ -10,3 +12,34 @@ export type Progress = {
10
12
  absolute?: ProgressStats;
11
13
  relative?: ProgressStats;
12
14
  };
15
+ export declare class ProgressManager {
16
+ readonly options: {
17
+ verbose?: boolean;
18
+ /**
19
+ * @default true
20
+ */
21
+ tty?: boolean | "auto";
22
+ enabled?: boolean | "auto" | "interval";
23
+ interval?: number;
24
+ };
25
+ protected timer: Timer;
26
+ protected interval: Timer | undefined;
27
+ protected keydownListener: ((data: Buffer) => void) | undefined;
28
+ readonly tty: boolean;
29
+ readonly enabled: boolean | "interval";
30
+ constructor(options: {
31
+ verbose?: boolean;
32
+ /**
33
+ * @default true
34
+ */
35
+ tty?: boolean | "auto";
36
+ enabled?: boolean | "auto" | "interval";
37
+ interval?: number;
38
+ });
39
+ elapsed(): number;
40
+ start(): void;
41
+ dispose(): void;
42
+ update(progress: Progress, cb: (text: string) => void): void;
43
+ }
44
+ export declare function renderProgress(progress: Progress, bar?: boolean): string[];
45
+ export declare function renderProgressStats(stats: ProgressStats, progressBar?: boolean): string;
package/utils/progress.js CHANGED
@@ -1,2 +1,115 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.renderProgressStats = exports.renderProgress = exports.ProgressManager = void 0;
7
+ const cli_1 = require("./cli");
8
+ const date_1 = require("./date");
9
+ const bytes_1 = __importDefault(require("bytes"));
10
+ const chalk_1 = require("chalk");
11
+ const readline_1 = require("readline");
12
+ class ProgressManager {
13
+ options;
14
+ timer = (0, date_1.createTimer)();
15
+ interval = (0, date_1.createTimer)();
16
+ keydownListener;
17
+ tty;
18
+ enabled;
19
+ constructor(options) {
20
+ this.options = options;
21
+ this.tty =
22
+ options.tty === "auto"
23
+ ? options.verbose
24
+ ? false
25
+ : process.stdout.isTTY
26
+ : !!options.tty;
27
+ this.enabled =
28
+ options.enabled === "auto"
29
+ ? this.tty
30
+ ? true
31
+ : "interval"
32
+ : !!options.enabled;
33
+ }
34
+ elapsed() {
35
+ return this.timer.elapsed();
36
+ }
37
+ start() {
38
+ this.timer.reset();
39
+ (0, readline_1.emitKeypressEvents)(process.stdin);
40
+ process.stdin?.setRawMode?.(true);
41
+ process.stdin?.resume();
42
+ process.stdin?.setEncoding("utf8");
43
+ process.stdin?.on("keypress", (this.keydownListener = (inKey) => {
44
+ const key = inKey.toString();
45
+ if (key === "\u0003") {
46
+ process.stdin.setRawMode?.(false);
47
+ process.emit("SIGINT");
48
+ }
49
+ else if (/^(\r\n)|\r|\n$/.test(key)) {
50
+ this.interval = undefined;
51
+ }
52
+ }));
53
+ }
54
+ dispose() {
55
+ this.timer.stop();
56
+ if (this.keydownListener) {
57
+ process.stdin?.off("keypress", this.keydownListener);
58
+ this.keydownListener = undefined;
59
+ }
60
+ }
61
+ update(progress, cb) {
62
+ if (!this.enabled)
63
+ return;
64
+ if (this.enabled === "interval") {
65
+ if (this.interval) {
66
+ if (!this.interval.reset(this.options.interval ?? 5000))
67
+ return;
68
+ }
69
+ else {
70
+ this.interval = (0, date_1.createTimer)();
71
+ }
72
+ }
73
+ cb(renderProgress(progress, this.tty).join("\n"));
74
+ }
75
+ }
76
+ exports.ProgressManager = ProgressManager;
77
+ function renderProgress(progress, bar) {
78
+ return [
79
+ progress.absolute && renderProgressStats(progress.absolute, bar),
80
+ progress.relative && renderProgressStats(progress.relative, bar),
81
+ ].filter((v) => !!v);
82
+ }
83
+ exports.renderProgress = renderProgress;
84
+ function renderProgressStats(stats, progressBar) {
85
+ const text = [];
86
+ if (typeof stats.percent === "number") {
87
+ if (progressBar)
88
+ text.push((0, cli_1.renderProgressBar)(stats.percent));
89
+ text.push(`${stats.percent.toFixed(2)}%`);
90
+ }
91
+ if (typeof stats.current === "number" || typeof stats.total === "number") {
92
+ const format = (value) => stats.format === "size" ? (0, bytes_1.default)(value) : value;
93
+ if (typeof stats.current === "number" && typeof stats.total === "number") {
94
+ text.push(`${format(stats.current)}/${format(stats.total)}`);
95
+ }
96
+ else if (typeof stats.current === "number") {
97
+ text.push(`${format(stats.current)}`);
98
+ }
99
+ else if (typeof stats.total === "number") {
100
+ text.push(`?/${format(stats.total)}`);
101
+ }
102
+ }
103
+ if (stats.description && stats.payload) {
104
+ text.push(`${stats.description}: ${stats.payload}`);
105
+ }
106
+ else if (stats.description) {
107
+ text.push(stats.description);
108
+ }
109
+ else if (stats.payload) {
110
+ text.push(stats.payload);
111
+ }
112
+ const sep = (0, chalk_1.grey)(`|`);
113
+ return text.join(` ${sep} `);
114
+ }
115
+ exports.renderProgressStats = renderProgressStats;
package/utils/steps.d.ts CHANGED
@@ -9,12 +9,20 @@ export type NodeStepConfig = {
9
9
  vars?: Record<string, any>;
10
10
  code: string | string[];
11
11
  };
12
+ export type TelegramMessageStepConfig = {
13
+ bot: string;
14
+ chatId: number;
15
+ text?: string;
16
+ };
12
17
  export type Step = {
13
18
  type: "process";
14
19
  config: ProcessStepConfig;
15
20
  } | {
16
21
  type: "node";
17
22
  config: NodeStepConfig;
23
+ } | {
24
+ type: "telegram-message";
25
+ config: TelegramMessageStepConfig;
18
26
  };
19
27
  export type StepOptions = {
20
28
  env?: Record<string, string | undefined>;
@@ -25,6 +33,9 @@ export type StepOptions = {
25
33
  vars?: Record<string, any>;
26
34
  tempDir?: () => Promise<string>;
27
35
  };
36
+ telegram?: {
37
+ vars?: Record<string, string>;
38
+ };
28
39
  cwd?: string;
29
40
  onLine?: (p: string) => any;
30
41
  verbose?: boolean;
package/utils/steps.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runSteps = void 0;
4
- const fs_1 = require("./fs");
4
+ const http_1 = require("./http");
5
5
  const process_1 = require("./process");
6
6
  const string_1 = require("./string");
7
+ const temp_1 = require("./temp");
7
8
  const promises_1 = require("fs/promises");
8
9
  const path_1 = require("path");
9
10
  async function runSteps(input, options) {
@@ -33,19 +34,19 @@ async function runSteps(input, options) {
33
34
  tempDir = await options.node.tempDir();
34
35
  }
35
36
  else {
36
- tempDir = await (0, fs_1.mkTmpDir)("node-step");
37
+ tempDir = await (0, temp_1.mkTmpDir)("node-step");
37
38
  }
38
39
  const scriptPath = (0, path_1.join)(tempDir, "script.js");
39
- const vars = Object.entries({
40
+ const vars = {
40
41
  ...step.config.vars,
41
42
  ...options.node?.vars,
42
- }).reduce((items, [name, value]) => {
43
- items.push(`let ${name} = ${JSON.stringify(value)}`);
44
- return items;
45
- }, []);
46
- await (0, promises_1.writeFile)(scriptPath, Array.isArray(step.config.code)
47
- ? [...vars, ...step.config.code].join(";\n")
48
- : `${vars.join(";\n")}\n${step.config.code}`);
43
+ };
44
+ const varKeys = Object.keys(vars);
45
+ const varJson = JSON.stringify(vars);
46
+ const code = Array.isArray(step.config.code)
47
+ ? [...step.config.code].join(";\n")
48
+ : step.config.code;
49
+ await (0, promises_1.writeFile)(scriptPath, `(async function({ ${varKeys} }) {\n${code};\n})(${varJson});`);
49
50
  await (0, process_1.exec)("node", [scriptPath], {
50
51
  cwd: options.cwd,
51
52
  env: {
@@ -63,6 +64,17 @@ async function runSteps(input, options) {
63
64
  }),
64
65
  });
65
66
  }
67
+ else if (step.type === "telegram-message") {
68
+ await (0, http_1.post)(`https://api.telegram.org/bot${step.config.bot}/sendMessage`, JSON.stringify({
69
+ chat_id: step.config.chatId.toString(),
70
+ text: (0, string_1.render)(step.config.text ?? `{TEXT}`, options.telegram?.vars || {}),
71
+ disable_notification: true,
72
+ }), {
73
+ headers: {
74
+ "Content-Type": "application/json",
75
+ },
76
+ });
77
+ }
66
78
  else {
67
79
  throw new Error(`Invalid step type: ${step.type}`);
68
80
  }
@@ -0,0 +1,7 @@
1
+ /// <reference types="node" />
2
+ import { Writable } from "stream";
3
+ export type Streams = {
4
+ stdout: Writable;
5
+ stderr: Writable;
6
+ };
7
+ export declare function createStreams(options?: Partial<Streams>): Streams;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createStreams = void 0;
4
+ function createStreams(options = {}) {
5
+ return {
6
+ stdout: options.stdout ?? process.stdout,
7
+ stderr: options.stderr ?? process.stderr,
8
+ };
9
+ }
10
+ exports.createStreams = createStreams;
package/utils/string.d.ts CHANGED
@@ -19,6 +19,5 @@ export declare function endsWith(input: string, patterns: string[]): boolean;
19
19
  export declare function createMatchFilter(include?: string[], exclude?: string[]): (input: string) => boolean;
20
20
  export declare function checkMatch(subject: string | undefined, patterns: string[]): boolean;
21
21
  export declare function formatDateTime(datetime: string): string;
22
- export declare function splitLines(input: string, satinize?: boolean): string[];
23
22
  export declare function undefIfEmpty(input: string): string | undefined;
24
23
  export {};
package/utils/string.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.undefIfEmpty = exports.splitLines = exports.formatDateTime = exports.checkMatch = exports.createMatchFilter = exports.endsWith = exports.match = exports.makePathPatterns = exports.formatSeconds = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = exports.serialize = void 0;
3
+ exports.undefIfEmpty = exports.formatDateTime = exports.checkMatch = exports.createMatchFilter = exports.endsWith = exports.match = 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) {
@@ -121,18 +121,6 @@ function formatDateTime(datetime) {
121
121
  return result;
122
122
  }
123
123
  exports.formatDateTime = formatDateTime;
124
- function splitLines(input, satinize = true) {
125
- const lines = input.split(/\r?\n/);
126
- return satinize
127
- ? input.split(/\r?\n/).reduce((result, value) => {
128
- value = value.trim();
129
- if (value.length)
130
- result.push(value);
131
- return result;
132
- }, [])
133
- : lines;
134
- }
135
- exports.splitLines = splitLines;
136
124
  function undefIfEmpty(input) {
137
125
  return input.length ? input : undefined;
138
126
  }
package/utils/tar.d.ts CHANGED
@@ -24,14 +24,17 @@ export type DecompressOptions = {
24
24
  */
25
25
  cores?: CoresOptions;
26
26
  };
27
- export interface CreateTarOptions {
27
+ export type CreateTarOptions = {
28
28
  path: string;
29
29
  verbose?: boolean;
30
30
  output: string;
31
- includeList: string;
32
31
  compress?: boolean | CompressOptions;
33
32
  onEntry?: (entry: TarEntry) => void;
34
- }
33
+ } & ({
34
+ includeList: string;
35
+ } | {
36
+ include: string[];
37
+ });
35
38
  export interface ExtractOptions {
36
39
  input: string;
37
40
  output: string;
@@ -51,4 +54,8 @@ export type ListTarOptions = {
51
54
  export declare function listTar(options: ListTarOptions): Promise<number>;
52
55
  export declare function checkPigzLib(cache?: boolean): Promise<boolean>;
53
56
  export declare function createTar(options: CreateTarOptions): Promise<void>;
57
+ /**
58
+ * bsdtar (only windows?) fails if path ends with slash
59
+ */
60
+ export declare function normalizeTarPath(path: string): string;
54
61
  export declare function extractTar(options: ExtractOptions): Promise<void>;