use anyhow::anyhow;
use camino::Utf8Path;
use crate::hashing::ObjectId;
use crate::tree::{Forest, Node, NodeContents, Tree};
#[cfg(windows)]
pub fn has_trailing_slash(p: &Utf8Path) -> bool {
let last = p.as_str().as_bytes().last();
last == Some(&b'\\') || last == Some(&b'/')
}
#[cfg(unix)]
pub fn has_trailing_slash(p: &Utf8Path) -> bool {
p.as_str().as_bytes().last() == Some(&b'/')
}
fn printer(prefix: &str, path: &Utf8Path, node: &Node) {
print!("{prefix}{path}");
match &node.contents {
NodeContents::Directory { .. } => {
if !has_trailing_slash(path) {
print!("{}", std::path::MAIN_SEPARATOR);
}
}
NodeContents::File { .. } => {}
NodeContents::Symlink { target } => {
print!(" -> {target}");
}
};
println!();
}
#[derive(Debug)]
pub enum Recurse<'a> {
No,
Yes(&'a Forest),
}
pub fn walk_node<V>(v: &mut V, path: &Utf8Path, node: &Node, should_recurse: Recurse)
where
V: FnMut(&Utf8Path, &Node),
{
v(path, node);
if let Recurse::Yes(forest) = should_recurse {
match &node.contents {
NodeContents::Directory { subtree } => walk_tree(v, path, subtree, forest),
NodeContents::File { .. } | NodeContents::Symlink { .. } => (),
}
}
}
pub fn walk_tree<V>(v: &mut V, tree_path: &Utf8Path, tree_id: &ObjectId, forest: &Forest)
where
V: FnMut(&Utf8Path, &Node),
{
let tree: &Tree = forest
.get(tree_id)
.ok_or_else(|| anyhow!("Missing tree {tree_id}"))
.unwrap();
for (path, node) in tree {
let mut node_path = tree_path.to_owned();
node_path.push(path);
walk_node(v, &node_path, node, Recurse::Yes(forest));
}
}
pub fn print_node(prefix: &str, path: &Utf8Path, node: &Node, should_recurse: Recurse) {
let mut v = |p: &Utf8Path, n: &Node| printer(prefix, p, n);
walk_node(&mut v, path, node, should_recurse);
}
pub fn print_tree(prefix: &str, tree_path: &Utf8Path, tree_id: &ObjectId, forest: &Forest) {
let mut v = |p: &Utf8Path, n: &Node| printer(prefix, p, n);
walk_tree(&mut v, tree_path, tree_id, forest);
}