summary refs log tree commit diff
path: root/ripple/fossil/src/bin/extract.rs
blob: 0a7d0c738d6e0a2eae5266ba83a91353bc594814 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// SPDX-FileCopyrightText: edef <edef@unfathomable.blue>
// 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();
			}
		}
	}
}