use std::path::Path;
use crate::cli::{
AssetsArgs, AssetsCommand, AssetsPathsArgs, AssetsScanArgs, AssetsStatusArgs, AssetsVerifyArgs,
};
use crate::context::Context;
use crate::error::{CliError, CliResult, ExitCode};
use dbmd_core::{assets, Store};
pub fn run(ctx: &Context, args: &AssetsArgs) -> CliResult {
match &args.command {
AssetsCommand::Scan(a) => run_scan(ctx, a),
AssetsCommand::Verify(a) => run_verify(ctx, a),
AssetsCommand::Status(a) => run_status(ctx, a),
AssetsCommand::Paths(a) => run_paths(ctx, a),
}
}
fn run_scan(ctx: &Context, args: &AssetsScanArgs) -> CliResult {
let store = Store::open_strict(Path::new(&args.dir))?;
let report = assets::scan(&store, args.dry_run, args.untracked)?;
if ctx.json {
println!(
"{}",
serde_json::to_string(&report).expect("scan report serializes")
);
} else {
let tail = if report.dry_run {
" · (dry run, not written)"
} else if report.wrote {
" · manifest updated"
} else {
" · no change"
};
println!(
"{} cataloged · {} hashed · {} preserved · {} bytes{tail}",
report.cataloged, report.hashed, report.preserved, report.bytes
);
for w in &report.warnings {
println!("warning: {w}");
}
for u in &report.untracked {
println!("untracked: {u}");
}
}
Ok(())
}
fn run_verify(ctx: &Context, args: &AssetsVerifyArgs) -> CliResult {
let store = Store::open_strict(Path::new(&args.dir))?;
let report = assets::verify(&store, args.include_optional, args.quick)?;
if ctx.json {
println!(
"{}",
serde_json::to_string(&report).expect("verify report serializes")
);
} else {
println!(
"{} checked · {} ok · {} missing · {} corrupt ({} mode)",
report.checked,
report.ok,
report.missing.len(),
report.corrupt.len(),
report.mode
);
for m in &report.missing {
println!("missing: {m}");
}
for c in &report.corrupt {
println!("corrupt: {c}");
}
println!(
"{}",
if report.complete {
"PASS — byte-complete"
} else {
"FAIL — store is not byte-complete"
}
);
}
if !report.complete {
return Err(CliError::new(
ExitCode::Runtime,
"ASSET_INCOMPLETE",
format!(
"{} missing, {} corrupt",
report.missing.len(),
report.corrupt.len()
),
)
.with_hint("run `vibecraft assets pull` (or your sync) to restore, then re-verify"));
}
Ok(())
}
fn run_status(ctx: &Context, args: &AssetsStatusArgs) -> CliResult {
let store = Store::open_strict(Path::new(&args.dir))?;
let report = assets::status(&store)?;
if ctx.json {
println!(
"{}",
serde_json::to_string(&report).expect("status report serializes")
);
} else {
println!(
"{} cataloged · {} present · {} missing ({} required, {} optional) · {} of {} bytes to restore",
report.total,
report.present,
report.missing,
report.required_missing,
report.optional_missing,
report.bytes_missing,
report.bytes_total
);
}
Ok(())
}
fn run_paths(ctx: &Context, args: &AssetsPathsArgs) -> CliResult {
let store = Store::open_strict(Path::new(&args.dir))?;
let paths = assets::paths(&store)?;
if ctx.json {
println!(
"{}",
serde_json::to_string(&paths).expect("paths serialize")
);
} else {
for p in &paths {
println!("{p}");
}
}
Ok(())
}