aboutsummaryrefslogtreecommitdiff
path: root/apps/servers/octopus/supergit/src/files/tree.rs
diff options
context:
space:
mode:
Diffstat (limited to 'apps/servers/octopus/supergit/src/files/tree.rs')
-rw-r--r--apps/servers/octopus/supergit/src/files/tree.rs104
1 files changed, 104 insertions, 0 deletions
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<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();
+}