From 873752f5abeaa212742551fafd67d66f7c0938ae Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Wed, 06 Jul 2022 02:45:18 +0100 Subject: [PATCH] Implement repository refs page --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/git.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ statics/style.css | 4 ++++ src/methods/repo.rs | 14 ++++++++++++-- templates/repo/refs.html | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b7d73e..a9eda85 100644 --- a/Cargo.lock +++ a/Cargo.lock @@ -753,6 +753,12 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1071,6 +1077,7 @@ "git2", "hex", "humantime", + "md5", "moka", "path-clean", "serde", diff --git a/Cargo.toml b/Cargo.toml index 9db11b0..9cc8330 100644 --- a/Cargo.toml +++ a/Cargo.toml @@ -14,6 +14,7 @@ git2 = "0.14" hex = "0.4" humantime = "2.1" +md5 = "0.7" moka = { version = "0.9", features = ["future"] } path-clean = "0.1" serde = { version = "1.0", features = ["derive"] } diff --git a/src/git.rs b/src/git.rs index 943206f..090277e 100644 --- a/src/git.rs +++ a/src/git.rs @@ -16,6 +16,7 @@ pub struct Git { commits: moka::future::Cache>, readme_cache: moka::future::Cache>, + refs: moka::future::Cache>, repository_metadata: Arc>, } @@ -24,6 +25,7 @@ Self { commits: moka::future::Cache::new(100), readme_cache: moka::future::Cache::new(100), + refs: moka::future::Cache::new(100), repository_metadata: Arc::new(ArcSwapOption::default()), } } @@ -47,6 +49,43 @@ .await } + pub async fn get_refs<'a>(&'a self, repo: PathBuf) -> Arc { + self.refs + .get_with(repo.clone(), async { + tokio::task::spawn_blocking(move || { + let repo = git2::Repository::open_bare(repo).unwrap(); + let refs = repo.references().unwrap(); + + let mut built_refs = Refs::default(); + + for ref_ in refs { + let ref_ = ref_.unwrap(); + + if ref_.is_branch() { + let commit = ref_.peel_to_commit().unwrap(); + + built_refs.branch.push(Branch { + name: ref_.shorthand().unwrap().to_string(), + commit: commit.into(), + }); + } else if ref_.is_tag() { + let commit = ref_.peel_to_commit().unwrap(); + + built_refs.tag.push(Tag { + name: ref_.shorthand().unwrap().to_string(), + commit: commit.into(), + }); + } + } + + Arc::new(built_refs) + }) + .await + .unwrap() + }) + .await + } + pub async fn get_readme(&self, repo: PathBuf) -> Arc { self.readme_cache .get_with(repo.clone(), async { @@ -99,6 +138,29 @@ repos } +} + +#[derive(Debug, Default)] +pub struct Refs { + pub branch: Vec, + pub tag: Vec, +} + +#[derive(Debug)] +pub struct Branch { + pub name: String, + pub commit: Commit, +} + +#[derive(Debug)] +pub struct Remote { + pub name: String, +} + +#[derive(Debug)] +pub struct Tag { + pub name: String, + pub commit: Commit, } #[derive(Debug)] @@ -109,9 +171,11 @@ pub last_modified: Duration, } +#[derive(Debug)] pub struct CommitUser { name: String, email: String, + email_md5: String, time: String, } @@ -120,6 +184,7 @@ CommitUser { name: v.name().unwrap().to_string(), email: v.email().unwrap().to_string(), + email_md5: format!("{:x}", md5::compute(v.email_bytes())), time: OffsetDateTime::from_unix_timestamp(v.when().seconds()) .unwrap() .to_string(), @@ -134,6 +199,10 @@ pub fn email(&self) -> &str { &self.email + } + + pub fn email_md5(&self) -> &str { + &self.email_md5 } pub fn time(&self) -> &str { @@ -141,6 +210,7 @@ } } +#[derive(Debug)] pub struct Commit { author: CommitUser, committer: CommitUser, diff --git a/statics/style.css b/statics/style.css index 57cb54c..7a84891 100644 --- a/statics/style.css +++ a/statics/style.css @@ -29,6 +29,10 @@ text-decoration: underline; } +.mt-2 { + margin-top: 2rem; +} + table { border-collapse: collapse; } table.repositories { width: 100%; } table.repositories a { color: black; } diff --git a/src/methods/repo.rs b/src/methods/repo.rs index 3926eff..7c9fe50 100644 --- a/src/methods/repo.rs +++ a/src/methods/repo.rs @@ -17,6 +17,7 @@ use tower::{util::BoxCloneService, Service}; use crate::{git::Commit, layers::UnwrapInfallible, Git}; +use crate::git::Refs; #[derive(Clone)] pub struct Repository(pub PathBuf); @@ -100,21 +101,28 @@ } #[allow(clippy::unused_async)] -pub async fn handle_refs(Extension(repo): Extension) -> Html { +pub async fn handle_refs( + Extension(repo): Extension, + Extension(RepositoryPath(repository_path)): Extension, + Extension(git): Extension, +) -> Html { #[derive(Template)] #[template(path = "repo/refs.html")] pub struct View { repo: Repository, + refs: Arc, } - Html(View { repo }.render().unwrap()) + let refs = git.get_refs(repository_path).await; + + Html(View { repo, refs }.render().unwrap()) } #[allow(clippy::unused_async)] pub async fn handle_about( Extension(repo): Extension, Extension(RepositoryPath(repository_path)): Extension, - Extension(git): Extension + Extension(git): Extension, ) -> Html { #[derive(Template)] #[template(path = "repo/about.html")] diff --git a/templates/repo/refs.html b/templates/repo/refs.html index efdfb77..dc8afc4 100644 --- a/templates/repo/refs.html +++ a/templates/repo/refs.html @@ -1,6 +1,55 @@ {% extends "repo/base.html" %} {% block refs_nav_class %}active{% endblock %} {% block content %} + + + + + + + + + + + + {% for branch in refs.branch %} + + + + + + + {% endfor %} + +
BranchCommit messageAuthorAge
{{ branch.name }}{{ branch.commit.summary() }} + + {{ branch.commit.author().name() }} + {{ branch.commit.author().time() }}
+ + + + + + + + + + + + + {% for tag in refs.tag %} + + + + + + + {% endfor %} + +
TagDownloadAuthorAge
{{ tag.name }} + + {{ tag.commit.author().name() }} + {{ tag.commit.author().time() }}
{% endblock %}-- rgit 0.1.3