@datatruck/cli 0.29.1 → 0.30.1
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.d.ts +2 -4
- package/Action/BackupAction.js +3 -11
- package/Action/CopyAction.d.ts +2 -2
- package/Action/CopyAction.js +1 -2
- package/Action/RestoreAction.d.ts +2 -3
- package/Action/RestoreAction.js +1 -2
- package/CHANGELOG.md +22 -0
- package/Command/BackupCommand.js +0 -1
- package/Command/CleanCacheCommand.js +2 -5
- package/Command/CommandAbstract.d.ts +2 -2
- package/Command/CopyCommand.js +0 -1
- package/Command/RestoreCommand.js +0 -1
- package/Command/SnapshotsCommand.js +2 -5
- package/Config/Config.js +22 -0
- package/Repository/DatatruckRepository.js +43 -15
- package/cli.js +6 -8
- package/config.schema.json +34 -0
- package/package.json +1 -2
- package/utils/bytes.d.ts +2 -0
- package/utils/bytes.js +29 -0
- package/utils/datatruck/client.d.ts +6 -1
- package/utils/datatruck/client.js +6 -5
- package/utils/datatruck/server.d.ts +10 -0
- package/utils/datatruck/server.js +30 -11
- package/utils/exit.d.ts +6 -0
- package/utils/exit.js +56 -0
- package/utils/fs.d.ts +3 -0
- package/utils/fs.js +24 -6
- package/utils/http.d.ts +2 -0
- package/utils/http.js +21 -2
- package/utils/list.d.ts +2 -0
- package/utils/list.js +18 -3
- package/utils/process.d.ts +1 -3
- package/utils/process.js +39 -54
- package/utils/progress.d.ts +23 -11
- package/utils/progress.js +25 -17
- package/utils/tar.d.ts +2 -6
- package/utils/virtual-fs.d.ts +7 -1
- package/utils/virtual-fs.js +3 -0
package/Action/BackupAction.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { RepositoryConfigType } from "../Config/RepositoryConfig";
|
|
|
4
4
|
import { PreSnapshot } from "../Repository/RepositoryAbstract";
|
|
5
5
|
import { DataFormat } from "../utils/DataFormat";
|
|
6
6
|
import { Listr3TaskResultEnd } from "../utils/list";
|
|
7
|
-
import { Progress,
|
|
7
|
+
import { Progress, ProgressMode } from "../utils/progress";
|
|
8
8
|
import { Streams } from "../utils/stream";
|
|
9
9
|
import { IfRequireKeys } from "../utils/ts";
|
|
10
10
|
export type BackupActionOptions = {
|
|
@@ -17,8 +17,7 @@ export type BackupActionOptions = {
|
|
|
17
17
|
verbose?: boolean;
|
|
18
18
|
date?: string;
|
|
19
19
|
tty?: "auto" | boolean;
|
|
20
|
-
progress?:
|
|
21
|
-
progressInterval?: number;
|
|
20
|
+
progress?: ProgressMode;
|
|
22
21
|
streams?: Streams;
|
|
23
22
|
prune?: boolean;
|
|
24
23
|
};
|
|
@@ -51,7 +50,6 @@ type Context = {
|
|
|
51
50
|
export declare class BackupAction<TRequired extends boolean = true> {
|
|
52
51
|
readonly config: ConfigType;
|
|
53
52
|
readonly options: IfRequireKeys<TRequired, BackupActionOptions>;
|
|
54
|
-
protected pm: ProgressManager;
|
|
55
53
|
constructor(config: ConfigType, options?: IfRequireKeys<TRequired, BackupActionOptions>);
|
|
56
54
|
protected prepareSnapshot(): PreSnapshot;
|
|
57
55
|
protected getPackages(snapshot: PreSnapshot): PackageConfigType[];
|
package/Action/BackupAction.js
CHANGED
|
@@ -22,16 +22,9 @@ const dayjs_1 = __importDefault(require("dayjs"));
|
|
|
22
22
|
class BackupAction {
|
|
23
23
|
config;
|
|
24
24
|
options;
|
|
25
|
-
pm;
|
|
26
25
|
constructor(config, options = {}) {
|
|
27
26
|
this.config = config;
|
|
28
27
|
this.options = options;
|
|
29
|
-
this.pm = new progress_1.ProgressManager({
|
|
30
|
-
verbose: options.verbose,
|
|
31
|
-
tty: options.tty,
|
|
32
|
-
enabled: options.progress,
|
|
33
|
-
interval: options.progressInterval,
|
|
34
|
-
});
|
|
35
28
|
}
|
|
36
29
|
prepareSnapshot() {
|
|
37
30
|
const date = this.options.date ?? new Date().toISOString();
|
|
@@ -153,7 +146,7 @@ class BackupAction {
|
|
|
153
146
|
.map((item) => [
|
|
154
147
|
(0, cli_1.renderResult)(item.error),
|
|
155
148
|
renderTitle(item, true),
|
|
156
|
-
renderData(item, true),
|
|
149
|
+
renderData(item, true, result),
|
|
157
150
|
(0, date_1.duration)(item.elapsed),
|
|
158
151
|
(0, cli_1.renderError)(item.error, options.verbose),
|
|
159
152
|
]),
|
|
@@ -165,8 +158,7 @@ class BackupAction {
|
|
|
165
158
|
const pm = new progress_1.ProgressManager({
|
|
166
159
|
verbose: options.verbose,
|
|
167
160
|
tty: options.tty,
|
|
168
|
-
|
|
169
|
-
interval: options.progressInterval,
|
|
161
|
+
mode: options.progress,
|
|
170
162
|
});
|
|
171
163
|
const l = new list_1.Listr3({
|
|
172
164
|
streams: this.options.streams,
|
|
@@ -246,7 +238,7 @@ class BackupAction {
|
|
|
246
238
|
repositoryName,
|
|
247
239
|
snapshot,
|
|
248
240
|
snapshotPath: taskResult?.snapshotPath,
|
|
249
|
-
onProgress: (p) =>
|
|
241
|
+
onProgress: (p) => pm.update(p, (t) => (task.output = t)),
|
|
250
242
|
});
|
|
251
243
|
},
|
|
252
244
|
})), l.$task({
|
package/Action/CopyAction.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ConfigType } from "../Config/Config";
|
|
|
2
2
|
import { Snapshot } from "../Repository/RepositoryAbstract";
|
|
3
3
|
import { DataFormat } from "../utils/DataFormat";
|
|
4
4
|
import { Listr3TaskResultEnd } from "../utils/list";
|
|
5
|
+
import { ProgressMode } from "../utils/progress";
|
|
5
6
|
import { Streams } from "../utils/stream";
|
|
6
7
|
import { IfRequireKeys } from "../utils/ts";
|
|
7
8
|
export type CopyActionOptionsType = {
|
|
@@ -13,8 +14,7 @@ export type CopyActionOptionsType = {
|
|
|
13
14
|
repositoryNames2?: string[];
|
|
14
15
|
verbose?: boolean;
|
|
15
16
|
tty?: "auto" | boolean;
|
|
16
|
-
progress?:
|
|
17
|
-
progressInterval?: number;
|
|
17
|
+
progress?: ProgressMode;
|
|
18
18
|
};
|
|
19
19
|
export type CopyActionResult = {
|
|
20
20
|
errors: Error[];
|
package/Action/CopyAction.js
CHANGED
|
@@ -69,8 +69,7 @@ class CopyAction {
|
|
|
69
69
|
const pm = new progress_1.ProgressManager({
|
|
70
70
|
verbose: options.verbose,
|
|
71
71
|
tty: options.tty,
|
|
72
|
-
|
|
73
|
-
interval: options.progressInterval,
|
|
72
|
+
mode: options.progress,
|
|
74
73
|
});
|
|
75
74
|
const l = new list_1.Listr3({ progressManager: pm });
|
|
76
75
|
return l
|
|
@@ -4,7 +4,7 @@ import { Snapshot } from "../Repository/RepositoryAbstract";
|
|
|
4
4
|
import { TaskAbstract } from "../Task/TaskAbstract";
|
|
5
5
|
import { DataFormat } from "../utils/DataFormat";
|
|
6
6
|
import { Listr3TaskResultEnd } from "../utils/list";
|
|
7
|
-
import { Progress } from "../utils/progress";
|
|
7
|
+
import { Progress, ProgressMode } from "../utils/progress";
|
|
8
8
|
import { Streams } from "../utils/stream";
|
|
9
9
|
import { GargabeCollector } from "../utils/temp";
|
|
10
10
|
import { IfRequireKeys } from "../utils/ts";
|
|
@@ -19,8 +19,7 @@ export type RestoreActionOptions = {
|
|
|
19
19
|
verbose?: boolean;
|
|
20
20
|
initial?: boolean;
|
|
21
21
|
tty?: "auto" | boolean;
|
|
22
|
-
progress?:
|
|
23
|
-
progressInterval?: number;
|
|
22
|
+
progress?: ProgressMode;
|
|
24
23
|
streams?: Streams;
|
|
25
24
|
};
|
|
26
25
|
type RestoreSnapshot = Snapshot & {
|
package/Action/RestoreAction.js
CHANGED
|
@@ -143,8 +143,7 @@ class RestoreAction {
|
|
|
143
143
|
const pm = new progress_1.ProgressManager({
|
|
144
144
|
verbose: options.verbose,
|
|
145
145
|
tty: options.tty,
|
|
146
|
-
|
|
147
|
-
interval: options.progressInterval,
|
|
146
|
+
mode: options.progress,
|
|
148
147
|
});
|
|
149
148
|
const l = new list_1.Listr3({
|
|
150
149
|
streams: options.streams,
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @datatruck/cli
|
|
2
2
|
|
|
3
|
+
## 0.30.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`68e991b`](https://github.com/swordev/datatruck/commit/68e991b862ee3793e6b31d1fd5d6cebdf59524a4) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix allowlist in datatruck server
|
|
8
|
+
|
|
9
|
+
- [`16f982c`](https://github.com/swordev/datatruck/commit/16f982c7da0d44cbbb691d5552da77fb27366f82) Thanks [@juanrgm](https://github.com/juanrgm)! - Reduce progress interval to 300 ms in auto progress mode
|
|
10
|
+
|
|
11
|
+
## 0.30.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [`e28b12d`](https://github.com/swordev/datatruck/commit/e28b12d08c36844317e506552443825ab3333139) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `allowlist` option to the datatruck server
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [`2f63e67`](https://github.com/swordev/datatruck/commit/2f63e67ee532892fda3a9d06e46336a42834e5ed) Thanks [@juanrgm](https://github.com/juanrgm)! - Add download progress in datatruck repository
|
|
20
|
+
|
|
21
|
+
- [`258e933`](https://github.com/swordev/datatruck/commit/258e93385d9b6f93a435a28a2b26e53ea1763755) Thanks [@juanrgm](https://github.com/juanrgm)! - Copy backups safely
|
|
22
|
+
|
|
23
|
+
- [`82b4c67`](https://github.com/swordev/datatruck/commit/82b4c67c55eee4f40753b48eb91345e6d6789f72) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix exit event
|
|
24
|
+
|
|
3
25
|
## 0.29.1
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/Command/BackupCommand.js
CHANGED
|
@@ -61,7 +61,6 @@ class BackupCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
61
61
|
date: this.options.date,
|
|
62
62
|
tty: this.globalOptions.tty,
|
|
63
63
|
progress: this.globalOptions.progress,
|
|
64
|
-
progressInterval: this.globalOptions.progressInterval,
|
|
65
64
|
streams: this.streams,
|
|
66
65
|
prune: this.options.prune,
|
|
67
66
|
});
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.CleanCacheCommand = void 0;
|
|
7
4
|
const CleanCacheAction_1 = require("../Action/CleanCacheAction");
|
|
8
5
|
const DataFormat_1 = require("../utils/DataFormat");
|
|
6
|
+
const bytes_1 = require("../utils/bytes");
|
|
9
7
|
const CommandAbstract_1 = require("./CommandAbstract");
|
|
10
|
-
const bytes_1 = __importDefault(require("bytes"));
|
|
11
8
|
class CleanCacheCommand extends CommandAbstract_1.CommandAbstract {
|
|
12
9
|
onOptions() {
|
|
13
10
|
return this.returnsOptions({});
|
|
@@ -29,7 +26,7 @@ class CleanCacheCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
29
26
|
value: "Freed disk space",
|
|
30
27
|
},
|
|
31
28
|
],
|
|
32
|
-
rows: () => [[result.path, (0, bytes_1.
|
|
29
|
+
rows: () => [[result.path, (0, bytes_1.formatBytes)(result.freedSize)]],
|
|
33
30
|
},
|
|
34
31
|
});
|
|
35
32
|
await cleanCache.exec();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ConfigType } from "../Config/Config";
|
|
2
2
|
import { FormatType } from "../utils/DataFormat";
|
|
3
3
|
import { OptionsType } from "../utils/cli";
|
|
4
|
+
import { ProgressMode } from "../utils/progress";
|
|
4
5
|
import { Streams } from "../utils/stream";
|
|
5
6
|
import { If, SimilarObject } from "../utils/ts";
|
|
6
7
|
export type GlobalOptions<TResolved = false> = {
|
|
@@ -8,8 +9,7 @@ export type GlobalOptions<TResolved = false> = {
|
|
|
8
9
|
outputFormat?: FormatType;
|
|
9
10
|
verbose?: number;
|
|
10
11
|
tty?: If<TResolved, "auto" | boolean, "auto" | "true" | "false">;
|
|
11
|
-
progress?: If<TResolved,
|
|
12
|
-
progressInterval?: number;
|
|
12
|
+
progress?: If<TResolved, ProgressMode, Exclude<ProgressMode, boolean> | "true" | "false">;
|
|
13
13
|
};
|
|
14
14
|
export type CommandConstructor<TUnresolvedOptions, TOptions extends SimilarObject<TUnresolvedOptions>> = {
|
|
15
15
|
new (globalOptions: GlobalOptions<true>, options: TOptions): CommandAbstract<TUnresolvedOptions, TOptions>;
|
package/Command/CopyCommand.js
CHANGED
|
@@ -53,7 +53,6 @@ class CopyCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
53
53
|
verbose: verbose > 0,
|
|
54
54
|
tty: this.globalOptions.tty,
|
|
55
55
|
progress: this.globalOptions.progress,
|
|
56
|
-
progressInterval: this.globalOptions.progressInterval,
|
|
57
56
|
});
|
|
58
57
|
const result = await copy.exec();
|
|
59
58
|
if (this.globalOptions.outputFormat)
|
|
@@ -63,7 +63,6 @@ class RestoreCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
63
63
|
initial: this.options.initial,
|
|
64
64
|
tty: this.globalOptions.tty,
|
|
65
65
|
progress: this.globalOptions.progress,
|
|
66
|
-
progressInterval: this.globalOptions.progressInterval,
|
|
67
66
|
streams: this.streams,
|
|
68
67
|
});
|
|
69
68
|
const result = await restore.exec();
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.SnapshotsCommand = void 0;
|
|
7
4
|
const ConfigAction_1 = require("../Action/ConfigAction");
|
|
8
5
|
const SnapshotsAction_1 = require("../Action/SnapshotsAction");
|
|
9
6
|
const DataFormat_1 = require("../utils/DataFormat");
|
|
7
|
+
const bytes_1 = require("../utils/bytes");
|
|
10
8
|
const string_1 = require("../utils/string");
|
|
11
9
|
const CommandAbstract_1 = require("./CommandAbstract");
|
|
12
|
-
const bytes_1 = __importDefault(require("bytes"));
|
|
13
10
|
class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
14
11
|
onOptions() {
|
|
15
12
|
const groupByValues = [
|
|
@@ -139,7 +136,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
139
136
|
item.date.replace("T", " ").replace("Z", ""),
|
|
140
137
|
item.packageName,
|
|
141
138
|
item.packageTaskName || "",
|
|
142
|
-
(0, bytes_1.
|
|
139
|
+
(0, bytes_1.formatBytes)(item.size),
|
|
143
140
|
item.repositoryName,
|
|
144
141
|
item.repositoryType,
|
|
145
142
|
]),
|
package/Config/Config.js
CHANGED
|
@@ -39,6 +39,7 @@ exports.configDefinition = {
|
|
|
39
39
|
additionalProperties: false,
|
|
40
40
|
properties: {
|
|
41
41
|
path: { type: "string" },
|
|
42
|
+
log: { type: "boolean" },
|
|
42
43
|
users: {
|
|
43
44
|
type: "array",
|
|
44
45
|
items: {
|
|
@@ -58,6 +59,27 @@ exports.configDefinition = {
|
|
|
58
59
|
address: { type: "string" },
|
|
59
60
|
},
|
|
60
61
|
},
|
|
62
|
+
trustProxy: {
|
|
63
|
+
anyOf: [
|
|
64
|
+
{ type: "boolean" },
|
|
65
|
+
{
|
|
66
|
+
type: "object",
|
|
67
|
+
additionalProperties: false,
|
|
68
|
+
required: ["remoteAddressHeader"],
|
|
69
|
+
properties: {
|
|
70
|
+
remoteAddressHeader: { type: "string" },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
allowlist: {
|
|
76
|
+
type: "object",
|
|
77
|
+
additionalProperties: false,
|
|
78
|
+
properties: {
|
|
79
|
+
enabled: { type: "boolean" },
|
|
80
|
+
remoteAddresses: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
61
83
|
},
|
|
62
84
|
},
|
|
63
85
|
prunePolicy: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.prunePolicy),
|
|
@@ -58,7 +58,9 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
58
58
|
static zipBasenameTpl = `.*.dd.tar.gz`;
|
|
59
59
|
static buildSnapshotName(snapshot, pkg) {
|
|
60
60
|
const date = snapshot.date.replace(/:/g, "-");
|
|
61
|
-
const pkgName = encodeURIComponent(pkg.name)
|
|
61
|
+
const pkgName = encodeURIComponent(pkg.name)
|
|
62
|
+
.replace(/%40/g, "@")
|
|
63
|
+
.replace("_", "%5F");
|
|
62
64
|
const snapshotShortId = snapshot.id.slice(0, 8);
|
|
63
65
|
return `${date}_${pkgName}_${snapshotShortId}`;
|
|
64
66
|
}
|
|
@@ -260,38 +262,64 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
260
262
|
const snapshotName = DatatruckRepository.buildSnapshotName(data.snapshot, data.package);
|
|
261
263
|
if (data.options.verbose)
|
|
262
264
|
(0, cli_1.logExec)(`Copying backup files to ${data.mirrorRepositoryConfig.backend}`);
|
|
263
|
-
|
|
264
|
-
await targetFs.
|
|
265
|
+
const tmpSnapshotName = `${snapshotName}_tmp`;
|
|
266
|
+
if (await targetFs.existsDir(snapshotName))
|
|
267
|
+
await targetFs.ensureEmptyDir(snapshotName);
|
|
268
|
+
try {
|
|
269
|
+
await targetFs.rmAll(tmpSnapshotName);
|
|
270
|
+
}
|
|
271
|
+
catch (_) { }
|
|
272
|
+
await targetFs.mkdir(tmpSnapshotName);
|
|
273
|
+
await targetFs.ensureEmptyDir(tmpSnapshotName);
|
|
265
274
|
const entries = await sourceFs.readdir(snapshotName);
|
|
266
275
|
const total = entries.length;
|
|
267
276
|
let current = 0;
|
|
268
277
|
for (const entry of entries) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
});
|
|
278
|
+
const absolute = {
|
|
279
|
+
current,
|
|
280
|
+
description: "Copying",
|
|
281
|
+
payload: entry,
|
|
282
|
+
total,
|
|
283
|
+
percent: (0, math_1.progressPercent)(total, current),
|
|
284
|
+
};
|
|
285
|
+
data.onProgress({ absolute });
|
|
278
286
|
current++;
|
|
279
287
|
const sourceEntry = `${snapshotName}/${entry}`;
|
|
288
|
+
const targetEntry = `${tmpSnapshotName}/${entry}`;
|
|
280
289
|
if (targetFs.isLocal()) {
|
|
281
|
-
await sourceFs.download(sourceEntry, targetFs.resolvePath(
|
|
290
|
+
await sourceFs.download(sourceEntry, targetFs.resolvePath(targetEntry), {
|
|
291
|
+
onProgress: (progress) => data.onProgress({
|
|
292
|
+
absolute,
|
|
293
|
+
relative: {
|
|
294
|
+
description: "Downloading",
|
|
295
|
+
format: "size",
|
|
296
|
+
...progress,
|
|
297
|
+
},
|
|
298
|
+
}),
|
|
299
|
+
});
|
|
282
300
|
}
|
|
283
301
|
else {
|
|
284
302
|
const tempDir = await (0, temp_1.mkTmpDir)(exports.datatruckRepositoryName, "repo", "remote-copy", entry);
|
|
285
303
|
const tempFile = (0, path_1.join)(tempDir, entry);
|
|
286
304
|
try {
|
|
287
|
-
await sourceFs.download(sourceEntry, tempFile
|
|
288
|
-
|
|
305
|
+
await sourceFs.download(sourceEntry, tempFile, {
|
|
306
|
+
onProgress: (progress) => data.onProgress({
|
|
307
|
+
absolute,
|
|
308
|
+
relative: {
|
|
309
|
+
description: "Downloading",
|
|
310
|
+
format: "size",
|
|
311
|
+
...progress,
|
|
312
|
+
},
|
|
313
|
+
}),
|
|
314
|
+
});
|
|
315
|
+
await targetFs.upload(tempFile, targetEntry);
|
|
289
316
|
}
|
|
290
317
|
finally {
|
|
291
318
|
await (0, fs_1.tryRm)(tempFile);
|
|
292
319
|
}
|
|
293
320
|
}
|
|
294
321
|
}
|
|
322
|
+
await targetFs.rename(tmpSnapshotName, snapshotName);
|
|
295
323
|
}
|
|
296
324
|
async restore(data) {
|
|
297
325
|
const fs = (0, client_1.createFs)(this.config.backend);
|
package/cli.js
CHANGED
|
@@ -9,8 +9,8 @@ const AppError_1 = require("./Error/AppError");
|
|
|
9
9
|
const CommandFactory_1 = require("./Factory/CommandFactory");
|
|
10
10
|
const globalData_1 = __importDefault(require("./globalData"));
|
|
11
11
|
const cli_1 = require("./utils/cli");
|
|
12
|
+
const exit_1 = require("./utils/exit");
|
|
12
13
|
const fs_1 = require("./utils/fs");
|
|
13
|
-
const process_1 = require("./utils/process");
|
|
14
14
|
const string_1 = require("./utils/string");
|
|
15
15
|
const temp_1 = require("./utils/temp");
|
|
16
16
|
const chalk_1 = require("chalk");
|
|
@@ -19,12 +19,11 @@ const fs_2 = require("fs");
|
|
|
19
19
|
const path_1 = require("path");
|
|
20
20
|
function getGlobalOptions() {
|
|
21
21
|
const result = program.opts();
|
|
22
|
+
const parseBool = (v) => v === "true" ? true : v === "false" ? false : v;
|
|
22
23
|
return {
|
|
23
24
|
...result,
|
|
24
|
-
tty: result.tty
|
|
25
|
-
progress: result.progress
|
|
26
|
-
? result.progress
|
|
27
|
-
: result.progress === "true",
|
|
25
|
+
tty: parseBool(result.tty),
|
|
26
|
+
progress: parseBool(result.progress),
|
|
28
27
|
};
|
|
29
28
|
}
|
|
30
29
|
function makeCommand(command) {
|
|
@@ -89,8 +88,7 @@ program.usage("dtt");
|
|
|
89
88
|
program.option("-v,--verbose", "Verbose", (_, previous) => previous + 1, 0);
|
|
90
89
|
program.option("-c,--config <path>", "Config path", process.env["DATATRUCK_CONFIG"] ?? (cwd.endsWith(path_1.sep) ? cwd : `${cwd}${path_1.sep}`));
|
|
91
90
|
program.option("--tty <value>", "TTY mode (auto, true, false)", "auto");
|
|
92
|
-
program.option("--progress <value>", "Progress type (auto, true, false, interval)", "auto");
|
|
93
|
-
program.option("--progress-interval <ms>", "Progress interval", Number, 1000);
|
|
91
|
+
program.option("--progress <value>", "Progress type (auto, true, false, interval, interval:[ms])", "auto");
|
|
94
92
|
program.option("-o,--output-format <format>", "Output format (json, pjson, yaml, table, custom=$, tpl=name)", "table");
|
|
95
93
|
makeCommand(CommandFactory_1.CommandEnum.startServer).alias("start");
|
|
96
94
|
makeCommand(CommandFactory_1.CommandEnum.config).alias("c");
|
|
@@ -112,7 +110,7 @@ exports.buildArgs = buildArgs;
|
|
|
112
110
|
function parseArgs(args) {
|
|
113
111
|
program.parse(args);
|
|
114
112
|
const verbose = getGlobalOptions().verbose;
|
|
115
|
-
(0,
|
|
113
|
+
(0, exit_1.onExit)((eventName, error) => {
|
|
116
114
|
if (eventName !== "exit") {
|
|
117
115
|
process.stdout.write(cli_1.showCursorCommand);
|
|
118
116
|
console.info(`\nClosing... (reason: ${eventName})`);
|
package/config.schema.json
CHANGED
|
@@ -1051,6 +1051,9 @@
|
|
|
1051
1051
|
"path": {
|
|
1052
1052
|
"type": "string"
|
|
1053
1053
|
},
|
|
1054
|
+
"log": {
|
|
1055
|
+
"type": "boolean"
|
|
1056
|
+
},
|
|
1054
1057
|
"users": {
|
|
1055
1058
|
"type": "array",
|
|
1056
1059
|
"items": {
|
|
@@ -1077,6 +1080,37 @@
|
|
|
1077
1080
|
"type": "string"
|
|
1078
1081
|
}
|
|
1079
1082
|
}
|
|
1083
|
+
},
|
|
1084
|
+
"trustProxy": {
|
|
1085
|
+
"anyOf": [
|
|
1086
|
+
{
|
|
1087
|
+
"type": "boolean"
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
"type": "object",
|
|
1091
|
+
"additionalProperties": false,
|
|
1092
|
+
"required": [
|
|
1093
|
+
"remoteAddressHeader"
|
|
1094
|
+
],
|
|
1095
|
+
"properties": {
|
|
1096
|
+
"remoteAddressHeader": {
|
|
1097
|
+
"type": "string"
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
]
|
|
1102
|
+
},
|
|
1103
|
+
"allowlist": {
|
|
1104
|
+
"type": "object",
|
|
1105
|
+
"additionalProperties": false,
|
|
1106
|
+
"properties": {
|
|
1107
|
+
"enabled": {
|
|
1108
|
+
"type": "boolean"
|
|
1109
|
+
},
|
|
1110
|
+
"remoteAddresses": {
|
|
1111
|
+
"$ref": "#/definitions/stringlist-util"
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1080
1114
|
}
|
|
1081
1115
|
}
|
|
1082
1116
|
},
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datatruck/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.1",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@supercharge/promise-pool": "^3.1.0",
|
|
6
6
|
"ajv": "^8.12.0",
|
|
7
7
|
"async": "^3.2.4",
|
|
8
|
-
"bytes": "^3.1.2",
|
|
9
8
|
"chalk": "^4.1.2",
|
|
10
9
|
"commander": "^11.0.0",
|
|
11
10
|
"dayjs": "^1.11.10",
|
package/utils/bytes.d.ts
ADDED
package/utils/bytes.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSize = exports.formatBytes = void 0;
|
|
4
|
+
const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
5
|
+
const sizeRegex = new RegExp(`^(\\d+(?:\\.\\d+)?)\\s*(${units.join("|")})$`, "i");
|
|
6
|
+
function formatBytes(bytes) {
|
|
7
|
+
let u = 0;
|
|
8
|
+
let n = bytes;
|
|
9
|
+
if (bytes < 0n)
|
|
10
|
+
throw new Error(`Invalid bytes: ${bytes.toString()}`);
|
|
11
|
+
while (n >= 1024n && ++u)
|
|
12
|
+
n = n / 1024;
|
|
13
|
+
return Number(n).toFixed(n < 10 && u > 0 ? 1 : 0) + units[u];
|
|
14
|
+
}
|
|
15
|
+
exports.formatBytes = formatBytes;
|
|
16
|
+
function parseSize(size) {
|
|
17
|
+
const matches = sizeRegex.exec(size);
|
|
18
|
+
if (!matches)
|
|
19
|
+
throw new Error(`Invalid size: ${size}`);
|
|
20
|
+
const [, value, unit] = matches;
|
|
21
|
+
const unitIndex = units.findIndex((v) => v === unit.toUpperCase());
|
|
22
|
+
if (unitIndex === -1)
|
|
23
|
+
throw new Error(`Unit not found: ${unit}`);
|
|
24
|
+
let result = Number(value);
|
|
25
|
+
for (let i = 0; i < unitIndex; ++i)
|
|
26
|
+
result *= 1024;
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
exports.parseSize = parseSize;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DiskStats } from "../fs";
|
|
2
|
+
import { BasicProgress } from "../progress";
|
|
2
3
|
import { AbstractFs, FsOptions } from "../virtual-fs";
|
|
3
4
|
export declare class RemoteFs extends AbstractFs {
|
|
4
5
|
readonly options: FsOptions;
|
|
@@ -9,6 +10,7 @@ export declare class RemoteFs extends AbstractFs {
|
|
|
9
10
|
protected fetchJson(name: string, params: any[]): Promise<any>;
|
|
10
11
|
protected post(name: string, params: any[], data: string): Promise<void>;
|
|
11
12
|
existsDir(path: string): Promise<any>;
|
|
13
|
+
rename(source: string, target: string): Promise<any>;
|
|
12
14
|
mkdir(path: string): Promise<any>;
|
|
13
15
|
readFile(path: string): Promise<any>;
|
|
14
16
|
readdir(path: string): Promise<any>;
|
|
@@ -18,7 +20,10 @@ export declare class RemoteFs extends AbstractFs {
|
|
|
18
20
|
rmAll(path: string): Promise<void>;
|
|
19
21
|
fetchDiskStats(path: string): Promise<DiskStats>;
|
|
20
22
|
upload(source: string, target: string): Promise<void>;
|
|
21
|
-
download(source: string, target: string,
|
|
23
|
+
download(source: string, target: string, options?: {
|
|
24
|
+
timeout?: number;
|
|
25
|
+
onProgress?: (progress: BasicProgress) => void;
|
|
26
|
+
}): Promise<void>;
|
|
22
27
|
}
|
|
23
28
|
export declare function isRemoteBackend(backend: string): boolean;
|
|
24
29
|
export declare function createFs(backend: string): AbstractFs;
|
|
@@ -44,6 +44,9 @@ class RemoteFs extends virtual_fs_1.AbstractFs {
|
|
|
44
44
|
async existsDir(path) {
|
|
45
45
|
return await this.fetchJson("existsDir", [path]);
|
|
46
46
|
}
|
|
47
|
+
async rename(source, target) {
|
|
48
|
+
return await this.fetchJson("rename", [source, target]);
|
|
49
|
+
}
|
|
47
50
|
async mkdir(path) {
|
|
48
51
|
return await this.fetchJson("mkdir", [path]);
|
|
49
52
|
}
|
|
@@ -76,13 +79,11 @@ class RemoteFs extends virtual_fs_1.AbstractFs {
|
|
|
76
79
|
},
|
|
77
80
|
});
|
|
78
81
|
}
|
|
79
|
-
async download(source, target,
|
|
82
|
+
async download(source, target, options = {}) {
|
|
80
83
|
await (0, http_1.downloadFile)(`${this.url}/download`, target, {
|
|
81
|
-
|
|
84
|
+
...options,
|
|
82
85
|
headers: this.headers,
|
|
83
|
-
query: {
|
|
84
|
-
params: JSON.stringify([source]),
|
|
85
|
-
},
|
|
86
|
+
query: { params: JSON.stringify([source]) },
|
|
86
87
|
});
|
|
87
88
|
}
|
|
88
89
|
}
|
|
@@ -12,6 +12,16 @@ export type DatatruckServerOptions = {
|
|
|
12
12
|
address?: string;
|
|
13
13
|
};
|
|
14
14
|
users?: User[];
|
|
15
|
+
trustProxy?: true | {
|
|
16
|
+
remoteAddressHeader: string;
|
|
17
|
+
};
|
|
18
|
+
allowlist?: {
|
|
19
|
+
/**
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
remoteAddresses?: string[];
|
|
24
|
+
};
|
|
15
25
|
};
|
|
16
26
|
export declare const headerKey: {
|
|
17
27
|
user: string;
|