aboutsummaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMx Kookie <kookie@spacekookie.de>2020-11-01 18:25:19 +0100
committerMx Kookie <kookie@spacekookie.de>2020-12-21 05:19:28 +0100
commiteb1b781fabde92081d9e8ba5ede17cbfbf4f7edf (patch)
tree7f9b9470622f65bf97bdad84a4a10c2fb285039e /apps
parenteaf889ee80ddfdb0b89efe9d371369f715dccd89 (diff)
apps/servers/octopus: implement initial branch parsing
Diffstat (limited to 'apps')
-rw-r--r--apps/servers/octopus/supergit/src/bin/test.rs11
-rw-r--r--apps/servers/octopus/supergit/src/raw/branch.rs51
-rw-r--r--apps/servers/octopus/supergit/src/raw/mod.rs65
-rw-r--r--apps/servers/octopus/supergit/src/raw/tree_walk.rs167
4 files changed, 284 insertions, 10 deletions
diff --git a/apps/servers/octopus/supergit/src/bin/test.rs b/apps/servers/octopus/supergit/src/bin/test.rs
index 166047e9dd17..3b5fad9462cf 100644
--- a/apps/servers/octopus/supergit/src/bin/test.rs
+++ b/apps/servers/octopus/supergit/src/bin/test.rs
@@ -10,7 +10,14 @@ fn main() {
std::process::exit(2);
}
};
-
+
let rr = RawRepository::open(path.as_str()).unwrap();
-
+ let branches = rr.parse_branches().unwrap();
+
+ for branch in branches {
+ if branch.name.as_str() != "main" && continue {}
+ println!("Branch: {}", branch.name);
+
+ branch.enumerate(" ".into(), &rr.inner);
+ }
}
diff --git a/apps/servers/octopus/supergit/src/raw/branch.rs b/apps/servers/octopus/supergit/src/raw/branch.rs
new file mode 100644
index 000000000000..1e2d27ad9c20
--- /dev/null
+++ b/apps/servers/octopus/supergit/src/raw/branch.rs
@@ -0,0 +1,51 @@
+use super::{HashId, RawRepository};
+use crate::Branch;
+use git2::{Commit, Repository};
+
+/// Represent some raw branch metadata
+pub struct RawBranch {
+ pub name: String,
+ pub head: HashId,
+}
+
+fn print_commit(i: &String, c: &Commit) {
+ println!(
+ "{}{}: {}",
+ i,
+ c.id().to_string(),
+ c.message().unwrap().trim().split("\n").nth(0).unwrap()
+ );
+}
+
+fn print_parent_tree(c: &Commit, indent: String) {
+ c.parents().for_each(|c| {
+ println!(
+ "{}{}: {}",
+ indent,
+ c.id().to_string(),
+ c.message().unwrap().trim().split("\n").nth(0).unwrap()
+ );
+
+ print_parent_tree(&c, indent.clone());
+ });
+}
+
+impl RawBranch {
+ /// Consume branch reference and enumerate real branch history
+ pub fn into_branch(self, repo: &mut RawRepository) -> Branch {
+ todo!()
+ }
+
+ /// **REMOVE ME** A test function to do some test things
+ pub fn enumerate(&self, indent: String, repo: &Repository) {
+ let c = repo.find_commit((&self.head).into()).unwrap();
+ println!(
+ "{}{}: {}",
+ indent,
+ c.id().to_string(),
+ c.message().unwrap().trim().split("\n").nth(0).unwrap()
+ );
+
+ print_parent_tree(&c, indent);
+ }
+}
diff --git a/apps/servers/octopus/supergit/src/raw/mod.rs b/apps/servers/octopus/supergit/src/raw/mod.rs
index 7bf6c0a396a4..80bff3528f3d 100644
--- a/apps/servers/octopus/supergit/src/raw/mod.rs
+++ b/apps/servers/octopus/supergit/src/raw/mod.rs
@@ -1,13 +1,45 @@
//! Raw representation wrappers for libgit2
+mod branch;
+pub use branch::RawBranch;
+
mod branch_walk;
mod tree_walk;
use crate::{Branch, BranchCommit};
-use git2::{self, Repository};
+use git2::{self, Oid, Repository};
pub type RawResult<T> = Result<T, RawError>;
+/// The hex ID of a commit
+#[derive(Debug)]
+pub struct HashId(String);
+
+impl From<Oid> for HashId {
+ fn from(o: Oid) -> Self {
+ Self(o.to_string())
+ }
+}
+
+impl From<HashId> for Oid {
+ fn from(hid: HashId) -> Self {
+ Oid::from_str(hid.0.as_str()).expect(&format!(
+ "Tried turning an invalid HashId variant into an Oid: {:?}",
+ hid
+ ))
+ }
+}
+
+impl<'any> From<&'any HashId> for Oid {
+ fn from(hid: &'any HashId) -> Self {
+ Oid::from_str(hid.0.as_str()).expect(&format!(
+ "Tried turning an invalid HashId variant into an Oid: {:?}",
+ hid
+ ))
+ }
+}
+
+
/// An error abstraction for raw git operations
#[derive(Debug)]
pub enum RawError {
@@ -20,15 +52,9 @@ impl From<git2::Error> for RawError {
}
}
-/// Represent a raw branch
-pub struct RawBranch {
- name: String,
- head: String,
-}
-
/// Wrap a libgit2 repository to provide an API fascade
pub struct RawRepository {
- inner: Repository,
+ pub inner: Repository,
}
impl RawRepository {
@@ -39,7 +65,30 @@ impl RawRepository {
}
/// Parse branch data from repository
+ ///
+ /// ## Panics
+ ///
+ /// If there is an error around getting the name, or head commit.
pub fn parse_branches(&self) -> RawResult<Vec<RawBranch>> {
+ Ok(self
+ .inner
+ .branches(None)?
+ .into_iter()
+ .filter_map(|e| e.ok())
+ .map(|(branch, _)| {
+ let name = branch.name().unwrap().unwrap().into();
+ let head = branch.get().peel_to_commit().unwrap().id().into();
+
+ RawBranch { name, head }
+ })
+ .collect())
+ }
+
+ /// Get the files touched by a commit
+ pub fn get_files_for(&self, id: HashId) -> RawResult<Vec<()>> {
+ let c = self.inner.find_commit(id.into())?;
+ let tree = c.tree()?;
+
todo!()
}
}
diff --git a/apps/servers/octopus/supergit/src/raw/tree_walk.rs b/apps/servers/octopus/supergit/src/raw/tree_walk.rs
index 05337640cd19..f6bb3a964906 100644
--- a/apps/servers/octopus/supergit/src/raw/tree_walk.rs
+++ b/apps/servers/octopus/supergit/src/raw/tree_walk.rs
@@ -1 +1,168 @@
//! 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
+}