aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2020-06-22 16:33:28 +0200
committerKatharina Fey <kookie@spacekookie.de>2020-06-22 16:33:28 +0200
commita0dca8186bdef76e09e9c388d7f85839e85ce8db (patch)
treee10257f724b01ddc9b8244c9b2429921612b6856 /src
parent367cb0b2358be04d18dfea963d1c42044893e3b4 (diff)
git: refactoring git module to have a unified actions API
Diffstat (limited to 'src')
-rw-r--r--src/git/log.rs57
-rw-r--r--src/git/mod.rs55
-rw-r--r--src/git/repo.rs19
-rw-r--r--src/git/tree.rs32
-rw-r--r--src/main.rs6
5 files changed, 120 insertions, 49 deletions
diff --git a/src/git/log.rs b/src/git/log.rs
index 97101cf..c8f4aa3 100644
--- a/src/git/log.rs
+++ b/src/git/log.rs
@@ -1,7 +1,7 @@
//! libgit2 log parsing
-use crate::git::{self, tree::FileNode};
-use git2::{Oid, Repository};
+use crate::git::{tree::FileNode, Repo};
+use git2::Oid;
use std::collections::{BTreeMap, BTreeSet};
/// A file-commit referenced graph thing
@@ -17,8 +17,11 @@ use std::collections::{BTreeMap, BTreeSet};
/// change" and it will tell you (sort of).
#[derive(Debug, Default)]
pub(crate) struct CommitGraph {
+ /// The correct order of commits in the log
order: Vec<String>,
- file_refs: BTreeMap<String, BTreeSet<String>>,
+ /// List of all files, and the commits in which they were touched
+ file_refs: BTreeMap<String, Vec<String>>,
+ /// Map of commit IDs to metadata
commit_refs: BTreeMap<String, CommitNode>,
}
@@ -31,19 +34,19 @@ pub(crate) struct CommitNode {
time: i64,
}
-fn build_diff_log(repo: &Repository, log: Vec<(String, Vec<FileNode>)>) -> Vec<CommitNode> {
+fn build_diff_log(repo: &Repo, log: Vec<(String, Vec<FileNode>)>) -> Vec<CommitNode> {
todo!()
}
/// Walk through all commits from a given ref and build a commit graph
-pub(crate) fn create_commit_log(id: String, repo: &Repository) -> CommitGraph {
- let mut walker = repo.revwalk().unwrap();
- walker.push(Oid::from_str(id.as_str()).unwrap()).unwrap();
+pub(crate) fn create_commit_log(rev: String, repo: &Repo) -> CommitGraph {
+ let mut walker = repo.get_inner().revwalk().unwrap();
+ walker.push(Oid::from_str(rev.as_str()).unwrap()).unwrap();
let mut commits = walker
.into_iter()
.map(|oid| {
let oid = oid.unwrap();
- repo.find_commit(oid).unwrap()
+ repo.get_inner().find_commit(oid).unwrap()
})
.collect::<Vec<_>>();
commits.reverse();
@@ -52,7 +55,7 @@ pub(crate) fn create_commit_log(id: String, repo: &Repository) -> CommitGraph {
.into_iter()
.map(|commit| {
let id = format!("{}", commit.id());
- (id.clone(), git::repo::get_tree(&repo, id.as_str()))
+ (id.clone(), repo.get_tree(id.as_str()))
})
.collect();
@@ -64,43 +67,51 @@ pub(crate) fn create_commit_log(id: String, repo: &Repository) -> CommitGraph {
let (commit_refs, file_refs) = log.into_iter().fold(
(BTreeMap::new(), BTreeMap::new()),
|(mut cm, mut fm), (cid, current)| {
+ let commit_id = format!("{}", cid);
+
let d = repo
+ .get_inner()
.diff_tree_to_tree(Some(&previous), Some(&current), None)
.unwrap();
- let files = d.deltas().fold(BTreeSet::new(), |mut set, delta| {
- set.insert(format!("{}", delta.new_file().id()));
+
+ // Store the commit to preserve order
+ order.push(commit_id.clone());
+
+ // For each file, store this commit as one that touched it
+ let touches = d.deltas().fold(BTreeSet::new(), |mut set, delta| {
+ let file_id = format!("{}", delta.new_file().id());
+ fm.entry(file_id.clone())
+ .or_insert(vec![])
+ .push(commit_id.clone());
+ set.insert(file_id);
set
});
- order.push(cid.clone());
- fm.insert(cid.clone(), files.clone());
-
+ // From the commit, build a metadata object
let commit_u = repo
+ .get_inner()
.find_commit(Oid::from_str(cid.as_str()).unwrap())
.unwrap();
let author_u = commit_u.author();
let commit = CommitNode {
- id: cid.clone(),
+ id: commit_id,
message: commit_u.message().unwrap().to_owned(),
author: format!("{} {}", author_u.name().unwrap(), author_u.email().unwrap()),
- touches: files,
+ touches,
time: author_u.when().seconds(),
};
+ // Insert the metadata object
cm.insert(cid.clone(), commit);
+ // We pass both the modified maps into the next commit
(cm, fm)
},
);
- let graph = CommitGraph {
+ CommitGraph {
order,
file_refs,
commit_refs,
- };
-
- dbg!(graph);
-
- // let diffs = build_diff_log(&repo, log);
- todo!()
+ }
}
diff --git a/src/git/mod.rs b/src/git/mod.rs
index 1cd9057..244e2f4 100644
--- a/src/git/mod.rs
+++ b/src/git/mod.rs
@@ -1,5 +1,58 @@
//! Wrappers for libgit2
pub mod log;
-pub mod repo;
pub mod tree;
+
+use git2::{self, Repository};
+use log::CommitGraph;
+use tree::Tree;
+
+/// A top-level wrapper API for all libgit2 functions
+pub struct Repo {
+ inner: Repository,
+ commits: Option<CommitGraph>,
+ rev: Option<String>,
+}
+
+impl Repo {
+ pub(crate) fn new(path: &str) -> Self {
+ Self {
+ inner: Repository::open(path).expect(&format!("`{}` is not a valid git repo", path)),
+ commits: None,
+ rev: None,
+ }
+ }
+
+ pub(self) fn get_inner(&self) -> &Repository {
+ &self.inner
+ }
+
+ pub(self) fn get_tree<'r>(&'r self, rev: &str) -> git2::Tree<'r> {
+ self.inner
+ .revparse_single(rev)
+ .unwrap()
+ .peel_to_tree()
+ .unwrap()
+ }
+
+ pub(crate) fn clear_cache(&mut self) {
+ self.rev = None;
+ self.commits = None;
+ }
+
+ /// Load and cache commits for a specific rev
+ pub(crate) fn load_commits(&mut self, rev: String) {
+ self.rev = Some(rev.clone());
+ self.commits = Some(log::create_commit_log(rev, &self));
+ }
+
+ /// Load the tree of files for the current rev
+ ///
+ /// Will fail if no rev was previously cached
+ pub(crate) fn get_file_tree(&self) -> Tree {
+ tree::parse_tree(
+ self.get_tree(self.rev.as_ref().unwrap().as_str()),
+ self.get_inner(),
+ )
+ }
+}
diff --git a/src/git/repo.rs b/src/git/repo.rs
deleted file mode 100644
index 0d04b0d..0000000
--- a/src/git/repo.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use crate::templ_data::repo::RepoData;
-use git2::{Oid, Repository, Tree};
-
-/// Represents a repo in libgit2
-pub(crate) struct Repo {
- pub(crate) inner: Repository,
-}
-
-impl Repo {
- pub(crate) fn new(path: &str) -> Self {
- Self {
- inner: Repository::open(path).expect(&format!("`{}` is not a valid git repo", path)),
- }
- }
-}
-
-pub(crate) fn get_tree<'r>(repo: &'r Repository, rev: &str) -> Tree<'r> {
- repo.revparse_single(rev).unwrap().peel_to_tree().unwrap()
-}
diff --git a/src/git/tree.rs b/src/git/tree.rs
index 457eb40..5343a57 100644
--- a/src/git/tree.rs
+++ b/src/git/tree.rs
@@ -57,6 +57,38 @@ impl Tree {
vec
})
}
+
+ /// Get all the commits that touch a file
+ pub(crate) fn grab_path_history(&self, mut 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)]
diff --git a/src/main.rs b/src/main.rs
index 7e589ec..a0d6dce 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -14,12 +14,6 @@ async fn main() -> io::Result<()> {
env_logger::init();
let root = PathBuf::new();
- let repo = git::repo::Repo::new(".");
- let commits = git::log::create_commit_log(
- "84a9a0ccee713e26a28ff5e54ea3776085d93b5f".into(),
- &repo.inner,
- );
-
HttpServer::new(move || {
App::new()
.service(fs::Files::new("/static", root.join("static")))