@datatruck/cli 0.35.1 → 0.36.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/config.schema.json +25 -28
- package/lib/actions/BackupAction.js +1 -0
- package/lib/actions/CopyAction.js +1 -0
- package/lib/actions/SnapshotsAction.d.ts +1 -0
- package/lib/actions/SnapshotsAction.js +4 -1
- package/lib/commands/RestoreCommand.d.ts +1 -0
- package/lib/commands/SnapshotsCommand.d.ts +1 -0
- package/lib/commands/SnapshotsCommand.js +8 -0
- package/lib/repositories/DatatruckRepository.d.ts +3 -9
- package/lib/repositories/DatatruckRepository.js +7 -5
- package/lib/repositories/GitRepository.d.ts +3 -5
- package/lib/repositories/GitRepository.js +10 -8
- package/lib/repositories/RepositoryAbstract.d.ts +5 -1
- package/lib/repositories/RepositoryAbstract.js +1 -0
- package/lib/repositories/ResticRepository.d.ts +3 -4
- package/lib/repositories/ResticRepository.js +27 -17
- package/lib/utils/datatruck/cron-server.d.ts +1 -1
- package/lib/utils/datatruck/cron-server.js +10 -2
- package/package.json +1 -1
package/config.schema.json
CHANGED
|
@@ -2073,7 +2073,7 @@
|
|
|
2073
2073
|
"const": "prune"
|
|
2074
2074
|
},
|
|
2075
2075
|
"options": {
|
|
2076
|
-
"$ref": "#/definitions/PruneCommandOptions"
|
|
2076
|
+
"$ref": "#/definitions/Omit<PruneCommandOptions,\"confirm\">"
|
|
2077
2077
|
}
|
|
2078
2078
|
},
|
|
2079
2079
|
"required": [
|
|
@@ -2084,62 +2084,59 @@
|
|
|
2084
2084
|
}
|
|
2085
2085
|
]
|
|
2086
2086
|
},
|
|
2087
|
-
"PruneCommandOptions": {
|
|
2088
|
-
"additionalProperties": false,
|
|
2087
|
+
"Omit<PruneCommandOptions,\"confirm\">": {
|
|
2089
2088
|
"type": "object",
|
|
2090
2089
|
"properties": {
|
|
2091
|
-
"
|
|
2092
|
-
"type": "
|
|
2090
|
+
"repository": {
|
|
2091
|
+
"type": "string"
|
|
2093
2092
|
},
|
|
2094
|
-
"
|
|
2093
|
+
"repositoryType": {
|
|
2094
|
+
"type": "string"
|
|
2095
|
+
},
|
|
2096
|
+
"id": {
|
|
2097
|
+
"type": "string"
|
|
2098
|
+
},
|
|
2099
|
+
"groupBy": {
|
|
2100
|
+
"type": "string"
|
|
2101
|
+
},
|
|
2102
|
+
"dryRun": {
|
|
2103
|
+
"type": "boolean"
|
|
2104
|
+
},
|
|
2105
|
+
"keepDaily": {
|
|
2095
2106
|
"type": "number"
|
|
2096
2107
|
},
|
|
2097
2108
|
"keepHourly": {
|
|
2098
2109
|
"type": "number"
|
|
2099
2110
|
},
|
|
2100
|
-
"
|
|
2111
|
+
"keepMinutely": {
|
|
2101
2112
|
"type": "number"
|
|
2102
2113
|
},
|
|
2103
|
-
"
|
|
2114
|
+
"keepLast": {
|
|
2104
2115
|
"type": "number"
|
|
2105
2116
|
},
|
|
2106
2117
|
"keepMonthly": {
|
|
2107
2118
|
"type": "number"
|
|
2108
2119
|
},
|
|
2109
|
-
"
|
|
2120
|
+
"keepWeekly": {
|
|
2110
2121
|
"type": "number"
|
|
2111
2122
|
},
|
|
2112
|
-
"
|
|
2113
|
-
"type": "
|
|
2114
|
-
},
|
|
2115
|
-
"longId": {
|
|
2116
|
-
"type": "boolean"
|
|
2123
|
+
"keepYearly": {
|
|
2124
|
+
"type": "number"
|
|
2117
2125
|
},
|
|
2118
2126
|
"package": {
|
|
2119
2127
|
"type": "string"
|
|
2120
2128
|
},
|
|
2121
|
-
"repository": {
|
|
2122
|
-
"type": "string"
|
|
2123
|
-
},
|
|
2124
|
-
"repositoryType": {
|
|
2125
|
-
"type": "string"
|
|
2126
|
-
},
|
|
2127
2129
|
"tag": {
|
|
2128
2130
|
"type": "string"
|
|
2129
2131
|
},
|
|
2130
|
-
"
|
|
2131
|
-
"type": "string"
|
|
2132
|
-
},
|
|
2133
|
-
"dryRun": {
|
|
2132
|
+
"longId": {
|
|
2134
2133
|
"type": "boolean"
|
|
2135
2134
|
},
|
|
2136
2135
|
"showAll": {
|
|
2137
2136
|
"type": "boolean"
|
|
2138
|
-
},
|
|
2139
|
-
"confirm": {
|
|
2140
|
-
"type": "boolean"
|
|
2141
2137
|
}
|
|
2142
|
-
}
|
|
2138
|
+
},
|
|
2139
|
+
"additionalProperties": false
|
|
2143
2140
|
}
|
|
2144
2141
|
},
|
|
2145
2142
|
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
@@ -164,6 +164,7 @@ class CopyAction {
|
|
|
164
164
|
if (this.config.minFreeDiskSpace)
|
|
165
165
|
await mirrorRepo.ensureFreeDiskSpace(mirrorConfig.config, this.config.minFreeDiskSpace);
|
|
166
166
|
return await mirrorRepo.backup({
|
|
167
|
+
hostname: snapshot.hostname,
|
|
167
168
|
options: {
|
|
168
169
|
verbose: this.options.verbose,
|
|
169
170
|
tags: snapshot.tags,
|
|
@@ -4,6 +4,7 @@ import { IfRequireKeys } from "../utils/ts";
|
|
|
4
4
|
export type SnapshotGroupByType = keyof Pick<ExtendedSnapshot, "packageName" | "repositoryName" | "repositoryType">;
|
|
5
5
|
export type SnapshotsActionOptions = {
|
|
6
6
|
ids?: string[];
|
|
7
|
+
hostnames?: string[];
|
|
7
8
|
repositoryNames?: string[];
|
|
8
9
|
packageNames?: string[];
|
|
9
10
|
packageTaskNames?: string[];
|
|
@@ -16,6 +16,7 @@ class SnapshotsAction {
|
|
|
16
16
|
if (!sourceAction)
|
|
17
17
|
sourceAction = "snapshots";
|
|
18
18
|
let result = [];
|
|
19
|
+
const filterHost = (0, string_1.createPatternFilter)(this.options.hostnames);
|
|
19
20
|
const filterRepo = (0, string_1.createPatternFilter)(this.options.repositoryNames);
|
|
20
21
|
const filterRepoType = (0, string_1.createPatternFilter)(this.options.repositoryTypes);
|
|
21
22
|
for (const repoConfig of this.config.repositories) {
|
|
@@ -36,12 +37,14 @@ class SnapshotsAction {
|
|
|
36
37
|
packageNames,
|
|
37
38
|
},
|
|
38
39
|
});
|
|
39
|
-
|
|
40
|
+
let extentedItems = snapshots.map((ss) => ({
|
|
40
41
|
...ss,
|
|
41
42
|
shortId: ss.id.slice(0, 8),
|
|
42
43
|
repositoryName: repoConfig.name,
|
|
43
44
|
repositoryType: repoConfig.type,
|
|
44
45
|
}));
|
|
46
|
+
if (this.options.hostnames)
|
|
47
|
+
extentedItems = extentedItems.filter((s) => filterHost(s.hostname));
|
|
45
48
|
result.push(...extentedItems);
|
|
46
49
|
}
|
|
47
50
|
result = result.sort((a, b) => b.date.localeCompare(a.date));
|
|
@@ -4,6 +4,7 @@ import { If } from "../utils/ts";
|
|
|
4
4
|
import { CommandAbstract } from "./CommandAbstract";
|
|
5
5
|
export type SnapshotsCommandOptions<TResolved = false> = {
|
|
6
6
|
id?: If<TResolved, string[]>;
|
|
7
|
+
host?: If<TResolved, string[]>;
|
|
7
8
|
package?: If<TResolved, string[]>;
|
|
8
9
|
packageTask?: If<TResolved, string[]>;
|
|
9
10
|
packageConfig?: boolean;
|
|
@@ -30,6 +30,11 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
30
30
|
description: "Filter by identifiers",
|
|
31
31
|
parser: string_1.parseStringList,
|
|
32
32
|
},
|
|
33
|
+
host: {
|
|
34
|
+
option: "-h,--host <names>",
|
|
35
|
+
description: "Filter by hostnames",
|
|
36
|
+
parser: string_1.parseStringList,
|
|
37
|
+
},
|
|
33
38
|
last: {
|
|
34
39
|
option: "-l,--last <number>",
|
|
35
40
|
description: "Filter by last snapshots",
|
|
@@ -101,6 +106,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
101
106
|
const config = await ConfigAction_1.ConfigAction.fromGlobalOptions(this.globalOptions);
|
|
102
107
|
const snapshots = new SnapshotsAction_1.SnapshotsAction(config, {
|
|
103
108
|
ids: this.options.id,
|
|
109
|
+
hostnames: this.options.host,
|
|
104
110
|
packageNames: this.options.package,
|
|
105
111
|
packageTaskNames: this.options.packageTask,
|
|
106
112
|
packageConfig: this.options.packageConfig,
|
|
@@ -125,6 +131,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
125
131
|
headers: [
|
|
126
132
|
{ value: "Id.", width: (this.options.longId ? 32 : 8) + 2 },
|
|
127
133
|
{ value: "Date", width: 23 + 2 },
|
|
134
|
+
{ value: "Host" },
|
|
128
135
|
{ value: "Package" },
|
|
129
136
|
{ value: "Task" },
|
|
130
137
|
{ value: "Size" },
|
|
@@ -134,6 +141,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
134
141
|
rows: () => result.map((item) => [
|
|
135
142
|
this.options.longId ? item.id : item.id.slice(0, 8),
|
|
136
143
|
item.date.replace("T", " ").replace("Z", ""),
|
|
144
|
+
item.hostname,
|
|
137
145
|
item.packageName,
|
|
138
146
|
item.packageTaskName || "",
|
|
139
147
|
(0, bytes_1.formatBytes)(item.size),
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { CompressOptions } from "../utils/tar";
|
|
2
|
-
import { RepositoryAbstract, RepoBackupData, RepoInitData, RepoRestoreData, RepoFetchSnapshotsData, Snapshot, RepoPruneData, RepoCopyData } from "./RepositoryAbstract";
|
|
3
|
-
export type MetaData = {
|
|
4
|
-
id: string;
|
|
5
|
-
date: string;
|
|
6
|
-
package: string;
|
|
7
|
-
task: string | undefined;
|
|
8
|
-
tags: string[];
|
|
9
|
-
version: string;
|
|
2
|
+
import { RepositoryAbstract, RepoBackupData, RepoInitData, RepoRestoreData, RepoFetchSnapshotsData, Snapshot, RepoPruneData, RepoCopyData, SnapshotTagObject } from "./RepositoryAbstract";
|
|
3
|
+
export type MetaData = Omit<SnapshotTagObject, "shortId" | "size"> & {
|
|
10
4
|
size: number;
|
|
11
5
|
tarStats?: Record<string, {
|
|
12
6
|
files: number;
|
|
@@ -32,7 +26,7 @@ export type DatatruckPackageRepositoryConfig = {
|
|
|
32
26
|
export declare const datatruckRepositoryName = "datatruck";
|
|
33
27
|
export declare class DatatruckRepository extends RepositoryAbstract<DatatruckRepositoryConfig> {
|
|
34
28
|
static zipBasenameTpl: string;
|
|
35
|
-
static
|
|
29
|
+
static createSnapshotName(snapshot: {
|
|
36
30
|
id: string;
|
|
37
31
|
date: string;
|
|
38
32
|
}, pkg: {
|
|
@@ -20,7 +20,7 @@ const path_1 = require("path");
|
|
|
20
20
|
exports.datatruckRepositoryName = "datatruck";
|
|
21
21
|
class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
22
22
|
static zipBasenameTpl = `.*.dd.tar.gz`;
|
|
23
|
-
static
|
|
23
|
+
static createSnapshotName(snapshot, pkg) {
|
|
24
24
|
const date = snapshot.date.replace(/:/g, "-");
|
|
25
25
|
const pkgName = encodeURIComponent(pkg.name)
|
|
26
26
|
.replace(/%40/g, "@")
|
|
@@ -55,7 +55,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
55
55
|
}
|
|
56
56
|
async prune(data) {
|
|
57
57
|
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
58
|
-
const snapshotName = DatatruckRepository.
|
|
58
|
+
const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, {
|
|
59
59
|
name: data.snapshot.packageName,
|
|
60
60
|
});
|
|
61
61
|
if (data.options.verbose)
|
|
@@ -103,6 +103,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
103
103
|
packageName: meta.package,
|
|
104
104
|
packageTaskName: meta.task,
|
|
105
105
|
tags: meta.tags,
|
|
106
|
+
hostname: meta.hostname ?? "",
|
|
106
107
|
size: meta.size || 0,
|
|
107
108
|
});
|
|
108
109
|
}
|
|
@@ -110,7 +111,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
110
111
|
}
|
|
111
112
|
async backup(data) {
|
|
112
113
|
const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
113
|
-
const snapshotName = DatatruckRepository.
|
|
114
|
+
const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, data.package);
|
|
114
115
|
const outPath = fs.isLocal()
|
|
115
116
|
? fs.resolvePath(snapshotName)
|
|
116
117
|
: await (0, temp_1.mkTmpDir)(exports.datatruckRepositoryName, "repo", "backup", "fs-remote");
|
|
@@ -213,6 +214,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
213
214
|
const nodePkg = (0, fs_1.parsePackageFile)();
|
|
214
215
|
const meta = {
|
|
215
216
|
id: data.snapshot.id,
|
|
217
|
+
hostname: data.hostname,
|
|
216
218
|
date: data.snapshot.date,
|
|
217
219
|
tags: data.options.tags ?? [],
|
|
218
220
|
package: data.package.name,
|
|
@@ -231,7 +233,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
231
233
|
async copy(data) {
|
|
232
234
|
const sourceFs = (0, client_1.createFs)(this.config.backend, this.verbose);
|
|
233
235
|
const targetFs = (0, client_1.createFs)(data.mirrorRepositoryConfig.backend, this.verbose);
|
|
234
|
-
const snapshotName = DatatruckRepository.
|
|
236
|
+
const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, data.package);
|
|
235
237
|
if (data.options.verbose)
|
|
236
238
|
(0, cli_1.logExec)(`Copying backup files to ${data.mirrorRepositoryConfig.backend}`);
|
|
237
239
|
const tmpSnapshotName = `${snapshotName}_tmp`;
|
|
@@ -311,7 +313,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
311
313
|
});
|
|
312
314
|
if (!snapshot)
|
|
313
315
|
throw new error_1.AppError("Snapshot not found");
|
|
314
|
-
const snapshotName = DatatruckRepository.
|
|
316
|
+
const snapshotName = DatatruckRepository.createSnapshotName(snapshot, data.package);
|
|
315
317
|
const meta = await DatatruckRepository.parseMetaData(await fs.readFile(`${snapshotName}/meta.json`));
|
|
316
318
|
const progress = (0, fs_1.createProgress)({ onProgress: data.onProgress });
|
|
317
319
|
progress.update("Scanning files");
|
|
@@ -9,15 +9,13 @@ export declare class GitRepository extends RepositoryAbstract<GitRepositoryConfi
|
|
|
9
9
|
static refPrefix: string;
|
|
10
10
|
getSource(): string;
|
|
11
11
|
fetchDiskStats(config: GitRepositoryConfig): Promise<import("../utils/fs").DiskStats | undefined>;
|
|
12
|
-
static
|
|
13
|
-
static
|
|
12
|
+
static createSnapshotTagName(tag: Pick<SnapshotTagObject, SnapshotTagEnum.PACKAGE | SnapshotTagEnum.ID>): string;
|
|
13
|
+
static createSnapshotTags(tags: SnapshotTagObject): {
|
|
14
14
|
name: string;
|
|
15
15
|
message: string;
|
|
16
16
|
};
|
|
17
17
|
static isSnapshotTag(name: string): boolean;
|
|
18
|
-
static
|
|
19
|
-
tags: string[];
|
|
20
|
-
}) | null;
|
|
18
|
+
static parseSnapshotTags(name: string, message: string): SnapshotTagObject | null;
|
|
21
19
|
static buildBranchName(packageName: string): string;
|
|
22
20
|
init(data: RepoInitData): Promise<void>;
|
|
23
21
|
prune(data: RepoPruneData): Promise<void>;
|
|
@@ -24,19 +24,19 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
24
24
|
if ((0, fs_1.isLocalDir)(config.repo))
|
|
25
25
|
return await (0, fs_1.fetchDiskStats)(config.repo);
|
|
26
26
|
}
|
|
27
|
-
static
|
|
27
|
+
static createSnapshotTagName(tag) {
|
|
28
28
|
return `${GitRepository.refPrefix}/${tag.package}/${tag.id}`;
|
|
29
29
|
}
|
|
30
|
-
static
|
|
30
|
+
static createSnapshotTags(tags) {
|
|
31
31
|
return {
|
|
32
|
-
name: GitRepository.
|
|
33
|
-
message: JSON.stringify(
|
|
32
|
+
name: GitRepository.createSnapshotTagName(tags),
|
|
33
|
+
message: JSON.stringify(tags),
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
static isSnapshotTag(name) {
|
|
37
37
|
return name.startsWith(`${GitRepository.refPrefix}/`);
|
|
38
38
|
}
|
|
39
|
-
static
|
|
39
|
+
static parseSnapshotTags(name, message) {
|
|
40
40
|
if (GitRepository.isSnapshotTag(name))
|
|
41
41
|
return JSON.parse(message);
|
|
42
42
|
return null;
|
|
@@ -111,7 +111,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
111
111
|
return tags
|
|
112
112
|
.reduce((result, tag) => {
|
|
113
113
|
const parsedTag = tag.message
|
|
114
|
-
? GitRepository.
|
|
114
|
+
? GitRepository.parseSnapshotTags(tag.name, tag.message)
|
|
115
115
|
: null;
|
|
116
116
|
if (!parsedTag)
|
|
117
117
|
return result;
|
|
@@ -129,6 +129,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
129
129
|
packageName: parsedTag.package,
|
|
130
130
|
packageTaskName: parsedTag.task,
|
|
131
131
|
tags: parsedTag.tags,
|
|
132
|
+
hostname: parsedTag.hostname ?? "",
|
|
132
133
|
size: Number(parsedTag.size) || 0,
|
|
133
134
|
});
|
|
134
135
|
return result;
|
|
@@ -196,8 +197,9 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
196
197
|
const nodePkg = (0, fs_1.parsePackageFile)();
|
|
197
198
|
const size = (await (0, fs_1.fastFolderSizeAsync)(tmpPath)) -
|
|
198
199
|
(await (0, fs_1.fastFolderSizeAsync)((0, path_1.join)(tmpPath, ".git")));
|
|
199
|
-
const meta = GitRepository.
|
|
200
|
+
const meta = GitRepository.createSnapshotTags({
|
|
200
201
|
id: data.snapshot.id,
|
|
202
|
+
hostname: data.hostname,
|
|
201
203
|
shortId: data.snapshot.id.slice(0, 8),
|
|
202
204
|
tags: data.options.tags ?? [],
|
|
203
205
|
date: data.snapshot.date,
|
|
@@ -220,7 +222,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
220
222
|
}
|
|
221
223
|
async restore(data) {
|
|
222
224
|
const restorePath = data.snapshotPath;
|
|
223
|
-
const tagName = GitRepository.
|
|
225
|
+
const tagName = GitRepository.createSnapshotTagName({
|
|
224
226
|
id: data.snapshot.id,
|
|
225
227
|
package: data.package.name,
|
|
226
228
|
});
|
|
@@ -13,6 +13,7 @@ export type Snapshot = PreSnapshot & {
|
|
|
13
13
|
packageName: string;
|
|
14
14
|
packageTaskName: string | undefined;
|
|
15
15
|
tags: string[];
|
|
16
|
+
hostname: string;
|
|
16
17
|
size: number;
|
|
17
18
|
};
|
|
18
19
|
export type RepoInitData = {
|
|
@@ -33,6 +34,7 @@ export type RepoCopyData<TRepositoryConfig> = {
|
|
|
33
34
|
export type RepoBackupData<TPackageConfig> = {
|
|
34
35
|
options: BackupActionOptions;
|
|
35
36
|
snapshot: PreSnapshot;
|
|
37
|
+
hostname: string;
|
|
36
38
|
package: Omit<PackageConfig, "path"> & {
|
|
37
39
|
path: string;
|
|
38
40
|
};
|
|
@@ -61,7 +63,8 @@ export declare enum SnapshotTagEnum {
|
|
|
61
63
|
TASK = "task",
|
|
62
64
|
TAGS = "tags",
|
|
63
65
|
VERSION = "version",
|
|
64
|
-
SIZE = "size"
|
|
66
|
+
SIZE = "size",
|
|
67
|
+
HOSTNAME = "hostname"
|
|
65
68
|
}
|
|
66
69
|
export type SnapshotTagObject = {
|
|
67
70
|
[SnapshotTagEnum.ID]: string;
|
|
@@ -72,6 +75,7 @@ export type SnapshotTagObject = {
|
|
|
72
75
|
[SnapshotTagEnum.TAGS]: string[];
|
|
73
76
|
[SnapshotTagEnum.VERSION]: string;
|
|
74
77
|
[SnapshotTagEnum.SIZE]: string;
|
|
78
|
+
[SnapshotTagEnum.HOSTNAME]: string;
|
|
75
79
|
};
|
|
76
80
|
export declare abstract class RepositoryAbstract<TConfig> {
|
|
77
81
|
readonly repository: RepositoryConfig;
|
|
@@ -12,6 +12,7 @@ var SnapshotTagEnum;
|
|
|
12
12
|
SnapshotTagEnum["TAGS"] = "tags";
|
|
13
13
|
SnapshotTagEnum["VERSION"] = "version";
|
|
14
14
|
SnapshotTagEnum["SIZE"] = "size";
|
|
15
|
+
SnapshotTagEnum["HOSTNAME"] = "hostname";
|
|
15
16
|
})(SnapshotTagEnum || (exports.SnapshotTagEnum = SnapshotTagEnum = {}));
|
|
16
17
|
class RepositoryAbstract {
|
|
17
18
|
repository;
|
|
@@ -20,14 +20,13 @@ export declare class ResticRepository extends RepositoryAbstract<ResticRepositor
|
|
|
20
20
|
RESTIC_PASSWORD_FILE?: string | undefined;
|
|
21
21
|
RESTIC_REPOSITORY: string;
|
|
22
22
|
}>;
|
|
23
|
-
static
|
|
23
|
+
static createSnapshotTag(name: SnapshotTagEnum, value: string): string;
|
|
24
|
+
static createSnapshotTags(object: Omit<SnapshotTagObject, "size">): string[];
|
|
24
25
|
static parseSnapshotTag(tag: string): {
|
|
25
26
|
name: SnapshotTagEnum;
|
|
26
27
|
value: string;
|
|
27
28
|
} | null;
|
|
28
|
-
static parseSnapshotTags(tags: string[]): SnapshotTagObject
|
|
29
|
-
tags: string[];
|
|
30
|
-
};
|
|
29
|
+
static parseSnapshotTags(tags: string[]): SnapshotTagObject;
|
|
31
30
|
getSource(): string;
|
|
32
31
|
fetchDiskStats(config: ResticRepositoryConfig): Promise<import("../utils/fs").DiskStats | undefined>;
|
|
33
32
|
init(data: RepoInitData): Promise<void>;
|
|
@@ -31,9 +31,21 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
31
31
|
RESTIC_REPOSITORY: await restic_1.Restic.formatRepository(this.config.repository),
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
static
|
|
34
|
+
static createSnapshotTag(name, value) {
|
|
35
35
|
return `${ResticRepository.refPrefix}${name}:${value}`;
|
|
36
36
|
}
|
|
37
|
+
static createSnapshotTags(object) {
|
|
38
|
+
const { tags: inTags, ...otherTags } = object;
|
|
39
|
+
const tags = [...inTags];
|
|
40
|
+
for (const key in otherTags) {
|
|
41
|
+
const value = object[key];
|
|
42
|
+
if (value !== undefined) {
|
|
43
|
+
const tag = ResticRepository.createSnapshotTag(key, value);
|
|
44
|
+
tags.push(tag);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return tags;
|
|
48
|
+
}
|
|
37
49
|
static parseSnapshotTag(tag) {
|
|
38
50
|
for (const metaName in RepositoryAbstract_1.SnapshotTagEnum) {
|
|
39
51
|
const name = RepositoryAbstract_1.SnapshotTagEnum[metaName];
|
|
@@ -86,7 +98,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
86
98
|
const result = await restic.snapshots({
|
|
87
99
|
json: true,
|
|
88
100
|
tags: [
|
|
89
|
-
...(data.options.ids?.map((id) => ResticRepository.
|
|
101
|
+
...(data.options.ids?.map((id) => ResticRepository.createSnapshotTag(id.length === 8 ? RepositoryAbstract_1.SnapshotTagEnum.SHORT_ID : RepositoryAbstract_1.SnapshotTagEnum.ID, id)) ?? []),
|
|
90
102
|
],
|
|
91
103
|
});
|
|
92
104
|
const filterPkg = (0, config_1.createPkgFilter)(data.options.packageNames);
|
|
@@ -109,6 +121,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
109
121
|
date: tag.date,
|
|
110
122
|
id: tag.id,
|
|
111
123
|
tags: itemTags,
|
|
124
|
+
hostname: tag.hostname ?? "",
|
|
112
125
|
size: Number(tag.size) || 0,
|
|
113
126
|
});
|
|
114
127
|
return items;
|
|
@@ -176,7 +189,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
176
189
|
}
|
|
177
190
|
if (data.options.tags?.some((tag) => tag.startsWith(ResticRepository.refPrefix)))
|
|
178
191
|
throw new error_1.AppError(`Tag prefix is not allowed`);
|
|
179
|
-
const packageTag = ResticRepository.
|
|
192
|
+
const packageTag = ResticRepository.createSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.PACKAGE, data.package.name);
|
|
180
193
|
data.onProgress({
|
|
181
194
|
relative: {
|
|
182
195
|
description: "Fetching last snapshot",
|
|
@@ -204,19 +217,16 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
204
217
|
allowEmptySnapshot: true,
|
|
205
218
|
excludeFile: gitignorePath ? [gitignorePath] : undefined,
|
|
206
219
|
parent: lastSnapshot?.id,
|
|
207
|
-
tags:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
: []),
|
|
218
|
-
...(data.options.tags ?? []),
|
|
219
|
-
],
|
|
220
|
+
tags: ResticRepository.createSnapshotTags({
|
|
221
|
+
id: data.snapshot.id,
|
|
222
|
+
hostname: data.hostname,
|
|
223
|
+
shortId: data.snapshot.id.slice(0, 8),
|
|
224
|
+
date: data.snapshot.date,
|
|
225
|
+
version: nodePkg.version,
|
|
226
|
+
package: data.package.name,
|
|
227
|
+
task: data.package.task?.name,
|
|
228
|
+
tags: data.options.tags || [],
|
|
229
|
+
}),
|
|
220
230
|
createEmptyDir: async () => await (0, temp_1.mkTmpDir)(exports.resticRepositoryName, "repo", "backup", "empty-dir"),
|
|
221
231
|
onStream: async (streamData) => {
|
|
222
232
|
if (streamData.message_type === "status") {
|
|
@@ -254,7 +264,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
254
264
|
throw new error_1.AppError(`Restic snapshot id is is not defined`);
|
|
255
265
|
if (typeof resticTotalBytes !== "number")
|
|
256
266
|
throw new error_1.AppError(`Restic snapshot total bytes is not defined`);
|
|
257
|
-
const sizeTag = ResticRepository.
|
|
267
|
+
const sizeTag = ResticRepository.createSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.SIZE, resticTotalBytes.toString());
|
|
258
268
|
await restic.exec(["tag", "--add", sizeTag, resticSnapshotId]);
|
|
259
269
|
data.onProgress({
|
|
260
270
|
absolute: {
|
|
@@ -31,9 +31,17 @@ function createCronServer(options, config) {
|
|
|
31
31
|
try {
|
|
32
32
|
const Command = command_1.datatruckCommandMap[action.name];
|
|
33
33
|
const command = new Command({ config: { packages: [], repositories: [] } }, {});
|
|
34
|
-
const cliOptions = (0, cli_1.stringifyOptions)(command.optionsConfig(), action.
|
|
34
|
+
const cliOptions = (0, cli_1.stringifyOptions)(command.optionsConfig(), action.name === "prune"
|
|
35
|
+
? ({ ...action.options, confirm: true })
|
|
36
|
+
: action.options);
|
|
35
37
|
const [node, bin] = process.argv;
|
|
36
|
-
await async_process_1.AsyncProcess.exec(node, [
|
|
38
|
+
await async_process_1.AsyncProcess.exec(node, [
|
|
39
|
+
process.env.pm_exec_path ?? bin,
|
|
40
|
+
"-c",
|
|
41
|
+
config.configPath,
|
|
42
|
+
action.name,
|
|
43
|
+
...cliOptions,
|
|
44
|
+
], { $log: config.verbose });
|
|
37
45
|
if (config.log)
|
|
38
46
|
console.info(`< [job] ${index} - ${action.name}`);
|
|
39
47
|
}
|