From c8f3364c742c3528ee0709a44e82643fee2f8afe Mon Sep 17 00:00:00 2001 From: Mx Kookie Date: Wed, 6 Jan 2021 23:04:53 +0100 Subject: octopus: supergit: add interface to query specific store paths --- apps/servers/octopus/supergit/src/files/tree.rs | 104 ++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 apps/servers/octopus/supergit/src/files/tree.rs (limited to 'apps/servers/octopus/supergit/src/files/tree.rs') diff --git a/apps/servers/octopus/supergit/src/files/tree.rs b/apps/servers/octopus/supergit/src/files/tree.rs new file mode 100644 index 000000000000..5f4fb6671aa5 --- /dev/null +++ b/apps/servers/octopus/supergit/src/files/tree.rs @@ -0,0 +1,104 @@ +//! 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(); +} -- cgit v1.2.3