From 204eb55d23d186c138fb7cab18e6f6555352bda8 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Wed, 06 Jul 2022 11:46:31 +0100 Subject: [PATCH] Implement pagination on log view --- src/git.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- statics/style.css | 9 +++++++++ src/methods/repo.rs | 22 ++++++++++++++++++++++ templates/repo/log.html | 6 ++++++ templates/repo/refs.html | 27 ++++++++++++++++++++++----- 5 files changed, 87 insertions(+), 30 deletions(-) diff --git a/src/git.rs b/src/git.rs index a29fe9d..0f5ef48 100644 --- a/src/git.rs +++ a/src/git.rs @@ -7,25 +7,35 @@ }; use arc_swap::ArcSwapOption; -use git2::{Oid, Repository, Signature, Sort}; +use git2::{ObjectType, Oid, Repository, Signature}; +use moka::future::Cache; use time::OffsetDateTime; pub type RepositoryMetadataList = BTreeMap, Vec>; #[derive(Clone)] pub struct Git { - commits: moka::future::Cache>, - readme_cache: moka::future::Cache>, - refs: moka::future::Cache>, + commits: Cache>, + readme_cache: Cache>, + refs: Cache>, repository_metadata: Arc>, } impl Default for Git { fn default() -> Self { Self { - commits: moka::future::Cache::new(100), - readme_cache: moka::future::Cache::new(100), - refs: moka::future::Cache::new(100), + commits: Cache::builder() + .time_to_live(Duration::from_secs(10)) + .max_capacity(100) + .build(), + readme_cache: Cache::builder() + .time_to_live(Duration::from_secs(10)) + .max_capacity(100) + .build(), + refs: Cache::builder() + .time_to_live(Duration::from_secs(10)) + .max_capacity(100) + .build(), repository_metadata: Arc::new(ArcSwapOption::default()), } } @@ -69,11 +79,11 @@ commit: commit.into(), }); } else if ref_.is_tag() { - let commit = ref_.peel_to_commit().unwrap(); + let tag = ref_.peel_to_tag().unwrap(); built_refs.tag.push(Tag { name: ref_.shorthand().unwrap().to_string(), - commit: commit.into(), + tagger: tag.tagger().map(Into::into), }); } } @@ -143,22 +153,27 @@ repos } - pub async fn get_commits(&self, repo: PathBuf) -> Vec { + pub async fn get_commits(&self, repo: PathBuf, offset: usize) -> (Vec, Option) { + const AMOUNT: usize = 200; + tokio::task::spawn_blocking(move || { let repo = Repository::open_bare(repo).unwrap(); let mut revs = repo.revwalk().unwrap(); - revs.set_sorting(Sort::TIME).unwrap(); revs.push_head().unwrap(); - let mut commits = Vec::with_capacity(200); + let mut commits: Vec = revs + .skip(offset) + .take(AMOUNT + 1) + .map(|rev| { + let rev = rev.unwrap(); + repo.find_commit(rev).unwrap().into() + }) + .collect(); - for rev in revs.skip(0).take(200) { - let rev = rev.unwrap(); - let commit = repo.find_commit(rev).unwrap(); - commits.push(commit.into()); - } + // TODO: avoid having to take + 1 and popping the last commit off + let next_offset = commits.pop().is_some().then(|| offset + commits.len()); - commits + (commits, next_offset) }) .await .unwrap() @@ -185,7 +200,7 @@ #[derive(Debug)] pub struct Tag { pub name: String, - pub commit: Commit, + pub tagger: Option, } #[derive(Debug)] diff --git a/statics/style.css b/statics/style.css index f407288..c0e96ce 100644 --- a/statics/style.css +++ a/statics/style.css @@ -33,6 +33,10 @@ margin-top: 2rem; } +.text-center { + text-align: center; +} + .no-hover:hover { text-decoration: none; } @@ -50,6 +54,11 @@ table tbody tr.has-parent td:first-of-type { padding-left: 1rem; +} + +tr.separator { + background: white !important; + height: 1rem; } table pre { margin: 0; } diff --git a/src/methods/repo.rs b/src/methods/repo.rs index 6431dba..1de00d8 100644 --- a/src/methods/repo.rs +++ a/src/methods/repo.rs @@ -89,22 +89,40 @@ Html(View { repo }.render().unwrap()) } +#[derive(Deserialize)] +pub struct LogQuery { + #[serde(rename = "ofs")] + offset: Option, +} + #[allow(clippy::unused_async)] pub async fn handle_log( Extension(repo): Extension, Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension, + Query(query): Query, ) -> Html { #[derive(Template)] #[template(path = "repo/log.html")] pub struct View { repo: Repository, commits: Vec, + next_offset: Option, } - let commits = git.get_commits(repository_path).await; + let (commits, next_offset) = git + .get_commits(repository_path, query.offset.unwrap_or(0)) + .await; - Html(View { repo, commits }.render().unwrap()) + Html( + View { + repo, + commits, + next_offset, + } + .render() + .unwrap(), + ) } #[allow(clippy::unused_async)] diff --git a/templates/repo/log.html b/templates/repo/log.html index 47e73f4..ce9dd7a 100644 --- a/templates/repo/log.html +++ a/templates/repo/log.html @@ -25,4 +25,10 @@ {% endfor %} + +{% if let Some(next_offset) = next_offset %} +
+ [next] +
+{% endif %} {% endblock %}diff --git a/templates/repo/refs.html b/templates/repo/refs.html index dc8afc4..6ab2718 100644 --- a/templates/repo/refs.html +++ a/templates/repo/refs.html @@ -26,28 +26,37 @@ {% endfor %} - - - + + + + + + + + - - - {% for tag in refs.tag %} + {% for tag in refs.tag.iter().rev() %} + - {% endfor %} -- rgit 0.1.3
Tag Download Author Age
{{ tag.name }} + {% if let Some(tagger) = tag.tagger %} + + {{ tagger.name() }} + {% endif %} + - - {{ tag.commit.author().name() }} + {% if let Some(tagger) = tag.tagger %} + {{ tagger.time() }} + {% endif %} {{ tag.commit.author().time() }}