@webtypen/webframez-core 0.3.47 → 0.3.49
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/README.md +5 -1
- package/dist/Api/ApiFunctionUtils.d.ts +28 -55
- package/dist/Api/ApiFunctionUtils.js +10 -29
- package/dist/Backup/BackupManager.d.ts +3 -0
- package/dist/Backup/BackupManager.js +45 -23
- package/dist/Backup/BackupTypes.d.ts +4 -0
- package/dist/Backup/Jobs/BackupRunJob.js +1 -0
- package/dist/Backup/Utils/ZipWriter.d.ts +10 -0
- package/dist/Backup/Utils/ZipWriter.js +50 -1
- package/dist/Commands/BackupRunCommand.js +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -617,6 +617,8 @@ export default {
|
|
|
617
617
|
outputDir: "storage/backups",
|
|
618
618
|
filename: "{key}_{date}_{time}",
|
|
619
619
|
zip: true,
|
|
620
|
+
zipDriver: "auto",
|
|
621
|
+
zipCompressionLevel: 6,
|
|
620
622
|
cleanupWorkDir: true,
|
|
621
623
|
retention: {
|
|
622
624
|
keepLast: 10,
|
|
@@ -665,10 +667,12 @@ export default {
|
|
|
665
667
|
|
|
666
668
|
Built-in backup commands:
|
|
667
669
|
- `backup:list`
|
|
668
|
-
- `backup:run <key> [--dry-run] [--channel=local]`
|
|
670
|
+
- `backup:run <key> [--dry-run] [--channel=local] [--silent]`
|
|
669
671
|
- `backup:queue <key> [--worker=worker_1] [--priority=10]`
|
|
670
672
|
- `backup:cleanup <key> [--channel=local] [--dry-run]`
|
|
671
673
|
|
|
674
|
+
ZIP artifacts use the system `zip` binary by default when available and fall back to the built-in Node.js ZIP writer. Set `zipDriver: "system"` to require system zip, `zipDriver: "node"` to force the built-in writer, or `zipDriver: "auto"` for fallback behavior. `zipCompressionLevel` accepts `0` through `9`.
|
|
675
|
+
|
|
672
676
|
Remote outputs are optional packages and must be registered by the application before the backup config is used:
|
|
673
677
|
|
|
674
678
|
```ts
|
|
@@ -54,77 +54,48 @@ export declare function apiFunctionParamToJsonSchema(definition: ApiFunctionPara
|
|
|
54
54
|
type: string;
|
|
55
55
|
pattern?: undefined;
|
|
56
56
|
items?: undefined;
|
|
57
|
-
|
|
57
|
+
additionalProperties?: undefined;
|
|
58
|
+
required?: undefined;
|
|
59
|
+
properties?: undefined;
|
|
58
60
|
"x-webframez-type"?: undefined;
|
|
59
61
|
enum?: undefined;
|
|
60
62
|
} | {
|
|
61
63
|
type: string;
|
|
62
64
|
pattern: string;
|
|
63
65
|
items?: undefined;
|
|
64
|
-
|
|
66
|
+
additionalProperties?: undefined;
|
|
67
|
+
required?: undefined;
|
|
68
|
+
properties?: undefined;
|
|
65
69
|
"x-webframez-type"?: undefined;
|
|
66
70
|
enum?: undefined;
|
|
67
71
|
} | {
|
|
68
72
|
type: string;
|
|
69
73
|
items: {};
|
|
70
74
|
pattern?: undefined;
|
|
71
|
-
|
|
75
|
+
additionalProperties?: undefined;
|
|
76
|
+
required?: undefined;
|
|
77
|
+
properties?: undefined;
|
|
72
78
|
"x-webframez-type"?: undefined;
|
|
73
79
|
enum?: undefined;
|
|
74
80
|
} | {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
};
|
|
85
|
-
mime_type: {
|
|
86
|
-
type: string;
|
|
87
|
-
};
|
|
88
|
-
file_name: {
|
|
89
|
-
type: string;
|
|
90
|
-
};
|
|
91
|
-
url: {
|
|
92
|
-
type: string;
|
|
93
|
-
};
|
|
94
|
-
download_link: {
|
|
95
|
-
type: string;
|
|
96
|
-
};
|
|
97
|
-
file_url: {
|
|
98
|
-
type: string;
|
|
99
|
-
};
|
|
100
|
-
content_base64: {
|
|
101
|
-
type: string;
|
|
102
|
-
};
|
|
103
|
-
data_url: {
|
|
104
|
-
type: string;
|
|
105
|
-
};
|
|
106
|
-
id: {
|
|
107
|
-
type: string;
|
|
108
|
-
};
|
|
109
|
-
filename: {
|
|
110
|
-
type: string;
|
|
111
|
-
};
|
|
112
|
-
name: {
|
|
113
|
-
type: string;
|
|
114
|
-
};
|
|
115
|
-
mime: {
|
|
116
|
-
type: string;
|
|
117
|
-
};
|
|
81
|
+
type: string;
|
|
82
|
+
additionalProperties: boolean;
|
|
83
|
+
required: string[];
|
|
84
|
+
properties: {
|
|
85
|
+
download_url: {
|
|
86
|
+
type: string;
|
|
87
|
+
};
|
|
88
|
+
file_id: {
|
|
89
|
+
type: string;
|
|
118
90
|
};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
91
|
+
mime_type: {
|
|
92
|
+
type: string;
|
|
93
|
+
};
|
|
94
|
+
file_name: {
|
|
95
|
+
type: string;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
126
98
|
"x-webframez-type": string;
|
|
127
|
-
type?: undefined;
|
|
128
99
|
pattern?: undefined;
|
|
129
100
|
items?: undefined;
|
|
130
101
|
enum?: undefined;
|
|
@@ -133,7 +104,9 @@ export declare function apiFunctionParamToJsonSchema(definition: ApiFunctionPara
|
|
|
133
104
|
type?: undefined;
|
|
134
105
|
pattern?: undefined;
|
|
135
106
|
items?: undefined;
|
|
136
|
-
|
|
107
|
+
additionalProperties?: undefined;
|
|
108
|
+
required?: undefined;
|
|
109
|
+
properties?: undefined;
|
|
137
110
|
"x-webframez-type"?: undefined;
|
|
138
111
|
};
|
|
139
112
|
export declare function toApiFunctionHttpResult(res: Response, result: any): Response;
|
|
@@ -254,10 +254,7 @@ function coerceApiFunctionParam(key, value, definition) {
|
|
|
254
254
|
if (isPlainApiObject(value)) {
|
|
255
255
|
return value;
|
|
256
256
|
}
|
|
257
|
-
|
|
258
|
-
return value;
|
|
259
|
-
}
|
|
260
|
-
throw new ApiFunctionRuntimeError(`Parameter "${key}" must be a file reference string or object`, 400);
|
|
257
|
+
throw new ApiFunctionRuntimeError(`Parameter "${key}" must be an OpenAI file reference object`, 400);
|
|
261
258
|
}
|
|
262
259
|
return value;
|
|
263
260
|
}
|
|
@@ -303,31 +300,15 @@ function apiFunctionParamToJsonSchema(definition) {
|
|
|
303
300
|
return { type: "object" };
|
|
304
301
|
if (type === "file") {
|
|
305
302
|
return {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
url: { type: "string" },
|
|
316
|
-
download_link: { type: "string" },
|
|
317
|
-
file_url: { type: "string" },
|
|
318
|
-
content_base64: { type: "string" },
|
|
319
|
-
data_url: { type: "string" },
|
|
320
|
-
id: { type: "string" },
|
|
321
|
-
filename: { type: "string" },
|
|
322
|
-
name: { type: "string" },
|
|
323
|
-
mime: { type: "string" },
|
|
324
|
-
},
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
type: "string",
|
|
328
|
-
description: "Connector runtime file reference string. Local paths must be rewritten by the ChatGPT connector before reaching the server.",
|
|
329
|
-
},
|
|
330
|
-
],
|
|
303
|
+
type: "object",
|
|
304
|
+
additionalProperties: true,
|
|
305
|
+
required: ["download_url", "file_id"],
|
|
306
|
+
properties: {
|
|
307
|
+
download_url: { type: "string" },
|
|
308
|
+
file_id: { type: "string" },
|
|
309
|
+
mime_type: { type: "string" },
|
|
310
|
+
file_name: { type: "string" },
|
|
311
|
+
},
|
|
331
312
|
"x-webframez-type": "file",
|
|
332
313
|
};
|
|
333
314
|
}
|
|
@@ -4,11 +4,14 @@ type ResolvedBackupTypeConfig = BackupTypeConfig & {
|
|
|
4
4
|
outputDir: string;
|
|
5
5
|
filename: string;
|
|
6
6
|
zip: boolean;
|
|
7
|
+
zipDriver: "auto" | "system" | "node";
|
|
8
|
+
zipCompressionLevel?: number;
|
|
7
9
|
cleanupWorkDir: boolean;
|
|
8
10
|
retention?: BackupRetentionConfig;
|
|
9
11
|
outputs: BackupOutputConfig[];
|
|
10
12
|
};
|
|
11
13
|
export declare class BackupManager {
|
|
14
|
+
private log;
|
|
12
15
|
getConfig(): BackupConfig;
|
|
13
16
|
listTypes(): {
|
|
14
17
|
key: string;
|
|
@@ -40,6 +40,12 @@ function normalizeArray(value) {
|
|
|
40
40
|
return value && Array.isArray(value) ? value : [];
|
|
41
41
|
}
|
|
42
42
|
class BackupManager {
|
|
43
|
+
log(options, message, payload) {
|
|
44
|
+
if ((options === null || options === void 0 ? void 0 : options.silent) || !(options === null || options === void 0 ? void 0 : options.log)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
options.log(message, payload);
|
|
48
|
+
}
|
|
43
49
|
getConfig() {
|
|
44
50
|
const config = Config_1.Config.get("backup");
|
|
45
51
|
if (!config || typeof config !== "object") {
|
|
@@ -62,7 +68,7 @@ class BackupManager {
|
|
|
62
68
|
}
|
|
63
69
|
const defaults = config.defaults || {};
|
|
64
70
|
const outputDir = backupType.outputDir || defaults.outputDir || "storage/backups";
|
|
65
|
-
return Object.assign(Object.assign(Object.assign({}, defaults), backupType), { workDir: backupType.workDir || defaults.workDir || "storage/backups/.work", outputDir: outputDir, filename: backupType.filename || defaults.filename || "{key}_{date}_{time}", zip: backupType.zip !== undefined ? backupType.zip : defaults.zip !== undefined ? defaults.zip : true, cleanupWorkDir: backupType.cleanupWorkDir !== undefined
|
|
71
|
+
return Object.assign(Object.assign(Object.assign({}, defaults), backupType), { workDir: backupType.workDir || defaults.workDir || "storage/backups/.work", outputDir: outputDir, filename: backupType.filename || defaults.filename || "{key}_{date}_{time}", zip: backupType.zip !== undefined ? backupType.zip : defaults.zip !== undefined ? defaults.zip : true, zipDriver: backupType.zipDriver || defaults.zipDriver || "auto", zipCompressionLevel: backupType.zipCompressionLevel !== undefined ? backupType.zipCompressionLevel : defaults.zipCompressionLevel, cleanupWorkDir: backupType.cleanupWorkDir !== undefined
|
|
66
72
|
? backupType.cleanupWorkDir
|
|
67
73
|
: defaults.cleanupWorkDir !== undefined
|
|
68
74
|
? defaults.cleanupWorkDir
|
|
@@ -191,28 +197,21 @@ class BackupManager {
|
|
|
191
197
|
};
|
|
192
198
|
});
|
|
193
199
|
}
|
|
194
|
-
buildArtifact(key, backupType, workRunDir, contentDir, date, id) {
|
|
200
|
+
buildArtifact(key, backupType, workRunDir, contentDir, date, id, options) {
|
|
195
201
|
const filename = (0, BackupPathUtils_1.formatBackupFilename)(backupType.filename, { key, date, id });
|
|
196
202
|
if (backupType.zip) {
|
|
197
203
|
const zipPath = path_1.default.join(workRunDir, `${filename}.zip`);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
name: (0, BackupPathUtils_1.normalizeBackupPath)(path_1.default.relative(contentDir, filepath)),
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
walk(contentDir);
|
|
215
|
-
(0, ZipWriter_1.createZipFile)(zipPath, files);
|
|
204
|
+
this.log(options, `Creating ZIP artifact '${path_1.default.basename(zipPath)}'`, {
|
|
205
|
+
driver: backupType.zipDriver,
|
|
206
|
+
compressionLevel: backupType.zipCompressionLevel,
|
|
207
|
+
});
|
|
208
|
+
const zipResult = (0, ZipWriter_1.createZipFileFromDirectory)(zipPath, contentDir, {
|
|
209
|
+
driver: backupType.zipDriver,
|
|
210
|
+
compressionLevel: backupType.zipCompressionLevel,
|
|
211
|
+
});
|
|
212
|
+
this.log(options, `ZIP artifact created using ${zipResult.driver} zip`, {
|
|
213
|
+
path: zipPath,
|
|
214
|
+
});
|
|
216
215
|
return {
|
|
217
216
|
path: zipPath,
|
|
218
217
|
filename: path_1.default.basename(zipPath),
|
|
@@ -228,10 +227,11 @@ class BackupManager {
|
|
|
228
227
|
};
|
|
229
228
|
}
|
|
230
229
|
run(key, options) {
|
|
231
|
-
var _a, _b;
|
|
230
|
+
var _a, _b, _c;
|
|
232
231
|
return __awaiter(this, void 0, void 0, function* () {
|
|
233
232
|
const backupType = this.resolveType(key);
|
|
234
233
|
this.ensureActive(key, backupType);
|
|
234
|
+
this.log(options, `Starting backup '${key}'`);
|
|
235
235
|
const now = new Date();
|
|
236
236
|
const id = (0, BackupPathUtils_1.backupTimestampId)(now);
|
|
237
237
|
const workRoot = (0, BackupPathUtils_1.resolveProjectPath)(backupType.workDir);
|
|
@@ -252,13 +252,17 @@ class BackupManager {
|
|
|
252
252
|
files: [],
|
|
253
253
|
databases: [],
|
|
254
254
|
};
|
|
255
|
+
this.log(options, "Collecting file sources");
|
|
255
256
|
const fileEntries = normalizeArray(backupType.files).flatMap((source) => this.collectFilesFromSource(source));
|
|
257
|
+
const fileSize = fileEntries.reduce((sum, entry) => sum + entry.size, 0);
|
|
258
|
+
this.log(options, `Collected ${fileEntries.length} file(s)`, { size: fileSize });
|
|
256
259
|
result.files = fileEntries.map((entry) => ({
|
|
257
260
|
from: entry.source,
|
|
258
261
|
to: entry.target,
|
|
259
262
|
size: entry.size,
|
|
260
263
|
}));
|
|
261
264
|
if (options === null || options === void 0 ? void 0 : options.dryRun) {
|
|
265
|
+
this.log(options, "Dry run enabled; skipping artifact and output writes");
|
|
262
266
|
result.outputs = outputs.map((output) => ({
|
|
263
267
|
driver: output.driver,
|
|
264
268
|
status: "skipped",
|
|
@@ -275,28 +279,44 @@ class BackupManager {
|
|
|
275
279
|
fs_1.default.rmSync(workRunDir, { recursive: true, force: true });
|
|
276
280
|
fs_1.default.mkdirSync(contentDir, { recursive: true });
|
|
277
281
|
try {
|
|
282
|
+
this.log(options, `Copying ${fileEntries.length} file(s) into backup work directory`);
|
|
278
283
|
this.copyFiles(fileEntries, contentDir);
|
|
284
|
+
this.log(options, "File copy finished");
|
|
279
285
|
for (const source of normalizeArray(backupType.databases)) {
|
|
286
|
+
this.log(options, `Backing up database '${source.connection || "default"}'`);
|
|
280
287
|
result.databases.push(yield this.backupDatabase(source, contentDir, { backupKey: key, backupId: id }));
|
|
288
|
+
this.log(options, `Database '${source.connection || "default"}' backup finished`);
|
|
281
289
|
}
|
|
282
|
-
result.artifact = this.buildArtifact(key, backupType, workRunDir, contentDir, now, id);
|
|
290
|
+
result.artifact = this.buildArtifact(key, backupType, workRunDir, contentDir, now, id, options);
|
|
283
291
|
const manifestPath = path_1.default.join(workRunDir, `${result.artifact.filename}.run-manifest.json`);
|
|
284
292
|
result.manifestPath = manifestPath;
|
|
285
293
|
for (const output of outputs) {
|
|
286
294
|
const retention = mergeRetention((_a = this.getConfig().defaults) === null || _a === void 0 ? void 0 : _a.retention, backupType.retention, output.retention);
|
|
287
295
|
const driver = BackupOutputDrivers_1.BackupOutputDrivers.get(output.driver);
|
|
296
|
+
this.log(options, `Writing artifact to '${output.driver}' output`, {
|
|
297
|
+
path: output.path,
|
|
298
|
+
folderPath: output.folderPath,
|
|
299
|
+
});
|
|
288
300
|
const outputResult = yield driver.write(result.artifact, output, {
|
|
289
301
|
backupKey: key,
|
|
290
302
|
backupId: id,
|
|
291
303
|
retention: retention,
|
|
292
304
|
});
|
|
293
305
|
result.outputs.push(outputResult);
|
|
306
|
+
this.log(options, `Output '${output.driver}' finished with status '${outputResult.status}'`, {
|
|
307
|
+
path: outputResult.path,
|
|
308
|
+
error: outputResult.error,
|
|
309
|
+
});
|
|
294
310
|
if (outputResult.status === "success" && (retention === null || retention === void 0 ? void 0 : retention.runAfterBackup)) {
|
|
311
|
+
this.log(options, `Running cleanup for '${output.driver}' output`);
|
|
295
312
|
result.cleanup.push(yield driver.cleanup(output, { backupKey: key, backupId: id, retention: retention }, { dryRun: false }));
|
|
313
|
+
this.log(options, `Cleanup for '${output.driver}' output finished`, {
|
|
314
|
+
deleted: ((_b = result.cleanup[result.cleanup.length - 1]) === null || _b === void 0 ? void 0 : _b.deleted.length) || 0,
|
|
315
|
+
});
|
|
296
316
|
}
|
|
297
317
|
}
|
|
298
318
|
result.endedAt = new Date().toISOString();
|
|
299
|
-
const outputManifestPath = (
|
|
319
|
+
const outputManifestPath = (_c = result.outputs.find((output) => output.payload && output.payload.manifestPath)) === null || _c === void 0 ? void 0 : _c.payload.manifestPath;
|
|
300
320
|
if (outputManifestPath) {
|
|
301
321
|
result.manifestPath = outputManifestPath;
|
|
302
322
|
}
|
|
@@ -307,10 +327,12 @@ class BackupManager {
|
|
|
307
327
|
fs_1.default.writeFileSync(output.payload.manifestPath, manifestJson, "utf-8");
|
|
308
328
|
}
|
|
309
329
|
}
|
|
330
|
+
this.log(options, `Backup '${key}' finished`);
|
|
310
331
|
return result;
|
|
311
332
|
}
|
|
312
333
|
finally {
|
|
313
334
|
if (backupType.cleanupWorkDir) {
|
|
335
|
+
this.log(options, "Cleaning backup work directory");
|
|
314
336
|
fs_1.default.rmSync(workRunDir, { recursive: true, force: true });
|
|
315
337
|
}
|
|
316
338
|
}
|
|
@@ -32,6 +32,8 @@ export type BackupDefaultsConfig = {
|
|
|
32
32
|
outputDir?: string;
|
|
33
33
|
filename?: string;
|
|
34
34
|
zip?: boolean;
|
|
35
|
+
zipDriver?: "auto" | "system" | "node";
|
|
36
|
+
zipCompressionLevel?: number;
|
|
35
37
|
cleanupWorkDir?: boolean;
|
|
36
38
|
retention?: BackupRetentionConfig;
|
|
37
39
|
};
|
|
@@ -100,6 +102,8 @@ export type BackupRunResult = {
|
|
|
100
102
|
export type BackupRunOptions = {
|
|
101
103
|
dryRun?: boolean;
|
|
102
104
|
channels?: string[];
|
|
105
|
+
silent?: boolean;
|
|
106
|
+
log?: (message: string, payload?: any) => void;
|
|
103
107
|
};
|
|
104
108
|
export type BackupCleanupOptions = {
|
|
105
109
|
dryRun?: boolean;
|
|
@@ -22,6 +22,7 @@ class BackupRunJob extends BaseQueueJob_1.BaseQueueJob {
|
|
|
22
22
|
this.log(`Starting backup '${backupKey}'`);
|
|
23
23
|
const result = yield new BackupManager_1.BackupManager().run(backupKey, {
|
|
24
24
|
channels: job.payload.channels,
|
|
25
|
+
log: (message, payload) => this.log(message, payload),
|
|
25
26
|
});
|
|
26
27
|
this.log(`Backup '${backupKey}' finished`, {
|
|
27
28
|
id: result.id,
|
|
@@ -2,3 +2,13 @@ export declare function createZipFile(zipPath: string, files: Array<{
|
|
|
2
2
|
source: string;
|
|
3
3
|
name: string;
|
|
4
4
|
}>): string;
|
|
5
|
+
export declare function createZipFileFromDirectory(zipPath: string, sourceDir: string, options?: {
|
|
6
|
+
driver?: "auto" | "system" | "node";
|
|
7
|
+
compressionLevel?: number;
|
|
8
|
+
}): {
|
|
9
|
+
path: string;
|
|
10
|
+
driver: "system";
|
|
11
|
+
} | {
|
|
12
|
+
path: string;
|
|
13
|
+
driver: "node";
|
|
14
|
+
};
|
|
@@ -3,10 +3,11 @@ 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.createZipFile = void 0;
|
|
6
|
+
exports.createZipFileFromDirectory = exports.createZipFile = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const zlib_1 = __importDefault(require("zlib"));
|
|
10
|
+
const child_process_1 = require("child_process");
|
|
10
11
|
const BackupPathUtils_1 = require("./BackupPathUtils");
|
|
11
12
|
const crcTable = (() => {
|
|
12
13
|
const table = [];
|
|
@@ -118,3 +119,51 @@ function createZipFile(zipPath, files) {
|
|
|
118
119
|
return zipPath;
|
|
119
120
|
}
|
|
120
121
|
exports.createZipFile = createZipFile;
|
|
122
|
+
function collectZipFiles(sourceDir) {
|
|
123
|
+
const files = [];
|
|
124
|
+
const walk = (dir) => {
|
|
125
|
+
for (const entry of fs_1.default.readdirSync(dir)) {
|
|
126
|
+
const filepath = path_1.default.join(dir, entry);
|
|
127
|
+
const stats = fs_1.default.statSync(filepath);
|
|
128
|
+
if (stats.isDirectory()) {
|
|
129
|
+
walk(filepath);
|
|
130
|
+
}
|
|
131
|
+
else if (stats.isFile()) {
|
|
132
|
+
files.push({
|
|
133
|
+
source: filepath,
|
|
134
|
+
name: (0, BackupPathUtils_1.normalizeBackupPath)(path_1.default.relative(sourceDir, filepath)),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
walk(sourceDir);
|
|
140
|
+
return files;
|
|
141
|
+
}
|
|
142
|
+
function compressionArg(level) {
|
|
143
|
+
if (level === undefined || level === null || Number.isNaN(level)) {
|
|
144
|
+
return "-6";
|
|
145
|
+
}
|
|
146
|
+
const normalized = Math.max(0, Math.min(9, Math.round(level)));
|
|
147
|
+
return `-${normalized}`;
|
|
148
|
+
}
|
|
149
|
+
function createZipFileFromDirectory(zipPath, sourceDir, options) {
|
|
150
|
+
var _a;
|
|
151
|
+
fs_1.default.mkdirSync(path_1.default.dirname(zipPath), { recursive: true });
|
|
152
|
+
if ((options === null || options === void 0 ? void 0 : options.driver) !== "node") {
|
|
153
|
+
const args = ["-q", compressionArg(options === null || options === void 0 ? void 0 : options.compressionLevel), "-r", zipPath, "."];
|
|
154
|
+
const result = (0, child_process_1.spawnSync)("zip", args, {
|
|
155
|
+
cwd: sourceDir,
|
|
156
|
+
encoding: "utf-8",
|
|
157
|
+
});
|
|
158
|
+
if (result.status === 0 && fs_1.default.existsSync(zipPath)) {
|
|
159
|
+
return { path: zipPath, driver: "system" };
|
|
160
|
+
}
|
|
161
|
+
if ((options === null || options === void 0 ? void 0 : options.driver) === "system") {
|
|
162
|
+
const detail = result.stderr || result.stdout || ((_a = result.error) === null || _a === void 0 ? void 0 : _a.message) || "unknown error";
|
|
163
|
+
throw new Error(`System zip failed: ${detail}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
createZipFile(zipPath, collectZipFiles(sourceDir));
|
|
167
|
+
return { path: zipPath, driver: "node" };
|
|
168
|
+
}
|
|
169
|
+
exports.createZipFileFromDirectory = createZipFileFromDirectory;
|
|
@@ -32,7 +32,12 @@ class BackupRunCommand extends ConsoleCommand_1.ConsoleCommand {
|
|
|
32
32
|
const result = yield new BackupManager_1.BackupManager().run(key, {
|
|
33
33
|
dryRun: this.getOption("dry-run") === true,
|
|
34
34
|
channels: parseChannels(this.getOption("channel")),
|
|
35
|
+
silent: this.getOption("silent") === true,
|
|
36
|
+
log: (message) => this.writeln(` [color=grey]${message}[/color]`),
|
|
35
37
|
});
|
|
38
|
+
if (this.getOption("silent") === true) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
36
41
|
if (result.dryRun) {
|
|
37
42
|
this.info(`Dry run for backup '${key}' finished.`);
|
|
38
43
|
}
|
package/package.json
CHANGED