You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
4.6 KiB
168 lines
4.6 KiB
//! Walk the file tree for a particular commit
|
|
|
|
use git2::{self, ObjectType, TreeWalkMode};
|
|
use std::collections::BTreeMap;
|
|
|
|
/// A cache of a repository tree
|
|
#[derive(Default, Debug, Clone)]
|
|
pub(crate) struct Tree {
|
|
inner: BTreeMap<String, TreeNode>,
|
|
}
|
|
|
|
impl Tree {
|
|
/// Insert a node into a subtree with it's full path
|
|
fn insert_to_subtree(&mut self, mut path: Vec<String>, name: String, node: TreeNode) {
|
|
// If we are given a path, resolve it first
|
|
let curr = if path.len() > 0 {
|
|
let rest = path.split_off(1);
|
|
let mut curr = self.inner.get_mut(&path[0]).unwrap();
|
|
|
|
for dir in rest {
|
|
match curr {
|
|
TreeNode::Dir(ref mut d) => {
|
|
curr = d.children.inner.get_mut(&dir).unwrap();
|
|
}
|
|
_ => panic!("Not a tree!"),
|
|
}
|
|
}
|
|
|
|
match curr {
|
|
TreeNode::Dir(ref mut d) => &mut d.children,
|
|
TreeNode::File(_) => panic!("Not a tree!"),
|
|
}
|
|
} else {
|
|
// If no path was given, we assume the root is meant
|
|
self
|
|
};
|
|
|
|
curr.inner.insert(name, node);
|
|
}
|
|
|
|
/// Walk through the tree and only return filenode objects
|
|
pub(crate) fn flatten(&self) -> Vec<FileNode> {
|
|
self.inner.values().fold(vec![], |mut vec, node| {
|
|
match node {
|
|
TreeNode::File(f) => vec.push(f.clone()),
|
|
TreeNode::Dir(d) => vec.append(&mut d.children.flatten()),
|
|
}
|
|
|
|
vec
|
|
})
|
|
}
|
|
|
|
/// Get all the commits that touch a file
|
|
pub(crate) fn grab_path_history(&self, path: String) -> String {
|
|
let mut path: Vec<String> = path
|
|
.split("/")
|
|
.filter_map(|seg| match seg {
|
|
"" => None,
|
|
val => Some(val.into()),
|
|
})
|
|
.collect();
|
|
|
|
let leaf = if path.len() > 0 {
|
|
let rest = path.split_off(1);
|
|
let mut curr = self.inner.get(&path[0]).unwrap();
|
|
|
|
for dir in rest {
|
|
match curr {
|
|
TreeNode::Dir(d) => curr = d.children.inner.get(&dir).unwrap(),
|
|
TreeNode::File(_) => break, // we reached the leaf
|
|
}
|
|
}
|
|
|
|
curr
|
|
} else {
|
|
panic!("No valid path!");
|
|
};
|
|
|
|
match leaf {
|
|
TreeNode::File(f) => f.id.clone(),
|
|
_ => panic!("Not a leaf!"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub(crate) enum TreeNode {
|
|
File(FileNode),
|
|
Dir(DirNode),
|
|
}
|
|
|
|
impl TreeNode {
|
|
fn name(&self) -> String {
|
|
match self {
|
|
Self::File(f) => f.name.clone(),
|
|
Self::Dir(d) => d.name.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub(crate) struct FileNode {
|
|
pub id: String,
|
|
pub path: Vec<String>,
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub(crate) struct DirNode {
|
|
pub path: Vec<String>,
|
|
pub name: String,
|
|
pub children: Tree,
|
|
}
|
|
|
|
impl DirNode {
|
|
fn append(&mut self, node: TreeNode) {
|
|
self.children.inner.insert(node.name(), node);
|
|
}
|
|
}
|
|
|
|
/// Take a series of path-segments and render a tree at that location
|
|
pub(crate) fn parse_tree(tree: git2::Tree) -> Tree {
|
|
let mut root = Tree::default();
|
|
|
|
tree.walk(TreeWalkMode::PreOrder, |path, entry| {
|
|
let path: Vec<String> = path
|
|
.split("/")
|
|
.filter_map(|seg| match seg {
|
|
"" => None,
|
|
val => Some(val.into()),
|
|
})
|
|
.collect();
|
|
let name = entry.name().unwrap().to_string();
|
|
|
|
match entry.kind() {
|
|
// For every tree in the tree we create a new TreeNode with the path we know about
|
|
Some(ObjectType::Tree) => {
|
|
root.insert_to_subtree(
|
|
path.clone(),
|
|
name.clone(),
|
|
TreeNode::Dir(DirNode {
|
|
path,
|
|
name,
|
|
children: Tree::default(),
|
|
}),
|
|
);
|
|
}
|
|
// If we encounter a blob, this is a file that we can simply insert into the tree
|
|
Some(ObjectType::Blob) => {
|
|
root.insert_to_subtree(
|
|
path.clone(),
|
|
name.clone(),
|
|
TreeNode::File(FileNode {
|
|
id: format!("{}", entry.id()),
|
|
path,
|
|
name,
|
|
}),
|
|
);
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
0
|
|
})
|
|
.unwrap();
|
|
|
|
root
|
|
}
|
|
|