Initial project outline
- package.json (ESM, bin entry) - bin/delta-backup.js — entrypoint - lib/args.js — CLI arg parsing via Node parseArgs - lib/config.js — config file merging + required path guards - lib/spawn.js — safe process spawning (no shell strings) - lib/state.js — sequence number + phase state management - lib/backends/zstd.js — zstd delta backend - lib/backends/index.js — backend registry - lib/commands/run.js — full run skeleton (phases 1-3 wired, 4-6 stubbed) - lib/commands/status.js — status command
This commit is contained in:
28
lib/spawn.js
Normal file
28
lib/spawn.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Process spawning — always explicit argument arrays, never shell strings.
|
||||
*/
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
/**
|
||||
* Spawn a process and stream its output.
|
||||
* @param {string} cmd
|
||||
* @param {string[]} args
|
||||
* @param {{ dryRun?: boolean, label?: string }} opts
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function run(cmd, args, { dryRun = false, label } = {}) {
|
||||
const display = [cmd, ...args].join(' ');
|
||||
if (label) console.log(`[${label}] ${display}`);
|
||||
else console.log(`$ ${display}`);
|
||||
|
||||
if (dryRun) return;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(cmd, args, { stdio: 'inherit' });
|
||||
child.on('error', reject);
|
||||
child.on('close', code => {
|
||||
if (code === 0) resolve();
|
||||
else reject(new Error(`${cmd} exited with code ${code}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user