//! 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, c: HashId, } impl FileTree { /// Construct a new FileTree with a repository pub(crate) fn new(repo: Arc, 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 { 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(); }