use anyhow::{Context, Result};
use db185::Db;
use std::env;
use std::io::{BufWriter, Write};
use std::process::ExitCode;
fn main() -> Result<ExitCode> {
let mut args = env::args_os().skip(1);
let Some(path) = args.next() else {
eprintln!("usage: dump <file.db> [key]");
return Ok(ExitCode::from(2));
};
let key = args.next();
if args.next().is_some() {
eprintln!("usage: dump <file.db> [key]");
return Ok(ExitCode::from(2));
}
let db = Db::open(&path).with_context(|| format!("opening {}", path.to_string_lossy()))?;
if let Some(k) = key {
let mut bytes = k.to_string_lossy().into_owned().into_bytes();
bytes.push(0);
let value = db
.get(&bytes)
.with_context(|| format!("looking up {}", k.to_string_lossy()))?;
value.map_or(Ok(ExitCode::from(1)), |v| {
println!("{}", String::from_utf8_lossy(trim_nul(&v)));
Ok(ExitCode::SUCCESS)
})
} else {
let mut out = BufWriter::with_capacity(64 * 1024, std::io::stdout().lock());
for entry in &db {
let entry = entry.context("iterating database")?;
write_pair(&mut out, entry.key(), entry.value()).context("writing output")?;
}
out.flush().context("flushing output")?;
Ok(ExitCode::SUCCESS)
}
}
fn write_pair<W: Write>(out: &mut W, key: &[u8], val: &[u8]) -> std::io::Result<()> {
out.write_all(b"file: ")?;
out.write_all(trim_nul(key))?;
out.write_all(b" pkg: ")?;
out.write_all(trim_nul(val))?;
out.write_all(b"\n")
}
fn trim_nul(bytes: &[u8]) -> &[u8] {
bytes.strip_suffix(b"\0").unwrap_or(bytes)
}