Bundle per-file deltas into delta.tar.zst instead of loose files
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* run command — full backup run.
|
* run command — full backup run.
|
||||||
*/
|
*/
|
||||||
import { mkdir, rename, writeFile } from 'fs/promises';
|
import { mkdir, rename, rm, writeFile } from 'fs/promises';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { run as spawn, rsync } from '../spawn.js';
|
import { run as spawn, rsync } from '../spawn.js';
|
||||||
import { parseItemize } from '../itemize.js';
|
import { parseItemize } from '../itemize.js';
|
||||||
@@ -51,12 +51,14 @@ export async function runCommand(config) {
|
|||||||
console.log(' [dry-run] change list determined at runtime');
|
console.log(' [dry-run] change list determined at runtime');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Phase 4: Generate per-file deltas into DELTAS/tmp/N/ ────
|
// ── Phase 4: Generate per-file deltas into DELTAS/tmp/N/files/
|
||||||
await setPhase(deltas, state, PHASES.GENERATING, dry);
|
await setPhase(deltas, state, PHASES.GENERATING, dry);
|
||||||
console.log('\n── Generate delta ──');
|
console.log('\n── Generate delta ──');
|
||||||
|
|
||||||
const tmpDir = join(deltas, 'tmp', String(seq));
|
const tmpDir = join(deltas, 'tmp', String(seq));
|
||||||
const filesDir = join(tmpDir, 'files');
|
const filesDir = join(tmpDir, 'files');
|
||||||
|
const tarFile = join(tmpDir, 'delta.tar');
|
||||||
|
const bundleFile = join(tmpDir, 'delta.tar.zst');
|
||||||
|
|
||||||
if (!dry) {
|
if (!dry) {
|
||||||
await mkdir(filesDir, { recursive: true });
|
await mkdir(filesDir, { recursive: true });
|
||||||
@@ -95,12 +97,24 @@ export async function runCommand(config) {
|
|||||||
manifestChanges.push({
|
manifestChanges.push({
|
||||||
path: change.path,
|
path: change.path,
|
||||||
status: change.status,
|
status: change.status,
|
||||||
delta: join('files', deltaFilename),
|
delta: deltaFilename,
|
||||||
});
|
});
|
||||||
|
|
||||||
fileIndex++;
|
fileIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Bundle: tar files/ → delta.tar → delta.tar.zst ──────────
|
||||||
|
console.log('\n── Bundle deltas ──');
|
||||||
|
// tar with -C so paths inside the archive are relative (just filenames)
|
||||||
|
await spawn('tar', ['cf', tarFile, '-C', filesDir, '.'], { dryRun: dry });
|
||||||
|
await spawn('zstd', [tarFile, '-o', bundleFile, '-f'], { dryRun: dry });
|
||||||
|
if (!dry) {
|
||||||
|
await rm(filesDir, { recursive: true });
|
||||||
|
await rm(tarFile);
|
||||||
|
} else {
|
||||||
|
console.log(`[dry-run] rm -rf ${filesDir} ${tarFile}`);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Phase 5: Write manifest + atomic commit ──────────────────
|
// ── Phase 5: Write manifest + atomic commit ──────────────────
|
||||||
await setPhase(deltas, state, PHASES.COMMITTING, dry);
|
await setPhase(deltas, state, PHASES.COMMITTING, dry);
|
||||||
console.log('\n── Commit delta ──');
|
console.log('\n── Commit delta ──');
|
||||||
@@ -110,6 +124,7 @@ export async function runCommand(config) {
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
prev_seq: state.last_complete,
|
prev_seq: state.last_complete,
|
||||||
backend: backendName,
|
backend: backendName,
|
||||||
|
bundle: 'delta.tar.zst',
|
||||||
changes: manifestChanges,
|
changes: manifestChanges,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user