@datatruck/cli 0.13.0 → 0.15.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 (36) hide show
  1. package/Action/BackupAction.js +3 -15
  2. package/Action/RestoreAction.js +2 -10
  3. package/Command/BackupCommand.js +2 -1
  4. package/Command/BackupSessionsCommand.js +1 -0
  5. package/Command/RestoreCommand.js +1 -1
  6. package/Command/RestoreSessionsCommand.js +1 -0
  7. package/Entity/StateEntityAbstract.d.ts +2 -1
  8. package/Repository/DatatruckRepository.d.ts +2 -0
  9. package/Repository/DatatruckRepository.js +239 -108
  10. package/Repository/RepositoryAbstract.d.ts +10 -5
  11. package/Repository/ResticRepository.js +34 -17
  12. package/SessionDriver/ConsoleSessionDriver.d.ts +2 -3
  13. package/SessionDriver/ConsoleSessionDriver.js +11 -10
  14. package/SessionManager/BackupSessionManager.d.ts +10 -11
  15. package/SessionManager/BackupSessionManager.js +24 -5
  16. package/SessionManager/RestoreSessionManager.d.ts +12 -11
  17. package/SessionManager/RestoreSessionManager.js +24 -5
  18. package/SessionManager/SessionManagerAbstract.d.ts +14 -0
  19. package/SessionManager/SessionManagerAbstract.js +21 -0
  20. package/Task/GitTask.js +23 -14
  21. package/Task/MariadbTask.js +9 -4
  22. package/Task/SqlDumpTaskAbstract.js +31 -10
  23. package/Task/TaskAbstract.d.ts +10 -5
  24. package/cli.js +1 -1
  25. package/config.schema.json +4 -0
  26. package/migrations/001-initial.sql +12 -6
  27. package/package.json +1 -1
  28. package/util/fs-util.d.ts +27 -21
  29. package/util/fs-util.js +89 -101
  30. package/util/math-util.js +2 -0
  31. package/util/process-util.d.ts +1 -0
  32. package/util/process-util.js +20 -4
  33. package/util/string-util.d.ts +1 -0
  34. package/util/string-util.js +8 -1
  35. package/util/zip-util.d.ts +64 -19
  36. package/util/zip-util.js +156 -59
package/util/zip-util.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.unzip = exports.zip = exports.buildArguments = void 0;
3
+ exports.unzip = exports.zip = exports.listZip = exports.checkSSEOption = exports.buildArguments = void 0;
4
4
  const process_util_1 = require("./process-util");
5
5
  const path_1 = require("path");
6
6
  function buildArguments(filters) {
@@ -30,45 +30,101 @@ function buildArguments(filters) {
30
30
  return args;
31
31
  }
32
32
  exports.buildArguments = buildArguments;
33
- function parseZipStream(chunk, buffer, cb) {
34
- const lines = chunk.replaceAll("\b", "").trim().split(/\r?\n/);
35
- for (const line of lines) {
36
- let matches = null;
37
- if ((matches = /^(\d+)% (\d+ )?\+/.exec(line))) {
38
- const path = line.slice(line.indexOf("+") + 1).trim();
39
- const progress = Number(matches[1]);
40
- if (!buffer.currentPaths)
41
- buffer.currentPaths = 0;
42
- if (path !== buffer.lastPath)
43
- buffer.currentPaths++;
44
- buffer.lastPath = path;
45
- cb({
46
- type: "progress",
47
- data: { progress, path, files: buffer.currentPaths },
48
- });
33
+ let checkSSEOptionResult;
34
+ async function checkSSEOption(command = "7z") {
35
+ const result = await (0, process_util_1.exec)(command);
36
+ if (typeof checkSSEOptionResult === "boolean")
37
+ return checkSSEOptionResult;
38
+ return (checkSSEOptionResult = result.stdout.includes(" -sse"));
39
+ }
40
+ exports.checkSSEOption = checkSSEOption;
41
+ const listZipLineEqChar = " = ";
42
+ function parseListZipLine(line, buffer) {
43
+ if (buffer.started) {
44
+ if (line === "") {
45
+ if (buffer.opened) {
46
+ const { stream } = buffer;
47
+ buffer.stream = {};
48
+ buffer.opened = false;
49
+ return stream;
50
+ }
49
51
  }
50
- else if (line.startsWith("Add new data to archive:")) {
51
- const [, folders] = /(\d+) folders?/i.exec(line) || [, 0];
52
- const [, files] = /(\d+) files?/i.exec(line) || [, 0];
53
- cb({
54
- type: "summary",
55
- data: {
56
- folders: Number(folders),
57
- files: Number(files),
58
- },
59
- });
52
+ else {
53
+ const separator = line.indexOf(listZipLineEqChar);
54
+ const key = line.slice(0, separator);
55
+ const value = line.slice(separator + listZipLineEqChar.length);
56
+ buffer.opened = true;
57
+ buffer.stream[key] = value;
60
58
  }
61
59
  }
60
+ else if (line.startsWith("----------")) {
61
+ buffer.started = true;
62
+ buffer.stream = {};
63
+ }
64
+ }
65
+ async function listZip(data) {
66
+ const buffer = {};
67
+ await (0, process_util_1.exec)(data.command ?? "7z", ["l", data.path, "-slt"], {}, {
68
+ log: {
69
+ exec: data.verbose ?? false,
70
+ stderr: data.verbose ?? false,
71
+ stdout: false,
72
+ },
73
+ onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
74
+ stdout: {
75
+ parseLines: true,
76
+ onData: async (line) => {
77
+ const stream = parseListZipLine(line, buffer);
78
+ if (stream) {
79
+ await data.onStream?.(stream);
80
+ }
81
+ },
82
+ },
83
+ });
84
+ }
85
+ exports.listZip = listZip;
86
+ function parseZipLine(line) {
87
+ let matches = null;
88
+ line = line.trim();
89
+ if (!line.length)
90
+ return;
91
+ if ((matches = /^(\d+)% (\d+ )?\+/.exec(line))) {
92
+ const path = line.slice(line.indexOf("+") + 1).trim();
93
+ const progress = Number(matches[1]);
94
+ const files = matches[2] ? Number(matches[2]) : 1;
95
+ return {
96
+ type: "progress",
97
+ data: { progress, path, files },
98
+ };
99
+ }
100
+ else if (line.startsWith("Add new data to archive:")) {
101
+ const [, folders] = /(\d+) folders?/i.exec(line) || [, 0];
102
+ const [, files] = /(\d+) files?/i.exec(line) || [, 0];
103
+ return {
104
+ type: "summary",
105
+ data: {
106
+ folders: Number(folders),
107
+ files: Number(files),
108
+ },
109
+ };
110
+ }
62
111
  }
63
112
  async function zip(data) {
64
- let result = {
113
+ let summary = {
65
114
  folders: 0,
66
115
  files: 0,
67
116
  };
68
- let buffer = {};
117
+ await data.onProgress?.({
118
+ current: 0,
119
+ percent: 0,
120
+ total: 0,
121
+ type: "start",
122
+ });
69
123
  await (0, process_util_1.exec)(data.command ?? "7z", [
70
124
  "a",
71
- "-mmt1",
125
+ // https://sourceforge.net/p/sevenzip/bugs/2099/,
126
+ // https://github.com/mcmilk/7-Zip/commit/87ba6f01ba3c5b2ce3186bddfe3d7d880639193c#diff-779d6b1bfa6196b288478f78ca96c4d4c6d7ac6cf8be15a28a20dabc9137ca36L515
127
+ ...((await checkSSEOption(data.command)) ? [] : ["-mmt1"]),
72
128
  "-bsp1",
73
129
  ...(data.deleteOnZip ? ["-sdel"] : []),
74
130
  (0, path_1.normalize)(data.output),
@@ -79,41 +135,61 @@ async function zip(data) {
79
135
  cwd: data.path,
80
136
  }, {
81
137
  log: data.verbose ?? false,
82
- stderr: {
83
- toExitCode: true,
84
- },
138
+ onExitCodeError: (data, error) => (data.exitCode > 2 ? error : false),
85
139
  stdout: {
86
- onData: (chunk) => {
87
- parseZipStream(chunk, buffer, (stream) => {
88
- data.onStream?.(stream);
89
- if (stream.type === "summary")
90
- result = stream.data;
91
- });
140
+ onData: async (lines) => {
141
+ for (const line of lines.split(/\r?\n/)) {
142
+ const stream = parseZipLine(line);
143
+ if (stream) {
144
+ if (stream.type === "summary")
145
+ summary = stream.data;
146
+ if (stream.type === "progress") {
147
+ const current = Math.max(0, stream.data.files - 1);
148
+ await data.onProgress?.({
149
+ total: summary.files,
150
+ current,
151
+ path: stream.data.path,
152
+ percent: stream.data.progress,
153
+ });
154
+ }
155
+ await data.onStream?.(stream);
156
+ }
157
+ }
92
158
  },
93
159
  },
94
160
  });
95
- return result;
161
+ await data.onProgress?.({
162
+ total: summary.files,
163
+ current: summary.files,
164
+ percent: 100,
165
+ type: "end",
166
+ });
167
+ return summary;
96
168
  }
97
169
  exports.zip = zip;
98
- function parseUnzipStream(chunk, cb) {
99
- const lines = chunk.trim().split(/\r?\n/g);
100
- for (const line of lines) {
101
- let matches = null;
102
- if ((matches = /^(\d+)% (\d+) \-/.exec(line))) {
103
- const progress = Number(matches[1]);
104
- const files = Number(matches[2]);
105
- const path = line.slice(line.indexOf("-") + 1).trim();
106
- cb({
107
- type: "progress",
108
- data: { progress, path, files },
109
- });
110
- }
170
+ function parseUnzipLine(line) {
171
+ let matches = null;
172
+ if ((matches = /^\s*(\d+)% (\d+) \-/.exec(line))) {
173
+ const progress = Number(matches[1]);
174
+ const files = Number(matches[2]);
175
+ const path = line.slice(line.indexOf("-") + 1).trim();
176
+ return {
177
+ type: "progress",
178
+ data: { percent: progress, path, files },
179
+ };
111
180
  }
112
181
  }
113
182
  async function unzip(data) {
114
- return await (0, process_util_1.exec)(data.command ?? "7z", [
183
+ let summary = {
184
+ files: 0,
185
+ };
186
+ await data.onProgress?.({
187
+ current: summary.files,
188
+ percent: 0,
189
+ type: "start",
190
+ });
191
+ const result = await (0, process_util_1.exec)(data.command ?? "7z", [
115
192
  "x",
116
- "-mmt1",
117
193
  "-bsp1",
118
194
  (0, path_1.normalize)(data.input),
119
195
  ...buildArguments(data.files ?? []),
@@ -123,13 +199,34 @@ async function unzip(data) {
123
199
  log: data.verbose ?? false,
124
200
  stderr: { toExitCode: true },
125
201
  stdout: {
126
- ...(data.onStream && {
127
- onData: (chunk) => {
128
- if (data.onStream)
129
- parseUnzipStream(chunk, data.onStream);
202
+ ...((data.onStream || data.onProgress) && {
203
+ parseLines: true,
204
+ onData: async (line) => {
205
+ const stream = parseUnzipLine(line);
206
+ if (stream) {
207
+ if (stream.type === "progress") {
208
+ const current = Math.max(0, stream.data.files - 1);
209
+ summary.files = stream.data.files;
210
+ await data.onProgress?.({
211
+ current,
212
+ percent: stream.data.percent,
213
+ path: stream.data.path,
214
+ });
215
+ }
216
+ await data.onStream?.(stream);
217
+ }
130
218
  },
131
219
  }),
132
220
  },
133
221
  });
222
+ await data.onProgress?.({
223
+ current: summary.files,
224
+ percent: 100,
225
+ type: "end",
226
+ });
227
+ return {
228
+ ...result,
229
+ ...summary,
230
+ };
134
231
  }
135
232
  exports.unzip = unzip;