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.
104 lines
2.9 KiB
104 lines
2.9 KiB
//! Low-level abstraction over finding refs inside a commit tree
|
|
|
|
use super::tree_utils as utils;
|
|
use crate::HashId;
|
|
use git2::{ObjectType, Repository, TreeWalkMode, TreeWalkResult};
|
|
use std::sync::Arc;
|
|
|
|
/// A git directory tree walker abstraction
|
|
///
|
|
/// This type is meant to be used ephemerally, and internally uses the
|
|
/// libgit2 `Tree` abstraction to walk directory trees lazily to
|
|
/// resolve paths to [`TreeEntry`](self::TreeEntry)'s.
|
|
///
|
|
/// Note: this type _may_ be removed in the future. For a more
|
|
/// high-level (and stable) API, check
|
|
/// [`Explorer`](crate::files::Explorer)
|
|
pub struct FileTree {
|
|
repo: Arc<Repository>,
|
|
c: HashId,
|
|
}
|
|
|
|
impl FileTree {
|
|
/// Construct a new FileTree with a repository
|
|
pub(crate) fn new(repo: Arc<Repository>, c: HashId) -> Self {
|
|
Self { repo, c }
|
|
}
|
|
|
|
/// Resolve a path inside this file tree
|
|
///
|
|
/// Will return `None` if there is no tree for the selected
|
|
/// commit, or the file inside the tree does not exist.
|
|
pub fn resolve(&self, path: &str) -> Option<TreeEntry> {
|
|
let tree = utils::open_tree(&self.repo, &self.c)?;
|
|
let target = utils::path_split(path);
|
|
|
|
// Initialise entry to None as a fallback
|
|
let mut entry = None;
|
|
|
|
// Walk over tree and swallor errors (which we use to
|
|
// terminace traversal to speed up indexing time)
|
|
let _ = tree.walk(TreeWalkMode::PreOrder, |p, e| {
|
|
if utils::path_cmp(&target, p, e.name().unwrap()) {
|
|
entry = Some(TreeEntry::new(p, &e));
|
|
TreeWalkResult::Ok
|
|
} else {
|
|
TreeWalkResult::Skip
|
|
}
|
|
});
|
|
|
|
// Return whatever the entry is now
|
|
entry
|
|
}
|
|
}
|
|
|
|
/// An entry in a commit tree
|
|
///
|
|
/// This type is lazily loaded, and can represent either a Blob or a
|
|
/// Directory. You can resolve its value by calling
|
|
/// [`resolve()`](Self::resolve)
|
|
pub struct TreeEntry {
|
|
tt: EntryType,
|
|
id: HashId,
|
|
path: String,
|
|
}
|
|
|
|
impl TreeEntry {
|
|
fn new(path: &str, entry: &git2::TreeEntry) -> Self {
|
|
let tt = match entry.kind() {
|
|
Some(ObjectType::Blob) => EntryType::File,
|
|
Some(ObjectType::Tree) => EntryType::Dir,
|
|
_ => unimplemented!(),
|
|
};
|
|
let id = entry.id().into();
|
|
let path = path.into();
|
|
|
|
Self { tt, id, path }
|
|
}
|
|
|
|
/// Resolve this type to a [`Yield`]()
|
|
pub fn resolve(&self) {}
|
|
}
|
|
|
|
/// Type of a TreeEntry
|
|
pub enum EntryType {
|
|
/// A file that can be loaded
|
|
File,
|
|
/// A directory that can be indexed
|
|
Dir,
|
|
}
|
|
|
|
#[test]
|
|
fn index_tree() {
|
|
let path = env!("CARGO_MANIFEST_DIR").to_owned() + "/test-repo";
|
|
use crate::Repository as Repo;
|
|
|
|
eprintln!("Path: `{}`", path);
|
|
|
|
let r = Repo::open(&path).unwrap();
|
|
let b = r.branch("master".into()).unwrap();
|
|
let h = b.head();
|
|
|
|
let t = h.tree();
|
|
t.resolve("README".into()).unwrap();
|
|
}
|
|
|