@datatruck/cli 0.16.0 → 0.16.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 +10 -3
- package/Action/BackupAction.js +34 -30
- package/Action/RestoreAction.d.ts +2 -2
- package/Action/RestoreAction.js +4 -4
- package/Repository/DatatruckRepository.js +20 -17
- package/package.json +1 -1
- package/util/zip-util.js +18 -16
package/Action/BackupAction.d.ts
CHANGED
|
@@ -23,10 +23,17 @@ export declare class BackupAction<TRequired extends boolean = true> {
|
|
|
23
23
|
protected repoErrors: Record<string, Error[]>;
|
|
24
24
|
constructor(config: ConfigType, options?: IfRequireKeys<TRequired, BackupActionOptionsType>);
|
|
25
25
|
protected init(session: BackupSessionManager): Promise<[SnapshotType, PackageConfigType[]]>;
|
|
26
|
-
protected
|
|
27
|
-
protected
|
|
28
|
-
protected
|
|
26
|
+
protected task(session: BackupSessionManager, pkg: PackageConfigType, task: TaskConfigType, snapshot: SnapshotType, targetPath: string | undefined): Promise<boolean>;
|
|
27
|
+
protected backup(session: BackupSessionManager, pkg: PackageConfigType, repo: RepositoryConfigType, snapshot: SnapshotType, targetPath: string | undefined): Promise<boolean>;
|
|
28
|
+
protected copyBackup(session: BackupSessionManager, pkg: PackageConfigType, repo: RepositoryConfigType, mirrorRepo: RepositoryConfigType, snapshot: SnapshotType): Promise<boolean>;
|
|
29
29
|
protected getError(pkg: PackageConfigType): AppError | null;
|
|
30
|
+
protected splitRepositories(repositoryNames: string[]): {
|
|
31
|
+
repoNames: string[];
|
|
32
|
+
mirrors: {
|
|
33
|
+
sourceName: string;
|
|
34
|
+
name: string;
|
|
35
|
+
}[];
|
|
36
|
+
};
|
|
30
37
|
exec(session: BackupSessionManager): Promise<{
|
|
31
38
|
total: number;
|
|
32
39
|
errors: number;
|
package/Action/BackupAction.js
CHANGED
|
@@ -53,7 +53,7 @@ class BackupAction {
|
|
|
53
53
|
}
|
|
54
54
|
return [snapshot, packages];
|
|
55
55
|
}
|
|
56
|
-
async
|
|
56
|
+
async task(session, pkg, task, snapshot, targetPath) {
|
|
57
57
|
const taskId = session.findTaskId({
|
|
58
58
|
packageName: pkg.name,
|
|
59
59
|
taskName: task.name,
|
|
@@ -94,7 +94,7 @@ class BackupAction {
|
|
|
94
94
|
});
|
|
95
95
|
return error ? false : true;
|
|
96
96
|
}
|
|
97
|
-
async
|
|
97
|
+
async backup(session, pkg, repo, snapshot, targetPath) {
|
|
98
98
|
const repositoryId = session.findRepositoryId({
|
|
99
99
|
packageName: pkg.name,
|
|
100
100
|
repositoryName: repo.name,
|
|
@@ -136,7 +136,7 @@ class BackupAction {
|
|
|
136
136
|
});
|
|
137
137
|
return error ? false : true;
|
|
138
138
|
}
|
|
139
|
-
async
|
|
139
|
+
async copyBackup(session, pkg, repo, mirrorRepo, snapshot) {
|
|
140
140
|
const repositoryId = session.findRepositoryId({
|
|
141
141
|
packageName: pkg.name,
|
|
142
142
|
repositoryName: mirrorRepo.name,
|
|
@@ -192,12 +192,33 @@ class BackupAction {
|
|
|
192
192
|
return null;
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
+
splitRepositories(repositoryNames) {
|
|
196
|
+
const mirrorRepoMap = {};
|
|
197
|
+
const allMirrorRepoNames = [];
|
|
198
|
+
const repoNames = repositoryNames ?? [];
|
|
199
|
+
for (const repoName of repoNames) {
|
|
200
|
+
const repo = (0, config_util_1.findRepositoryOrFail)(this.config, repoName);
|
|
201
|
+
if (repo.mirrorRepoNames)
|
|
202
|
+
mirrorRepoMap[repoName] = repo.mirrorRepoNames.filter((mirrorRepoName) => {
|
|
203
|
+
allMirrorRepoNames.push(mirrorRepoName);
|
|
204
|
+
return repoNames.includes(mirrorRepoName);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
repoNames: repoNames.filter((v) => !allMirrorRepoNames.includes(v)),
|
|
209
|
+
mirrors: repoNames.flatMap((sourceName) => {
|
|
210
|
+
const mirrorNames = mirrorRepoMap[sourceName] || [];
|
|
211
|
+
return mirrorNames.map((name) => ({
|
|
212
|
+
sourceName,
|
|
213
|
+
name,
|
|
214
|
+
}));
|
|
215
|
+
}),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
195
218
|
async exec(session) {
|
|
196
219
|
const [snapshot, packages] = await this.init(session);
|
|
197
|
-
let total = 0;
|
|
198
220
|
let errors = 0;
|
|
199
221
|
for (const pkg of packages) {
|
|
200
|
-
total++;
|
|
201
222
|
const id = session.findId({
|
|
202
223
|
packageName: pkg.name,
|
|
203
224
|
});
|
|
@@ -212,34 +233,17 @@ class BackupAction {
|
|
|
212
233
|
package: pkg,
|
|
213
234
|
snapshot,
|
|
214
235
|
});
|
|
215
|
-
await this.
|
|
236
|
+
await this.task(session, pkg, pkg.task, snapshot, (targetPath = result?.targetPath));
|
|
216
237
|
}
|
|
217
|
-
const
|
|
218
|
-
const allMirrorRepoNames = [];
|
|
219
|
-
const repoNames = pkg.repositoryNames ?? [];
|
|
238
|
+
const { repoNames, mirrors } = this.splitRepositories(pkg.repositoryNames ?? []);
|
|
220
239
|
for (const repoName of repoNames) {
|
|
221
240
|
const repo = (0, config_util_1.findRepositoryOrFail)(this.config, repoName);
|
|
222
|
-
|
|
223
|
-
mirrorRepoMap[repoName] = repo.mirrorRepoNames.filter((mirrorRepoName) => {
|
|
224
|
-
allMirrorRepoNames.push(mirrorRepoName);
|
|
225
|
-
return repoNames.includes(mirrorRepoName);
|
|
226
|
-
});
|
|
241
|
+
await this.backup(session, pkg, repo, snapshot, targetPath);
|
|
227
242
|
}
|
|
228
|
-
for (const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
await this.execRepository(session, pkg, repo, snapshot, targetPath);
|
|
233
|
-
}
|
|
234
|
-
for (const repoName of repoNames) {
|
|
235
|
-
const repo = (0, config_util_1.findRepositoryOrFail)(this.config, repoName);
|
|
236
|
-
const mirrorRepoNames = mirrorRepoMap[repoName];
|
|
237
|
-
if (mirrorRepoNames) {
|
|
238
|
-
for (const mirrorRepoName of mirrorRepoNames) {
|
|
239
|
-
const mirrorRepo = (0, config_util_1.findRepositoryOrFail)(this.config, mirrorRepoName);
|
|
240
|
-
await this.execCopyRepository(session, pkg, repo, mirrorRepo, snapshot);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
+
for (const mirror of mirrors) {
|
|
244
|
+
const repo = (0, config_util_1.findRepositoryOrFail)(this.config, mirror.sourceName);
|
|
245
|
+
const mirrorRepo = (0, config_util_1.findRepositoryOrFail)(this.config, mirror.name);
|
|
246
|
+
await this.copyBackup(session, pkg, repo, mirrorRepo, snapshot);
|
|
243
247
|
}
|
|
244
248
|
const error = this.getError(pkg);
|
|
245
249
|
if (error)
|
|
@@ -253,7 +257,7 @@ class BackupAction {
|
|
|
253
257
|
snapshotId: snapshot.id.slice(0, 8),
|
|
254
258
|
});
|
|
255
259
|
return {
|
|
256
|
-
total:
|
|
260
|
+
total: packages.length,
|
|
257
261
|
errors: errors,
|
|
258
262
|
};
|
|
259
263
|
}
|
|
@@ -30,8 +30,8 @@ export declare class RestoreAction<TRequired extends boolean = true> {
|
|
|
30
30
|
protected init(session: RestoreSessionManager, snapshotId: string, snapshots: SnapshotAndConfigType[]): Promise<void>;
|
|
31
31
|
protected findSnapshots(): Promise<SnapshotType[]>;
|
|
32
32
|
protected groupSnapshots(snapshots: SnapshotType[]): SnapshotType[];
|
|
33
|
-
protected
|
|
34
|
-
protected
|
|
33
|
+
protected task(session: RestoreSessionManager, pkg: PackageConfigType, task: TaskConfigType, snapshot: SnapshotType, targetPath: string | undefined): Promise<boolean>;
|
|
34
|
+
protected restore(session: RestoreSessionManager, pkg: PackageConfigType, repo: RepositoryConfigType, snapshot: SnapshotType, targetPath: string | undefined): Promise<boolean>;
|
|
35
35
|
protected getError(pkg: PackageConfigType): AppError | null;
|
|
36
36
|
exec(session: RestoreSessionManager): Promise<boolean>;
|
|
37
37
|
}
|
package/Action/RestoreAction.js
CHANGED
|
@@ -88,7 +88,7 @@ class RestoreAction {
|
|
|
88
88
|
return true;
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
|
-
async
|
|
91
|
+
async task(session, pkg, task, snapshot, targetPath) {
|
|
92
92
|
const taskId = session.findTaskId({
|
|
93
93
|
packageName: pkg.name,
|
|
94
94
|
taskName: task.name,
|
|
@@ -131,7 +131,7 @@ class RestoreAction {
|
|
|
131
131
|
});
|
|
132
132
|
return error ? false : true;
|
|
133
133
|
}
|
|
134
|
-
async
|
|
134
|
+
async restore(session, pkg, repo, snapshot, targetPath) {
|
|
135
135
|
const repositoryId = session.findRepositoryId({
|
|
136
136
|
packageName: pkg.name,
|
|
137
137
|
repositoryName: repo.name,
|
|
@@ -232,9 +232,9 @@ class RestoreAction {
|
|
|
232
232
|
});
|
|
233
233
|
targetPath = result?.targetPath;
|
|
234
234
|
}
|
|
235
|
-
await this.
|
|
235
|
+
await this.restore(session, pkg, repo, snapshot, targetPath);
|
|
236
236
|
if (pkg.task)
|
|
237
|
-
await this.
|
|
237
|
+
await this.task(session, pkg, pkg.task, snapshot, targetPath);
|
|
238
238
|
const error = this.getError(pkg);
|
|
239
239
|
await session.end({
|
|
240
240
|
id,
|
|
@@ -123,30 +123,29 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
123
123
|
object.current += data.current;
|
|
124
124
|
}
|
|
125
125
|
},
|
|
126
|
+
updateProgress: async (end) => {
|
|
127
|
+
const currentTime = perf_hooks_1.performance.now();
|
|
128
|
+
const diff = currentTime - lastTime;
|
|
129
|
+
if (end || diff > 1000) {
|
|
130
|
+
await options.onProgress({
|
|
131
|
+
relative: {
|
|
132
|
+
description: end ? "Scanned files" : "Scanning files",
|
|
133
|
+
payload: object.total.toString(),
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
lastTime = currentTime;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
126
139
|
start: async (cb) => {
|
|
127
140
|
for await (const entry of (0, fs_util_1.pathIterator)(stream)) {
|
|
128
141
|
if (!options.disableCounting)
|
|
129
142
|
object.total++;
|
|
130
|
-
|
|
131
|
-
const diff = currentTime - lastTime;
|
|
132
|
-
if (diff > 1000) {
|
|
133
|
-
await options.onProgress({
|
|
134
|
-
relative: {
|
|
135
|
-
description: "Scanning files",
|
|
136
|
-
payload: object.total.toString(),
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
lastTime = currentTime;
|
|
140
|
-
}
|
|
143
|
+
await object.updateProgress();
|
|
141
144
|
if (cb)
|
|
142
145
|
await cb(entry);
|
|
143
146
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
description: "Scanned files",
|
|
147
|
-
payload: object.total.toString(),
|
|
148
|
-
},
|
|
149
|
-
});
|
|
147
|
+
if (!options.disableEndProgress)
|
|
148
|
+
await object.updateProgress(true);
|
|
150
149
|
},
|
|
151
150
|
};
|
|
152
151
|
await options.onProgress({
|
|
@@ -439,6 +438,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
439
438
|
cwd: sourcePath,
|
|
440
439
|
},
|
|
441
440
|
onProgress: data.onProgress,
|
|
441
|
+
disableEndProgress: true,
|
|
442
442
|
});
|
|
443
443
|
await scanner.start();
|
|
444
444
|
const it = await (0, promises_1.opendir)(sourcePath);
|
|
@@ -446,6 +446,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
446
446
|
const path = (0, path_1.join)(sourcePath, dirent.name);
|
|
447
447
|
if (dirent.name === "permissions.txt") {
|
|
448
448
|
scanner.total++;
|
|
449
|
+
await scanner.updateProgress();
|
|
449
450
|
}
|
|
450
451
|
else if (dirent.name.endsWith(".zip")) {
|
|
451
452
|
await (0, zip_util_1.listZip)({
|
|
@@ -455,10 +456,12 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
|
|
|
455
456
|
const isDir = item.Folder === "+";
|
|
456
457
|
if (!isDir)
|
|
457
458
|
scanner.total++;
|
|
459
|
+
await scanner.updateProgress();
|
|
458
460
|
},
|
|
459
461
|
});
|
|
460
462
|
}
|
|
461
463
|
}
|
|
464
|
+
await scanner.updateProgress(true);
|
|
462
465
|
if (data.options.verbose)
|
|
463
466
|
(0, cli_util_1.logExec)(`Copying files to ${restorePath}`);
|
|
464
467
|
await (0, fs_util_1.cpy)({
|
package/package.json
CHANGED
package/util/zip-util.js
CHANGED
|
@@ -173,9 +173,9 @@ async function zip(data) {
|
|
|
173
173
|
exports.zip = zip;
|
|
174
174
|
function parseUnzipLine(line) {
|
|
175
175
|
let matches = null;
|
|
176
|
-
if ((matches = /^\s*(
|
|
177
|
-
const progress = Number(matches[
|
|
178
|
-
const files = Number(matches[2]);
|
|
176
|
+
if ((matches = /^\s*(?<percent>\d+)%(?: (?<files>\d+))? \-/.exec(line))) {
|
|
177
|
+
const progress = Number(matches.groups["percent"]);
|
|
178
|
+
const files = matches.groups["files"] ? Number(matches[2]) : 1;
|
|
179
179
|
const path = line.slice(line.indexOf("-") + 1).trim();
|
|
180
180
|
return {
|
|
181
181
|
type: "progress",
|
|
@@ -204,20 +204,22 @@ async function unzip(data) {
|
|
|
204
204
|
stderr: { toExitCode: true },
|
|
205
205
|
stdout: {
|
|
206
206
|
...((data.onStream || data.onProgress) && {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
if (stream
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
207
|
+
onData: async (chunk) => {
|
|
208
|
+
const lines = chunk.replaceAll("\b", "").split(/\r?\n/);
|
|
209
|
+
for (const line of lines) {
|
|
210
|
+
const stream = parseUnzipLine(line);
|
|
211
|
+
if (stream) {
|
|
212
|
+
if (stream.type === "progress") {
|
|
213
|
+
const current = Math.max(0, stream.data.files - 1);
|
|
214
|
+
summary.files = stream.data.files;
|
|
215
|
+
await data.onProgress?.({
|
|
216
|
+
current,
|
|
217
|
+
percent: stream.data.percent,
|
|
218
|
+
path: stream.data.path,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
await data.onStream?.(stream);
|
|
219
222
|
}
|
|
220
|
-
await data.onStream?.(stream);
|
|
221
223
|
}
|
|
222
224
|
},
|
|
223
225
|
}),
|