parrot-blackbox 1.0.9 → 1.0.12
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/package.json +1 -1
- package/src/backup/snapshot.js +20 -9
- package/src/cli.js +31 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "parrot-blackbox",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "parrot-blackbox — crash-proof, multi-cloud backup & recovery automation for Parrot OS. Daily/weekly off-disk backups with automatic catch-up, smart storage across many MEGA + Google Drive accounts, Timeshift snapshot backups and one-command restore.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/cli.js",
|
package/src/backup/snapshot.js
CHANGED
|
@@ -197,7 +197,7 @@ export function snapshotDirFor(snapshot, { privileged = 'noninteractive' } = {})
|
|
|
197
197
|
|
|
198
198
|
// Get the device that contains the root filesystem
|
|
199
199
|
const deviceResult = execaSync('findmnt', ['-n', '-o', 'SOURCE', '/'], { reject: false });
|
|
200
|
-
const device = deviceResult.stdout.trim();
|
|
200
|
+
const device = deviceResult.stdout.trim().split('[')[0];
|
|
201
201
|
|
|
202
202
|
if (device && deviceResult.exitCode === 0) {
|
|
203
203
|
// Create temporary mount point
|
|
@@ -268,14 +268,25 @@ export async function runSnapshotBackup(cfg, state, { due, privileged = 'noninte
|
|
|
268
268
|
|
|
269
269
|
let manifest;
|
|
270
270
|
try {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
271
|
+
const bin = process.argv[1] || 'parrot-blackbox';
|
|
272
|
+
const outPath = path.join(process.env.PBB_STATE_DIR || '/tmp', `manifest-${created.name}.json`);
|
|
273
|
+
const baseArgs = [process.execPath, bin, '_internal_upload', dir, 'snapshots', created.name, cfg.storage.remoteRoot, String(cfg.storage.chunkSize), outPath];
|
|
274
|
+
const args = process.env.PBB_SUDO_DIRECT === '1' ? baseArgs : ['-E', ...baseArgs];
|
|
275
|
+
|
|
276
|
+
let res;
|
|
277
|
+
if (privileged === 'interactive') {
|
|
278
|
+
res = await sudoInteractive(args);
|
|
279
|
+
} else {
|
|
280
|
+
res = await sudoNonInteractive(args);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (res.exitCode !== 0) {
|
|
284
|
+
throw new Error(`upload failed (exit ${res.exitCode})`);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const manifestStr = fs.readFileSync(outPath, 'utf8');
|
|
288
|
+
manifest = JSON.parse(manifestStr);
|
|
289
|
+
try { fs.rmSync(outPath, {force: true}); } catch {}
|
|
279
290
|
} catch (e) {
|
|
280
291
|
// The local snapshot exists and is safe; the cloud upload failed.
|
|
281
292
|
journal('snapshots', `upload failed for ${created.name}: ${e.message}`, 'error');
|
package/src/cli.js
CHANGED
|
@@ -512,6 +512,36 @@ const main = defineCommand({
|
|
|
512
512
|
console.log(`parrot-blackbox v${pkg.version}`);
|
|
513
513
|
return;
|
|
514
514
|
|
|
515
|
+
case '_internal_upload': {
|
|
516
|
+
const localDir = rest[0];
|
|
517
|
+
const kind = rest[1];
|
|
518
|
+
const id = rest[2];
|
|
519
|
+
const remoteRoot = rest[3];
|
|
520
|
+
const chunkSize = parseInt(rest[4], 10);
|
|
521
|
+
const outPath = rest[5];
|
|
522
|
+
const { planAndPlace } = await import('./storage/allocator.js');
|
|
523
|
+
const s = p.spinner();
|
|
524
|
+
s.start(`Uploading snapshot ${id}...`);
|
|
525
|
+
const cfg = loadConfig();
|
|
526
|
+
const accs = await refreshAccounts(cfg);
|
|
527
|
+
try {
|
|
528
|
+
const manifest = await planAndPlace(localDir, {
|
|
529
|
+
kind, id, accounts: accs, remoteRoot, chunkSize,
|
|
530
|
+
onProgress: (prog) => {
|
|
531
|
+
s.message(prog.text);
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
s.stop('✔ Upload complete');
|
|
535
|
+
import('node:fs').then(fs => fs.writeFileSync(outPath, JSON.stringify(manifest)));
|
|
536
|
+
process.exitCode = 0;
|
|
537
|
+
} catch (e) {
|
|
538
|
+
s.stop('✖ Upload failed');
|
|
539
|
+
console.error(`_internal_upload failed: ${e.message}`);
|
|
540
|
+
process.exitCode = 1;
|
|
541
|
+
}
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
|
|
515
545
|
case 'help':
|
|
516
546
|
case '-h':
|
|
517
547
|
case '--help':
|
|
@@ -522,6 +552,4 @@ const main = defineCommand({
|
|
|
522
552
|
process.exitCode = 1;
|
|
523
553
|
}
|
|
524
554
|
},
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
runMain(main);
|
|
555
|
+
});runMain(main);
|