// SPDX-FileCopyrightText: edef // SPDX-License-Identifier: OSL-3.0 use { clap::StructOpt, fossil::{store, Directory}, prost::Message, std::{ fs, io::Write, os::unix::{fs::symlink, prelude::OpenOptionsExt}, path::{Path, PathBuf}, }, }; #[derive(clap::Parser)] struct Args { #[clap(long, default_value = "fossil.db")] store: PathBuf, #[clap(parse(try_from_str = fossil::digest_from_str))] root: fossil::Digest, } fn main() { let args = Args::parse(); let store = fossil::Store::open(args.store).unwrap(); let root = { let bytes = store.read_blob(args.root).expect("blob not found"); let pb = store::Directory::decode(&*bytes).unwrap(); Directory::from_pb(pb) }; let root_path = Path::new("."); extract(&store, root_path, &root); } fn extract(store: &fossil::Store, path: &Path, dir: &Directory) { for (name, node) in &dir.children { let path = path.join(name); match node.clone() { fossil::Node::Directory(fossil::DirectoryRef { ident, size: _ }) => { let blob = store.read_blob(ident).expect("blob not found"); let pb = store::Directory::decode(&*blob).unwrap(); fs::create_dir(&path).unwrap(); extract(store, &path, &Directory::from_pb(pb)); } fossil::Node::File(fossil::FileRef { ident, executable, size: _, }) => { let mode = if executable { 0o755 } else { 0o644 }; let mut f = fs::OpenOptions::new() .write(true) .create_new(true) .mode(mode) .open(path) .unwrap(); let blob = store.read_blob(ident).expect("blob not found"); f.write_all(&blob).unwrap(); } fossil::Node::Link { target } => { symlink(target, path).unwrap(); } } } }