@datatruck/cli 0.12.1 → 0.13.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.
- package/Command/BackupCommand.js +2 -0
- package/Command/CommandAbstract.d.ts +2 -0
- package/Command/RestoreCommand.js +2 -0
- package/Command/SnapshotsCommand.js +6 -0
- package/Config/PackageRepositoryConfig.d.ts +3 -3
- package/Config/PackageRepositoryConfig.js +2 -2
- package/Config/RepositoryConfig.d.ts +3 -3
- package/Config/RepositoryConfig.js +2 -2
- package/Factory/RepositoryFactory.js +3 -3
- package/JsonSchema/DefinitionEnum.d.ts +2 -2
- package/JsonSchema/DefinitionEnum.js +2 -2
- package/JsonSchema/JsonSchema.js +3 -3
- package/Repository/{LocalRepository.d.ts → DatatruckRepository.d.ts} +10 -9
- package/Repository/{LocalRepository.js → DatatruckRepository.js} +16 -14
- package/Repository/GitRepository.js +3 -0
- package/Repository/RepositoryAbstract.d.ts +4 -1
- package/Repository/RepositoryAbstract.js +1 -0
- package/Repository/ResticRepository.js +25 -1
- package/SessionDriver/ConsoleSessionDriver.d.ts +8 -2
- package/SessionDriver/ConsoleSessionDriver.js +18 -10
- package/SessionDriver/SessionDriverAbstract.d.ts +6 -7
- package/cli.js +2 -0
- package/config.schema.json +6 -6
- package/package.json +3 -1
- package/util/ResticUtil.d.ts +9 -2
- package/util/ResticUtil.js +47 -20
- package/util/datatruck/config-util.d.ts +6 -6
- package/util/fs-util.d.ts +1 -0
- package/util/fs-util.js +7 -1
- package/util/process-util.js +3 -1
package/Command/BackupCommand.js
CHANGED
|
@@ -67,6 +67,8 @@ class BackupCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
67
67
|
altDrivers: [
|
|
68
68
|
new ConsoleSessionDriver_1.ConsoleSessionDriver({
|
|
69
69
|
verbose: verbose > 0,
|
|
70
|
+
progress: this.globalOptions.progress,
|
|
71
|
+
progressInterval: this.globalOptions.progressInterval,
|
|
70
72
|
}),
|
|
71
73
|
],
|
|
72
74
|
});
|
|
@@ -6,6 +6,8 @@ export declare type GlobalOptionsType<TResolved = false> = {
|
|
|
6
6
|
config: string | ConfigType;
|
|
7
7
|
outputFormat?: FormatType;
|
|
8
8
|
verbose?: number;
|
|
9
|
+
progress?: "auto" | "plain" | "tty";
|
|
10
|
+
progressInterval?: number;
|
|
9
11
|
};
|
|
10
12
|
export declare type CommandConstructorType<TUnresolvedOptions, TOptions extends SimilarObject<TUnresolvedOptions>> = {
|
|
11
13
|
new (globalOptions: GlobalOptionsType<true>, options: TOptions): CommandAbstract<TUnresolvedOptions, TOptions>;
|
|
@@ -67,6 +67,8 @@ class RestoreCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
67
67
|
altDrivers: [
|
|
68
68
|
new ConsoleSessionDriver_1.ConsoleSessionDriver({
|
|
69
69
|
verbose: verbose > 0,
|
|
70
|
+
progress: this.globalOptions.progress,
|
|
71
|
+
progressInterval: this.globalOptions.progressInterval,
|
|
70
72
|
}),
|
|
71
73
|
],
|
|
72
74
|
verbose: verbose > 1,
|
|
@@ -1,4 +1,7 @@
|
|
|
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 });
|
|
3
6
|
exports.SnapshotsCommand = void 0;
|
|
4
7
|
const ConfigAction_1 = require("../Action/ConfigAction");
|
|
@@ -6,6 +9,7 @@ const SnapshotsAction_1 = require("../Action/SnapshotsAction");
|
|
|
6
9
|
const DataFormat_1 = require("../util/DataFormat");
|
|
7
10
|
const string_util_1 = require("../util/string-util");
|
|
8
11
|
const CommandAbstract_1 = require("./CommandAbstract");
|
|
12
|
+
const pretty_bytes_1 = __importDefault(require("pretty-bytes"));
|
|
9
13
|
class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
10
14
|
onOptions() {
|
|
11
15
|
const groupByValues = ["packageName", "repositoryName", "repositoryType"];
|
|
@@ -120,6 +124,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
120
124
|
"Date",
|
|
121
125
|
"Package",
|
|
122
126
|
"Task",
|
|
127
|
+
"Size",
|
|
123
128
|
"Repository",
|
|
124
129
|
"Repository type",
|
|
125
130
|
],
|
|
@@ -128,6 +133,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
128
133
|
item.date.replace("T", " ").replace("Z", ""),
|
|
129
134
|
item.packageName,
|
|
130
135
|
item.packageTaskName || "",
|
|
136
|
+
(0, pretty_bytes_1.default)(item.size),
|
|
131
137
|
item.repositoryName,
|
|
132
138
|
item.repositoryType,
|
|
133
139
|
],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { DatatruckPackageRepositoryConfigType, datatruckRepositoryName } from "../Repository/DatatruckRepository";
|
|
1
2
|
import { GitPackageRepositoryConfigType, gitRepositoryName } from "../Repository/GitRepository";
|
|
2
|
-
import { LocalPackageRepositoryConfigType, localRepositoryName } from "../Repository/LocalRepository";
|
|
3
3
|
import { ResticPackageRepositoryConfigType, resticRepositoryName } from "../Repository/ResticRepository";
|
|
4
4
|
import type { JSONSchema7 } from "json-schema";
|
|
5
5
|
export declare const packageRepositoryConfigDefinition: JSONSchema7;
|
|
@@ -9,8 +9,8 @@ export declare type PackageRepositoryConfigType = {
|
|
|
9
9
|
type: typeof resticRepositoryName;
|
|
10
10
|
config: ResticPackageRepositoryConfigType;
|
|
11
11
|
} | {
|
|
12
|
-
type: typeof
|
|
13
|
-
config:
|
|
12
|
+
type: typeof datatruckRepositoryName;
|
|
13
|
+
config: DatatruckPackageRepositoryConfigType;
|
|
14
14
|
} | {
|
|
15
15
|
type: typeof gitRepositoryName;
|
|
16
16
|
config: GitPackageRepositoryConfigType;
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.packageRepositoryConfigDefinition = void 0;
|
|
4
4
|
const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
|
|
5
|
+
const DatatruckRepository_1 = require("../Repository/DatatruckRepository");
|
|
5
6
|
const GitRepository_1 = require("../Repository/GitRepository");
|
|
6
|
-
const LocalRepository_1 = require("../Repository/LocalRepository");
|
|
7
7
|
const ResticRepository_1 = require("../Repository/ResticRepository");
|
|
8
8
|
const types = {
|
|
9
9
|
[ResticRepository_1.resticRepositoryName]: DefinitionEnum_1.DefinitionEnum.resticPackageRepository,
|
|
10
|
-
[
|
|
10
|
+
[DatatruckRepository_1.datatruckRepositoryName]: DefinitionEnum_1.DefinitionEnum.datatruckPackageRepository,
|
|
11
11
|
[GitRepository_1.gitRepositoryName]: DefinitionEnum_1.DefinitionEnum.gitPackageRepository,
|
|
12
12
|
};
|
|
13
13
|
exports.packageRepositoryConfigDefinition = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { DatatruckRepositoryConfigType, datatruckRepositoryName } from "../Repository/DatatruckRepository";
|
|
1
2
|
import { GitRepositoryConfigType, gitRepositoryName } from "../Repository/GitRepository";
|
|
2
|
-
import { LocalRepositoryConfigType, localRepositoryName } from "../Repository/LocalRepository";
|
|
3
3
|
import { ResticRepositoryConfigType, resticRepositoryName } from "../Repository/ResticRepository";
|
|
4
4
|
import type { JSONSchema7 } from "json-schema";
|
|
5
5
|
export declare const repositoryConfigDefinition: JSONSchema7;
|
|
@@ -15,8 +15,8 @@ export declare type RepositoryConfigType = {
|
|
|
15
15
|
type: typeof resticRepositoryName;
|
|
16
16
|
config: ResticRepositoryConfigType;
|
|
17
17
|
} | {
|
|
18
|
-
type: typeof
|
|
19
|
-
config:
|
|
18
|
+
type: typeof datatruckRepositoryName;
|
|
19
|
+
config: DatatruckRepositoryConfigType;
|
|
20
20
|
} | {
|
|
21
21
|
type: typeof gitRepositoryName;
|
|
22
22
|
config: GitRepositoryConfigType;
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.repositoryConfigDefinition = void 0;
|
|
4
4
|
const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
|
|
5
|
+
const DatatruckRepository_1 = require("../Repository/DatatruckRepository");
|
|
5
6
|
const GitRepository_1 = require("../Repository/GitRepository");
|
|
6
|
-
const LocalRepository_1 = require("../Repository/LocalRepository");
|
|
7
7
|
const ResticRepository_1 = require("../Repository/ResticRepository");
|
|
8
8
|
const types = {
|
|
9
9
|
[ResticRepository_1.resticRepositoryName]: DefinitionEnum_1.DefinitionEnum.resticRepository,
|
|
10
|
-
[
|
|
10
|
+
[DatatruckRepository_1.datatruckRepositoryName]: DefinitionEnum_1.DefinitionEnum.datatruckRepository,
|
|
11
11
|
[GitRepository_1.gitRepositoryName]: DefinitionEnum_1.DefinitionEnum.gitRepository,
|
|
12
12
|
};
|
|
13
13
|
exports.repositoryConfigDefinition = {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RepositoryFactory = void 0;
|
|
4
4
|
const AppError_1 = require("../Error/AppError");
|
|
5
|
+
const DatatruckRepository_1 = require("../Repository/DatatruckRepository");
|
|
5
6
|
const GitRepository_1 = require("../Repository/GitRepository");
|
|
6
|
-
const LocalRepository_1 = require("../Repository/LocalRepository");
|
|
7
7
|
const ResticRepository_1 = require("../Repository/ResticRepository");
|
|
8
8
|
function RepositoryFactory(repository) {
|
|
9
9
|
const type = repository.type;
|
|
@@ -13,8 +13,8 @@ function RepositoryFactory(repository) {
|
|
|
13
13
|
else if (type === ResticRepository_1.resticRepositoryName) {
|
|
14
14
|
return new ResticRepository_1.ResticRepository(repository);
|
|
15
15
|
}
|
|
16
|
-
else if (type ===
|
|
17
|
-
return new
|
|
16
|
+
else if (type === DatatruckRepository_1.datatruckRepositoryName) {
|
|
17
|
+
return new DatatruckRepository_1.DatatruckRepository(repository);
|
|
18
18
|
}
|
|
19
19
|
else {
|
|
20
20
|
throw new AppError_1.AppError(`Invalid repository type: ${type}`);
|
|
@@ -6,8 +6,8 @@ export declare enum DefinitionEnum {
|
|
|
6
6
|
task = "task",
|
|
7
7
|
resticRepository = "restic-repository",
|
|
8
8
|
resticPackageRepository = "restic-package-repository",
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
datatruckRepository = "datatruck-repository",
|
|
10
|
+
datatruckPackageRepository = "datatruck-package-repository",
|
|
11
11
|
gitRepository = "git-repository",
|
|
12
12
|
gitPackageRepository = "git-package-repository",
|
|
13
13
|
gitTask = "git-task",
|
|
@@ -10,8 +10,8 @@ var DefinitionEnum;
|
|
|
10
10
|
DefinitionEnum["task"] = "task";
|
|
11
11
|
DefinitionEnum["resticRepository"] = "restic-repository";
|
|
12
12
|
DefinitionEnum["resticPackageRepository"] = "restic-package-repository";
|
|
13
|
-
DefinitionEnum["
|
|
14
|
-
DefinitionEnum["
|
|
13
|
+
DefinitionEnum["datatruckRepository"] = "datatruck-repository";
|
|
14
|
+
DefinitionEnum["datatruckPackageRepository"] = "datatruck-package-repository";
|
|
15
15
|
DefinitionEnum["gitRepository"] = "git-repository";
|
|
16
16
|
DefinitionEnum["gitPackageRepository"] = "git-package-repository";
|
|
17
17
|
DefinitionEnum["gitTask"] = "git-task";
|
package/JsonSchema/JsonSchema.js
CHANGED
|
@@ -7,8 +7,8 @@ const PackageRepositoryConfig_1 = require("../Config/PackageRepositoryConfig");
|
|
|
7
7
|
const PrunePolicyConfig_1 = require("../Config/PrunePolicyConfig");
|
|
8
8
|
const RepositoryConfig_1 = require("../Config/RepositoryConfig");
|
|
9
9
|
const TaskConfig_1 = require("../Config/TaskConfig");
|
|
10
|
+
const DatatruckRepository_1 = require("../Repository/DatatruckRepository");
|
|
10
11
|
const GitRepository_1 = require("../Repository/GitRepository");
|
|
11
|
-
const LocalRepository_1 = require("../Repository/LocalRepository");
|
|
12
12
|
const ResticRepository_1 = require("../Repository/ResticRepository");
|
|
13
13
|
const GitTask_1 = require("../Task/GitTask");
|
|
14
14
|
const MariadbTask_1 = require("../Task/MariadbTask");
|
|
@@ -31,8 +31,8 @@ exports.definitions = {
|
|
|
31
31
|
[DefinitionEnum_1.DefinitionEnum.task]: TaskConfig_1.taskConfigDefinition,
|
|
32
32
|
[DefinitionEnum_1.DefinitionEnum.gitRepository]: GitRepository_1.gitRepositoryDefinition,
|
|
33
33
|
[DefinitionEnum_1.DefinitionEnum.gitPackageRepository]: GitRepository_1.gitPackageRepositoryDefinition,
|
|
34
|
-
[DefinitionEnum_1.DefinitionEnum.
|
|
35
|
-
[DefinitionEnum_1.DefinitionEnum.
|
|
34
|
+
[DefinitionEnum_1.DefinitionEnum.datatruckRepository]: DatatruckRepository_1.datatruckRepositoryDefinition,
|
|
35
|
+
[DefinitionEnum_1.DefinitionEnum.datatruckPackageRepository]: DatatruckRepository_1.datatruckPackageRepositoryDefinition,
|
|
36
36
|
[DefinitionEnum_1.DefinitionEnum.resticRepository]: ResticRepository_1.resticRepositoryDefinition,
|
|
37
37
|
[DefinitionEnum_1.DefinitionEnum.resticPackageRepository]: ResticRepository_1.resticPackageRepositoryDefinition,
|
|
38
38
|
[DefinitionEnum_1.DefinitionEnum.gitTask]: GitTask_1.gitTaskDefinition,
|
|
@@ -7,8 +7,9 @@ export declare type MetaDataType = {
|
|
|
7
7
|
task: string | undefined;
|
|
8
8
|
tags: string[];
|
|
9
9
|
version: string;
|
|
10
|
+
size: number;
|
|
10
11
|
};
|
|
11
|
-
export declare type
|
|
12
|
+
export declare type DatatruckRepositoryConfigType = {
|
|
12
13
|
outPath: string;
|
|
13
14
|
compress?: boolean;
|
|
14
15
|
/**
|
|
@@ -23,13 +24,13 @@ declare type CompressObjectType = {
|
|
|
23
24
|
onePackByResult?: boolean;
|
|
24
25
|
}[];
|
|
25
26
|
};
|
|
26
|
-
export declare type
|
|
27
|
+
export declare type DatatruckPackageRepositoryConfigType = {
|
|
27
28
|
compress?: CompressObjectType | boolean;
|
|
28
29
|
};
|
|
29
|
-
export declare const
|
|
30
|
-
export declare const
|
|
31
|
-
export declare const
|
|
32
|
-
export declare class
|
|
30
|
+
export declare const datatruckRepositoryName = "datatruck";
|
|
31
|
+
export declare const datatruckRepositoryDefinition: JSONSchema7;
|
|
32
|
+
export declare const datatruckPackageRepositoryDefinition: JSONSchema7;
|
|
33
|
+
export declare class DatatruckRepository extends RepositoryAbstract<DatatruckRepositoryConfigType> {
|
|
33
34
|
static zipBasenameTpl: string;
|
|
34
35
|
static buildSnapshotName(data: {
|
|
35
36
|
snapshotId: string;
|
|
@@ -50,8 +51,8 @@ export declare class LocalRepository extends RepositoryAbstract<LocalRepositoryC
|
|
|
50
51
|
onPrune(data: PruneDataType): Promise<void>;
|
|
51
52
|
onSnapshots(data: SnapshotsDataType): Promise<SnapshotResultType[]>;
|
|
52
53
|
private normalizeCompressConfig;
|
|
53
|
-
onBackup(data: BackupDataType<
|
|
54
|
-
onCopyBackup(data: CopyBackupType<
|
|
55
|
-
onRestore(data: RestoreDataType<
|
|
54
|
+
onBackup(data: BackupDataType<DatatruckPackageRepositoryConfigType>): Promise<void>;
|
|
55
|
+
onCopyBackup(data: CopyBackupType<DatatruckRepositoryConfigType>): Promise<void>;
|
|
56
|
+
onRestore(data: RestoreDataType<DatatruckPackageRepositoryConfigType>): Promise<void>;
|
|
56
57
|
}
|
|
57
58
|
export {};
|
|
@@ -3,7 +3,7 @@ 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.
|
|
6
|
+
exports.DatatruckRepository = exports.datatruckPackageRepositoryDefinition = exports.datatruckRepositoryDefinition = exports.datatruckRepositoryName = void 0;
|
|
7
7
|
const AppError_1 = require("../Error/AppError");
|
|
8
8
|
const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
|
|
9
9
|
const cli_util_1 = require("../util/cli-util");
|
|
@@ -20,8 +20,8 @@ const promises_1 = require("fs/promises");
|
|
|
20
20
|
const micromatch_1 = require("micromatch");
|
|
21
21
|
const path_1 = require("path");
|
|
22
22
|
const readline_1 = require("readline");
|
|
23
|
-
exports.
|
|
24
|
-
exports.
|
|
23
|
+
exports.datatruckRepositoryName = "datatruck";
|
|
24
|
+
exports.datatruckRepositoryDefinition = {
|
|
25
25
|
type: "object",
|
|
26
26
|
required: ["outPath"],
|
|
27
27
|
additionalProperties: false,
|
|
@@ -30,7 +30,7 @@ exports.localRepositoryDefinition = {
|
|
|
30
30
|
compress: { type: "boolean" },
|
|
31
31
|
},
|
|
32
32
|
};
|
|
33
|
-
exports.
|
|
33
|
+
exports.datatruckPackageRepositoryDefinition = {
|
|
34
34
|
type: "object",
|
|
35
35
|
additionalProperties: false,
|
|
36
36
|
properties: {
|
|
@@ -66,7 +66,7 @@ exports.localPackageRepositoryDefinition = {
|
|
|
66
66
|
},
|
|
67
67
|
},
|
|
68
68
|
};
|
|
69
|
-
class
|
|
69
|
+
class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
70
70
|
static buildSnapshotName(data) {
|
|
71
71
|
const date = data.snapshotDate.replace(/:/g, "-");
|
|
72
72
|
const pkgName = encodeURIComponent(data.packageName).replace(/%40/g, "@");
|
|
@@ -103,7 +103,7 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
103
103
|
await (0, fs_util_1.mkdirIfNotExists)(this.config.outPath);
|
|
104
104
|
}
|
|
105
105
|
async onPrune(data) {
|
|
106
|
-
const snapshotName =
|
|
106
|
+
const snapshotName = DatatruckRepository.buildSnapshotName({
|
|
107
107
|
snapshotId: data.snapshot.id,
|
|
108
108
|
snapshotDate: data.snapshot.date,
|
|
109
109
|
packageName: data.snapshot.packageName,
|
|
@@ -127,7 +127,7 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
127
127
|
const packagePatterns = (0, string_util_1.makePathPatterns)(data.options.packageNames);
|
|
128
128
|
const taskPatterns = (0, string_util_1.makePathPatterns)(data.options.packageTaskNames);
|
|
129
129
|
for (const snapshotName of snapshotNames) {
|
|
130
|
-
const snapshotNameData =
|
|
130
|
+
const snapshotNameData = DatatruckRepository.parseSnapshotName(snapshotName);
|
|
131
131
|
if (!snapshotNameData)
|
|
132
132
|
continue;
|
|
133
133
|
if (packagePatterns &&
|
|
@@ -137,7 +137,7 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
137
137
|
!data.options.ids.some((id) => snapshotNameData.snapshotShortId.startsWith(id.slice(0, 8))))
|
|
138
138
|
continue;
|
|
139
139
|
const metaPath = (0, path_1.join)(this.config.outPath, snapshotName);
|
|
140
|
-
const meta = await
|
|
140
|
+
const meta = await DatatruckRepository.parseMetaData(metaPath);
|
|
141
141
|
if (taskPatterns && !(0, string_util_1.checkMatch)(meta.task, taskPatterns))
|
|
142
142
|
continue;
|
|
143
143
|
if (data.options.ids &&
|
|
@@ -153,6 +153,7 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
153
153
|
packageName: meta.package,
|
|
154
154
|
packageTaskName: meta.task,
|
|
155
155
|
tags: meta.tags,
|
|
156
|
+
size: meta.size || 0,
|
|
156
157
|
});
|
|
157
158
|
}
|
|
158
159
|
return snapshots;
|
|
@@ -174,7 +175,7 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
174
175
|
return compress;
|
|
175
176
|
}
|
|
176
177
|
async onBackup(data) {
|
|
177
|
-
const snapshotName =
|
|
178
|
+
const snapshotName = DatatruckRepository.buildSnapshotName({
|
|
178
179
|
snapshotId: data.snapshot.id,
|
|
179
180
|
snapshotDate: data.snapshot.date,
|
|
180
181
|
packageName: data.package.name,
|
|
@@ -294,13 +295,14 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
294
295
|
package: data.package.name,
|
|
295
296
|
task: data.package.task?.name,
|
|
296
297
|
version: nodePkg.version,
|
|
298
|
+
size: await (0, fs_util_1.fastFolderSizeAsync)(outPath),
|
|
297
299
|
};
|
|
298
300
|
if (data.options.verbose)
|
|
299
301
|
(0, cli_util_1.logExec)(`Writing metadata into ${metaPath}`);
|
|
300
|
-
await (0, promises_1.writeFile)(metaPath,
|
|
302
|
+
await (0, promises_1.writeFile)(metaPath, DatatruckRepository.stringifyMetaData(meta));
|
|
301
303
|
}
|
|
302
304
|
async onCopyBackup(data) {
|
|
303
|
-
const snapshotName =
|
|
305
|
+
const snapshotName = DatatruckRepository.buildSnapshotName({
|
|
304
306
|
snapshotId: data.snapshot.id,
|
|
305
307
|
snapshotDate: data.snapshot.date,
|
|
306
308
|
packageName: data.package.name,
|
|
@@ -332,7 +334,7 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
332
334
|
});
|
|
333
335
|
if (!snapshot)
|
|
334
336
|
throw new AppError_1.AppError("Snapshot not found");
|
|
335
|
-
const snapshotName =
|
|
337
|
+
const snapshotName = DatatruckRepository.buildSnapshotName({
|
|
336
338
|
snapshotId: data.snapshot.id,
|
|
337
339
|
snapshotDate: data.snapshot.date,
|
|
338
340
|
packageName: data.package.name,
|
|
@@ -384,5 +386,5 @@ class LocalRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
384
386
|
});
|
|
385
387
|
}
|
|
386
388
|
}
|
|
387
|
-
exports.
|
|
388
|
-
|
|
389
|
+
exports.DatatruckRepository = DatatruckRepository;
|
|
390
|
+
DatatruckRepository.zipBasenameTpl = `.*.dd.zip`;
|
|
@@ -136,6 +136,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
136
136
|
packageName: parsedTag.package,
|
|
137
137
|
packageTaskName: parsedTag.task,
|
|
138
138
|
tags: parsedTag.tags,
|
|
139
|
+
size: Number(parsedTag.size) || 0,
|
|
139
140
|
});
|
|
140
141
|
return result;
|
|
141
142
|
}, [])
|
|
@@ -207,6 +208,8 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
207
208
|
package: data.package.name,
|
|
208
209
|
task: data.package.task?.name,
|
|
209
210
|
version: nodePkg.version,
|
|
211
|
+
size: ((await (0, fs_util_1.fastFolderSizeAsync)(tmpPath)) -
|
|
212
|
+
(await (0, fs_util_1.fastFolderSizeAsync)((0, path_1.join)(tmpPath, ".git")))).toString(),
|
|
210
213
|
});
|
|
211
214
|
await git.addTag(meta.name, meta.message);
|
|
212
215
|
await git.push({ branchName });
|
|
@@ -13,6 +13,7 @@ export declare type SnapshotResultType = SnapshotType & {
|
|
|
13
13
|
packageName: string;
|
|
14
14
|
packageTaskName: string | undefined;
|
|
15
15
|
tags: string[];
|
|
16
|
+
size: number;
|
|
16
17
|
};
|
|
17
18
|
export declare type ProgressDataType = {
|
|
18
19
|
total?: number;
|
|
@@ -63,7 +64,8 @@ export declare enum SnapshotTagEnum {
|
|
|
63
64
|
PACKAGE = "package",
|
|
64
65
|
TASK = "task",
|
|
65
66
|
TAGS = "tags",
|
|
66
|
-
VERSION = "version"
|
|
67
|
+
VERSION = "version",
|
|
68
|
+
SIZE = "size"
|
|
67
69
|
}
|
|
68
70
|
export declare type SnapshotTagObjectType = {
|
|
69
71
|
[SnapshotTagEnum.ID]: string;
|
|
@@ -73,6 +75,7 @@ export declare type SnapshotTagObjectType = {
|
|
|
73
75
|
[SnapshotTagEnum.TASK]: string | undefined;
|
|
74
76
|
[SnapshotTagEnum.TAGS]: string[];
|
|
75
77
|
[SnapshotTagEnum.VERSION]: string;
|
|
78
|
+
[SnapshotTagEnum.SIZE]: string;
|
|
76
79
|
};
|
|
77
80
|
export declare abstract class RepositoryAbstract<TConfig> {
|
|
78
81
|
readonly repository: RepositoryConfigType;
|
|
@@ -10,6 +10,7 @@ var SnapshotTagEnum;
|
|
|
10
10
|
SnapshotTagEnum["TASK"] = "task";
|
|
11
11
|
SnapshotTagEnum["TAGS"] = "tags";
|
|
12
12
|
SnapshotTagEnum["VERSION"] = "version";
|
|
13
|
+
SnapshotTagEnum["SIZE"] = "size";
|
|
13
14
|
})(SnapshotTagEnum = exports.SnapshotTagEnum || (exports.SnapshotTagEnum = {}));
|
|
14
15
|
class RepositoryAbstract {
|
|
15
16
|
constructor(repository) {
|
|
@@ -9,6 +9,7 @@ const ResticUtil_1 = require("../util/ResticUtil");
|
|
|
9
9
|
const cli_util_1 = require("../util/cli-util");
|
|
10
10
|
const paths_util_1 = require("../util/datatruck/paths-util");
|
|
11
11
|
const fs_util_1 = require("../util/fs-util");
|
|
12
|
+
const math_util_1 = require("../util/math-util");
|
|
12
13
|
const string_util_1 = require("../util/string-util");
|
|
13
14
|
const RepositoryAbstract_1 = require("./RepositoryAbstract");
|
|
14
15
|
const assert_1 = require("assert");
|
|
@@ -164,6 +165,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
164
165
|
date: tag.date,
|
|
165
166
|
id: tag.id,
|
|
166
167
|
tags: itemTags,
|
|
168
|
+
size: Number(tag.size) || 0,
|
|
167
169
|
});
|
|
168
170
|
return items;
|
|
169
171
|
}, []);
|
|
@@ -245,6 +247,8 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
245
247
|
await data.onProgress({
|
|
246
248
|
step: "Executing backup action...",
|
|
247
249
|
});
|
|
250
|
+
let resticSnapshotId;
|
|
251
|
+
let resticTotalBytes;
|
|
248
252
|
await restic.backup({
|
|
249
253
|
cwd: sourcePath,
|
|
250
254
|
paths: ["."],
|
|
@@ -281,7 +285,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
281
285
|
totalFilesChanges++;
|
|
282
286
|
}
|
|
283
287
|
await data.onProgress((lastProgress = {
|
|
284
|
-
total: Math.max(lastProgress?.total || 0, streamData.total_files),
|
|
288
|
+
total: Math.max(lastProgress?.total || 0, streamData.total_files || 0),
|
|
285
289
|
current: Math.max(lastProgress?.current || 0, streamData.files_done ?? 0),
|
|
286
290
|
percent: showProgressBar
|
|
287
291
|
? Number((streamData.percent_done * 100).toFixed(2))
|
|
@@ -289,8 +293,18 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
289
293
|
step: streamData.current_files?.join(", ") ?? "-",
|
|
290
294
|
}));
|
|
291
295
|
}
|
|
296
|
+
else if (streamData.message_type === "summary") {
|
|
297
|
+
resticSnapshotId = streamData.snapshot_id;
|
|
298
|
+
resticTotalBytes = streamData.total_bytes_processed;
|
|
299
|
+
}
|
|
292
300
|
},
|
|
293
301
|
});
|
|
302
|
+
if (typeof resticSnapshotId !== "string")
|
|
303
|
+
throw new AppError_1.AppError(`Restic snapshot id is is not defined`);
|
|
304
|
+
if (typeof resticTotalBytes !== "number")
|
|
305
|
+
throw new AppError_1.AppError(`Restic snapshot total bytes is not defined`);
|
|
306
|
+
const sizeTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.SIZE, resticTotalBytes.toString());
|
|
307
|
+
await restic.exec(["tag", "--add", sizeTag, resticSnapshotId]);
|
|
294
308
|
await data.onProgress({
|
|
295
309
|
total: lastProgress?.total || 0,
|
|
296
310
|
current: lastProgress?.total || 0,
|
|
@@ -339,6 +353,16 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
339
353
|
await restic.restore({
|
|
340
354
|
id: snapshot.originalId,
|
|
341
355
|
target: restorePath,
|
|
356
|
+
onStream: async (streamData) => {
|
|
357
|
+
if (streamData.message_type === "restore-status") {
|
|
358
|
+
const current = Math.min(streamData.total_bytes, snapshot.size);
|
|
359
|
+
await data.onProgress({
|
|
360
|
+
total: snapshot.size,
|
|
361
|
+
current,
|
|
362
|
+
percent: (0, math_util_1.progressPercent)(snapshot.size, current),
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
},
|
|
342
366
|
});
|
|
343
367
|
}
|
|
344
368
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { WriteDataType, ReadResultType, SessionDriverAbstract } from "./SessionDriverAbstract";
|
|
2
|
+
import { WriteDataType, ReadResultType, SessionDriverAbstract, SessionDriverOptions } from "./SessionDriverAbstract";
|
|
3
3
|
declare type BadgeType = {
|
|
4
4
|
name: string;
|
|
5
5
|
value: string;
|
|
@@ -18,9 +18,14 @@ declare type MessageType = {
|
|
|
18
18
|
progressStep?: string | null;
|
|
19
19
|
progressStepPercent?: number | null;
|
|
20
20
|
};
|
|
21
|
-
|
|
21
|
+
declare type ConsoleSessionDriverOptions = SessionDriverOptions & {
|
|
22
|
+
progress?: "auto" | "tty" | "plain";
|
|
23
|
+
progressInterval?: number;
|
|
24
|
+
};
|
|
25
|
+
export declare class ConsoleSessionDriver extends SessionDriverAbstract<ConsoleSessionDriverOptions> {
|
|
22
26
|
protected lastMessage: MessageType | undefined;
|
|
23
27
|
protected lastMessageText: string | undefined;
|
|
28
|
+
protected lastProgressDate: number | undefined;
|
|
24
29
|
protected prints: number;
|
|
25
30
|
protected renderInterval: NodeJS.Timeout;
|
|
26
31
|
protected rendering?: boolean;
|
|
@@ -30,6 +35,7 @@ export declare class ConsoleSessionDriver extends SessionDriverAbstract {
|
|
|
30
35
|
start: () => number;
|
|
31
36
|
elapsed: (formatted?: boolean | undefined) => string | number;
|
|
32
37
|
};
|
|
38
|
+
protected tty: boolean;
|
|
33
39
|
onInit(): Promise<void>;
|
|
34
40
|
onEnd(data?: Record<string, any>): Promise<void>;
|
|
35
41
|
onRead(): Promise<ReadResultType[]>;
|
|
@@ -16,6 +16,11 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
16
16
|
this.chron = (0, date_util_1.createChron)();
|
|
17
17
|
}
|
|
18
18
|
async onInit() {
|
|
19
|
+
this.tty = this.options.verbose
|
|
20
|
+
? false
|
|
21
|
+
: this.options.progress === "auto"
|
|
22
|
+
? process.stdout.isTTY
|
|
23
|
+
: this.options.progress === "tty";
|
|
19
24
|
this.chron.start();
|
|
20
25
|
this.renderInterval = setInterval(() => {
|
|
21
26
|
if (this.lastMessage)
|
|
@@ -24,7 +29,7 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
24
29
|
}
|
|
25
30
|
async onEnd(data) {
|
|
26
31
|
clearInterval(this.renderInterval);
|
|
27
|
-
if (
|
|
32
|
+
if (this.tty)
|
|
28
33
|
process.stdout.write(cli_util_1.showCursorCommand);
|
|
29
34
|
(0, cli_util_1.logVars)({
|
|
30
35
|
...data,
|
|
@@ -36,10 +41,10 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
36
41
|
}
|
|
37
42
|
printMessage(message, endMessage) {
|
|
38
43
|
const text = this.renderMessage(message);
|
|
39
|
-
if (this.
|
|
44
|
+
if (!this.tty && this.lastMessageText === text) {
|
|
40
45
|
return;
|
|
41
46
|
}
|
|
42
|
-
if (this.
|
|
47
|
+
if (!this.tty) {
|
|
43
48
|
process.stdout.write(`${this.renderSpinner(text)}\n`);
|
|
44
49
|
}
|
|
45
50
|
else {
|
|
@@ -58,7 +63,7 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
58
63
|
this.lastMessageText = text;
|
|
59
64
|
}
|
|
60
65
|
renderSpinner(text) {
|
|
61
|
-
return text.replace("{spinner}", (0, chalk_1.grey)(this.
|
|
66
|
+
return text.replace("{spinner}", (0, chalk_1.grey)(this.tty ? (0, cli_util_1.renderSpinner)(this.prints) : "?"));
|
|
62
67
|
}
|
|
63
68
|
renderMessage(message) {
|
|
64
69
|
const badges = renderBadges([
|
|
@@ -66,7 +71,6 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
66
71
|
...(message.errorBadge ? [message.errorBadge] : []),
|
|
67
72
|
]);
|
|
68
73
|
const padding = " ".repeat(message.level ?? 0);
|
|
69
|
-
const haveProgressBar = typeof message.progressPercent === "number";
|
|
70
74
|
const sessionId = message.sessionId.toString().padStart(2, "0");
|
|
71
75
|
const parts = [
|
|
72
76
|
`${padding}${message.textPrefix} [${(0, chalk_1.grey)(sessionId)}] ${message.text}`,
|
|
@@ -89,6 +93,13 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
89
93
|
async onWrite(data) {
|
|
90
94
|
if (data.action === SessionDriverAbstract_1.ActionEnum.Init)
|
|
91
95
|
return;
|
|
96
|
+
if (data.action === SessionDriverAbstract_1.ActionEnum.Progress && this.options.progressInterval) {
|
|
97
|
+
const skip = this.lastProgressDate &&
|
|
98
|
+
Date.now() - this.lastProgressDate < this.options.progressInterval;
|
|
99
|
+
if (skip)
|
|
100
|
+
return;
|
|
101
|
+
this.lastProgressDate = Date.now();
|
|
102
|
+
}
|
|
92
103
|
const message = {
|
|
93
104
|
sessionId: "sessionId" in data.data ? data.data.sessionId : data.data.id,
|
|
94
105
|
badges: [],
|
|
@@ -113,9 +124,7 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
113
124
|
if (data.data.error)
|
|
114
125
|
message.errorBadge = {
|
|
115
126
|
name: "error",
|
|
116
|
-
value: this.
|
|
117
|
-
? data.data.error
|
|
118
|
-
: data.data.error.split("\n")[0],
|
|
127
|
+
value: this.tty ? data.data.error.split("\n")[0] : data.data.error,
|
|
119
128
|
color: chalk_1.red,
|
|
120
129
|
};
|
|
121
130
|
}
|
|
@@ -159,8 +168,7 @@ class ConsoleSessionDriver extends SessionDriverAbstract_1.SessionDriverAbstract
|
|
|
159
168
|
if (isHeader && data.action === SessionDriverAbstract_1.ActionEnum.End) {
|
|
160
169
|
return;
|
|
161
170
|
}
|
|
162
|
-
const endMessage =
|
|
163
|
-
(!hasProgress || data.action === SessionDriverAbstract_1.ActionEnum.End || isHeader);
|
|
171
|
+
const endMessage = this.tty && (!hasProgress || data.action === SessionDriverAbstract_1.ActionEnum.End || isHeader);
|
|
164
172
|
this.printMessage(message, endMessage);
|
|
165
173
|
if (endMessage)
|
|
166
174
|
process.stdout.write("\n");
|
|
@@ -64,13 +64,12 @@ export declare type ReadResultType = {
|
|
|
64
64
|
repositoryType: string;
|
|
65
65
|
error: string | null;
|
|
66
66
|
};
|
|
67
|
-
export declare
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
});
|
|
67
|
+
export declare type SessionDriverOptions = {
|
|
68
|
+
verbose?: boolean;
|
|
69
|
+
};
|
|
70
|
+
export declare abstract class SessionDriverAbstract<TOptions extends SessionDriverOptions = SessionDriverOptions> {
|
|
71
|
+
readonly options: TOptions;
|
|
72
|
+
constructor(options: TOptions);
|
|
74
73
|
onInit(): Promise<void>;
|
|
75
74
|
abstract onWrite(data: WriteDataType): Promise<void>;
|
|
76
75
|
onEnd(data?: Record<string, any>): Promise<void>;
|
package/cli.js
CHANGED
|
@@ -80,6 +80,8 @@ program.description(description);
|
|
|
80
80
|
program.usage("dtt");
|
|
81
81
|
program.option("-v,--verbose", "Verbose", (_, previous) => previous + 1, 0);
|
|
82
82
|
program.option("-c,--config <path>", "Config path", process.env["DATATRUCK_CONFIG"] ?? (cwd.endsWith(path_1.sep) ? cwd : `${cwd}${path_1.sep}`));
|
|
83
|
+
program.option("--progress <value>", "Progress type (auto, plain, tty)", "auto");
|
|
84
|
+
program.option("--progress-interval <ms>", "Progress interval");
|
|
83
85
|
program.option("-o,--output-format <format>", "Output format (json, pjson, yaml, table, custom=$, tpl=name)", "table");
|
|
84
86
|
makeCommand(CommandFactory_1.CommandEnum.config).alias("c");
|
|
85
87
|
makeCommand(CommandFactory_1.CommandEnum.init).alias("i");
|
package/config.schema.json
CHANGED
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"type": "object",
|
|
82
82
|
"properties": {
|
|
83
83
|
"type": {
|
|
84
|
-
"const": "
|
|
84
|
+
"const": "datatruck"
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
},
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"type": "object",
|
|
90
90
|
"properties": {
|
|
91
91
|
"config": {
|
|
92
|
-
"$ref": "#/definitions/
|
|
92
|
+
"$ref": "#/definitions/datatruck-repository"
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
},
|
|
@@ -248,7 +248,7 @@
|
|
|
248
248
|
"type": "object",
|
|
249
249
|
"properties": {
|
|
250
250
|
"type": {
|
|
251
|
-
"const": "
|
|
251
|
+
"const": "datatruck"
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
},
|
|
@@ -256,7 +256,7 @@
|
|
|
256
256
|
"type": "object",
|
|
257
257
|
"properties": {
|
|
258
258
|
"config": {
|
|
259
|
-
"$ref": "#/definitions/
|
|
259
|
+
"$ref": "#/definitions/datatruck-package-repository"
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
},
|
|
@@ -438,7 +438,7 @@
|
|
|
438
438
|
"additionalProperties": false,
|
|
439
439
|
"properties": {}
|
|
440
440
|
},
|
|
441
|
-
"
|
|
441
|
+
"datatruck-repository": {
|
|
442
442
|
"type": "object",
|
|
443
443
|
"required": [
|
|
444
444
|
"outPath"
|
|
@@ -453,7 +453,7 @@
|
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
455
|
},
|
|
456
|
-
"
|
|
456
|
+
"datatruck-package-repository": {
|
|
457
457
|
"type": "object",
|
|
458
458
|
"additionalProperties": false,
|
|
459
459
|
"properties": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datatruck/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"ajv": "^8.11.0",
|
|
6
6
|
"async": "^3.2.4",
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
"cli-table3": "^0.6.2",
|
|
9
9
|
"commander": "^9.4.0",
|
|
10
10
|
"dayjs": "^1.11.5",
|
|
11
|
+
"fast-folder-size": "^1.7.1",
|
|
11
12
|
"fast-glob": "^3.2.11",
|
|
12
13
|
"micromatch": "^4.0.5",
|
|
14
|
+
"pretty-bytes": "^5.6.0",
|
|
13
15
|
"sqlite": "^4.1.2",
|
|
14
16
|
"sqlite3": "^5.0.11"
|
|
15
17
|
},
|
package/util/ResticUtil.d.ts
CHANGED
|
@@ -10,13 +10,16 @@ export declare type RepositoryType = {
|
|
|
10
10
|
} & Omit<UriType, "password">;
|
|
11
11
|
export declare type BackupStreamType = {
|
|
12
12
|
message_type: "status";
|
|
13
|
-
seconds_elapsed
|
|
13
|
+
seconds_elapsed?: number;
|
|
14
14
|
percent_done: number;
|
|
15
|
-
total_files
|
|
15
|
+
total_files?: number;
|
|
16
16
|
files_done?: number;
|
|
17
17
|
total_bytes: number;
|
|
18
18
|
bytes_done?: number;
|
|
19
19
|
current_files?: string[];
|
|
20
|
+
} | {
|
|
21
|
+
message_type: "restore-status";
|
|
22
|
+
total_bytes: number;
|
|
20
23
|
} | {
|
|
21
24
|
message_type: "summary";
|
|
22
25
|
files_new: number;
|
|
@@ -95,6 +98,10 @@ export declare class ResticUtil {
|
|
|
95
98
|
restore(options: {
|
|
96
99
|
id: string;
|
|
97
100
|
target: string;
|
|
101
|
+
/**
|
|
102
|
+
* @default 30_000
|
|
103
|
+
*/
|
|
104
|
+
progressInterval?: number | false;
|
|
98
105
|
onStream?: (data: BackupStreamType) => Promise<void>;
|
|
99
106
|
}): Promise<ExecResultType>;
|
|
100
107
|
}
|
package/util/ResticUtil.js
CHANGED
|
@@ -29,7 +29,7 @@ class ResticUtil {
|
|
|
29
29
|
async exec(args, settings, options) {
|
|
30
30
|
return await (0, process_util_1.exec)("restic", args, {
|
|
31
31
|
stdio: ["ignore", "pipe", "pipe"],
|
|
32
|
-
env: { ...this.options.env },
|
|
32
|
+
env: { ...process.env, ...this.options.env },
|
|
33
33
|
cwd: options?.cwd,
|
|
34
34
|
}, {
|
|
35
35
|
stderr: { toExitCode: true },
|
|
@@ -40,7 +40,11 @@ class ResticUtil {
|
|
|
40
40
|
stderr: true,
|
|
41
41
|
colorize: true,
|
|
42
42
|
allToStderr: true,
|
|
43
|
-
envNames: [
|
|
43
|
+
envNames: [
|
|
44
|
+
"RESTIC_REPOSITORY",
|
|
45
|
+
"RESTIC_PASSWORD_FILE",
|
|
46
|
+
"RESTIC_PASSWORD",
|
|
47
|
+
],
|
|
44
48
|
}
|
|
45
49
|
: {},
|
|
46
50
|
...(settings ?? {}),
|
|
@@ -96,11 +100,12 @@ class ResticUtil {
|
|
|
96
100
|
return JSON.parse(result.stdout);
|
|
97
101
|
}
|
|
98
102
|
async checkBackupSetPathSupport() {
|
|
99
|
-
const result = await this.exec(["backup", "--set-path"], {
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
/*const result = await this.exec(["backup", "--set-path"], {
|
|
104
|
+
onExitCodeError: () => false,
|
|
105
|
+
stderr: { save: true },
|
|
102
106
|
});
|
|
103
|
-
return result.stderr.includes("flag needs an argument")
|
|
107
|
+
return result.stderr.includes("flag needs an argument");*/
|
|
108
|
+
return false;
|
|
104
109
|
}
|
|
105
110
|
async backup(options) {
|
|
106
111
|
const exec = async () => await this.exec([
|
|
@@ -174,20 +179,42 @@ class ResticUtil {
|
|
|
174
179
|
});
|
|
175
180
|
}
|
|
176
181
|
async restore(options) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
182
|
+
let progressTimeout;
|
|
183
|
+
const progressInterval = options.progressInterval ?? 30000;
|
|
184
|
+
async function progressRutine() {
|
|
185
|
+
try {
|
|
186
|
+
const total_bytes = await (0, fs_util_1.fastFolderSizeAsync)(options.target);
|
|
187
|
+
options.onStream?.({
|
|
188
|
+
message_type: "restore-status",
|
|
189
|
+
total_bytes,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
if (typeof progressInterval === "number")
|
|
194
|
+
progressTimeout = setTimeout(progressRutine, progressInterval);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (typeof progressInterval === "number")
|
|
198
|
+
progressRutine();
|
|
199
|
+
try {
|
|
200
|
+
return await this.exec(["restore", "--json", options.id, "--target", options.target], {
|
|
201
|
+
stderr: {
|
|
202
|
+
toExitCode: true,
|
|
203
|
+
},
|
|
204
|
+
stdout: {
|
|
205
|
+
...(options.onStream && {
|
|
206
|
+
onData: async (data) => {
|
|
207
|
+
if (data.startsWith("{") && data.endsWith("}")) {
|
|
208
|
+
await options.onStream?.(JSON.parse(data));
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
}),
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
clearTimeout(progressTimeout);
|
|
217
|
+
}
|
|
191
218
|
}
|
|
192
219
|
}
|
|
193
220
|
exports.ResticUtil = ResticUtil;
|
|
@@ -31,17 +31,17 @@ export declare const pkgPathParams: {
|
|
|
31
31
|
[name in "temp" | Exclude<keyof ResolvePackagePathParamsType, "path">]: string;
|
|
32
32
|
};
|
|
33
33
|
export declare const pkgIncludeParams: {
|
|
34
|
-
snapshotDate: string;
|
|
35
34
|
packageName: string;
|
|
36
35
|
temp: string;
|
|
37
36
|
snapshotId: string;
|
|
37
|
+
snapshotDate: string;
|
|
38
38
|
action: string;
|
|
39
39
|
};
|
|
40
40
|
export declare const pkgExcludeParams: {
|
|
41
|
-
snapshotDate: string;
|
|
42
41
|
packageName: string;
|
|
43
42
|
temp: string;
|
|
44
43
|
snapshotId: string;
|
|
44
|
+
snapshotDate: string;
|
|
45
45
|
action: string;
|
|
46
46
|
};
|
|
47
47
|
export declare const pkgRestorePathParams: {
|
|
@@ -52,32 +52,32 @@ export declare const dbNameParams: {
|
|
|
52
52
|
};
|
|
53
53
|
export declare const params: {
|
|
54
54
|
pkgPath: {
|
|
55
|
-
snapshotDate: string;
|
|
56
55
|
packageName: string;
|
|
57
56
|
temp: string;
|
|
58
57
|
snapshotId: string;
|
|
58
|
+
snapshotDate: string;
|
|
59
59
|
action: string;
|
|
60
60
|
};
|
|
61
61
|
pkgRestorePath: {
|
|
62
|
-
snapshotDate: string;
|
|
63
62
|
packageName: string;
|
|
64
63
|
path: string;
|
|
65
64
|
temp: string;
|
|
66
65
|
snapshotId: string;
|
|
66
|
+
snapshotDate: string;
|
|
67
67
|
action: string;
|
|
68
68
|
};
|
|
69
69
|
pkgInclude: {
|
|
70
|
-
snapshotDate: string;
|
|
71
70
|
packageName: string;
|
|
72
71
|
temp: string;
|
|
73
72
|
snapshotId: string;
|
|
73
|
+
snapshotDate: string;
|
|
74
74
|
action: string;
|
|
75
75
|
};
|
|
76
76
|
pkgExclude: {
|
|
77
|
-
snapshotDate: string;
|
|
78
77
|
packageName: string;
|
|
79
78
|
temp: string;
|
|
80
79
|
snapshotId: string;
|
|
80
|
+
snapshotDate: string;
|
|
81
81
|
action: string;
|
|
82
82
|
};
|
|
83
83
|
dbName: {
|
package/util/fs-util.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare function existsFile(path: string): Promise<boolean>;
|
|
|
23
23
|
export declare function parentTmpDir(): string;
|
|
24
24
|
export declare function sessionTmpDir(): string;
|
|
25
25
|
export declare function tmpDir(prefix: string, id?: string): string;
|
|
26
|
+
export declare function fastFolderSizeAsync(path: string): Promise<number>;
|
|
26
27
|
export declare function mkTmpDir(prefix: string, id?: string): Promise<string>;
|
|
27
28
|
export declare function readPartialFile(path: string, positions: [number, number?]): Promise<string>;
|
|
28
29
|
export declare function checkFile(path: string): Promise<boolean>;
|
package/util/fs-util.js
CHANGED
|
@@ -3,11 +3,12 @@ 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.cpy = exports.updateFileStats = exports.copyFileWithStreams = exports.writePathLists = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.tmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.existsFile = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.readdirIfExists = exports.writeJSONFile = exports.existsDir = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isDirEmpty = exports.isLocalDir = exports.isWSLSystem = void 0;
|
|
6
|
+
exports.cpy = exports.updateFileStats = exports.copyFileWithStreams = exports.writePathLists = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.checkDir = exports.checkFile = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = exports.tmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.existsFile = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.readdirIfExists = exports.writeJSONFile = exports.existsDir = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isDirEmpty = exports.isLocalDir = exports.isWSLSystem = void 0;
|
|
7
7
|
const globalData_1 = __importDefault(require("../globalData"));
|
|
8
8
|
const path_util_1 = require("./path-util");
|
|
9
9
|
const async_1 = require("async");
|
|
10
10
|
const crypto_1 = require("crypto");
|
|
11
|
+
const fast_folder_size_1 = __importDefault(require("fast-folder-size"));
|
|
11
12
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
12
13
|
const fs_1 = require("fs");
|
|
13
14
|
const fs_2 = require("fs");
|
|
@@ -17,6 +18,7 @@ const os_1 = require("os");
|
|
|
17
18
|
const path_1 = require("path");
|
|
18
19
|
const path_2 = require("path");
|
|
19
20
|
const readline_1 = require("readline");
|
|
21
|
+
const util_1 = require("util");
|
|
20
22
|
exports.isWSLSystem = (0, os_1.release)().includes("microsoft-standard-WSL");
|
|
21
23
|
function isLocalDir(path) {
|
|
22
24
|
return /^[\/\.]|([A-Z]:)/i.test(path);
|
|
@@ -130,6 +132,10 @@ function tmpDir(prefix, id) {
|
|
|
130
132
|
return (0, path_1.join)(sessionTmpDir(), `${prefix}-${id}`);
|
|
131
133
|
}
|
|
132
134
|
exports.tmpDir = tmpDir;
|
|
135
|
+
async function fastFolderSizeAsync(path) {
|
|
136
|
+
return (await (0, util_1.promisify)(fast_folder_size_1.default)(path)) || 0;
|
|
137
|
+
}
|
|
138
|
+
exports.fastFolderSizeAsync = fastFolderSizeAsync;
|
|
133
139
|
async function mkTmpDir(prefix, id) {
|
|
134
140
|
const path = tmpDir(prefix, id);
|
|
135
141
|
await (0, promises_1.mkdir)(path, { recursive: true });
|
package/util/process-util.js
CHANGED
|
@@ -34,7 +34,9 @@ async function exec(command, argv = [], options = null, settings = {}) {
|
|
|
34
34
|
return new Promise(async (resolve, reject) => {
|
|
35
35
|
if (log.exec) {
|
|
36
36
|
const logEnv = log.envNames?.reduce((env, key) => {
|
|
37
|
-
|
|
37
|
+
const value = options?.env?.[key];
|
|
38
|
+
if (typeof value !== "undefined")
|
|
39
|
+
env[key] = value;
|
|
38
40
|
return env;
|
|
39
41
|
}, {});
|
|
40
42
|
(0, cli_util_1.logExec)(command, pipe
|