Repositories

grarr

(mirrored on github)

Wim Looman <wim@nemo157.com>
5b4176 Add pagination of commits
Wim Looman committed at 2016-03-06 12:29:26

Modified src/commit_tree.rs

@@ -3,6 +3,7 @@ use git2::{ self, Oid, Repository, Commit };
pub struct CommitTree<'repo> {
repo: &'repo Repository,
next_after: Option<Commit<'repo>>,
next: Option<Commit<'repo>>,
commits: IntoIter<Commit<'repo>>,
ignored: Vec<Oid>,
@@ -10,12 +11,14 @@ pub struct CommitTree<'repo> {
}
impl<'repo> CommitTree<'repo> {
pub fn new(repo: &'repo Repository, commit: &Commit<'repo>) -> Result<CommitTree<'repo>, git2::Error> {
pub fn new(repo: &'repo Repository, commit: &Commit<'repo>, limit: usize) -> Result<CommitTree<'repo>, git2::Error> {
let mut walker = try!(repo.revwalk());
try!(walker.push(commit.id()));
walker.simplify_first_parent();
let commits = try!(walker.map(|id| id.and_then(|id| repo.find_commit(id))).collect());
Ok(CommitTree::create(repo, commits, Vec::new()))
let mut all_commits = walker.map(|id| id.and_then(|id| repo.find_commit(id)));
let commits = try!((&mut all_commits).take(limit).collect());
let next_after = all_commits.next().and_then(|c| c.ok());
Ok(CommitTree::create(repo, commits, next_after, Vec::new()))
}
pub fn is_empty(&self) -> bool {
@@ -26,6 +29,10 @@ impl<'repo> CommitTree<'repo> {
self.len
}
pub fn next_after(&self) -> Option<&Commit<'repo>> {
self.next_after.as_ref()
}
fn between(repo: &'repo Repository, first: &Commit<'repo>, ignored: Vec<Oid>) -> CommitTree<'repo> {
let mut walker = repo.revwalk().unwrap();
for parent in first.parent_ids().skip(1) {
@@ -36,14 +43,15 @@ impl<'repo> CommitTree<'repo> {
}
walker.simplify_first_parent();
let commits = walker.map(|id| id.and_then(|id| repo.find_commit(id)).unwrap()).collect();
CommitTree::create(repo, commits, ignored)
CommitTree::create(repo, commits, None, ignored)
}
fn create(repo: &'repo Repository, commits: Vec<Commit<'repo>>, ignored: Vec<Oid>) -> CommitTree<'repo> {
fn create(repo: &'repo Repository, commits: Vec<Commit<'repo>>, next_after: Option<Commit<'repo>>, ignored: Vec<Oid>) -> CommitTree<'repo> {
let len = commits.len();
let mut iter = commits.into_iter();
CommitTree {
repo: repo,
next_after: next_after,
next: iter.next(),
commits: iter,
ignored: ignored,

Modified src/handler/commits.rs

@@ -1,5 +1,6 @@
use super::base::*;
use git2::Oid;
use commit_tree::CommitTree;
#[derive(Clone)]
@@ -8,8 +9,20 @@ pub struct Commits;
impl Handler for Commits {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
let context = itry!(req.extensions.get::<RepositoryContext>().ok_or(Error::MissingExtension), status::InternalServerError);
let start_commit = req.url.clone().into_generic_url()
.query_pairs()
.unwrap_or_default()
.into_iter()
.find(|&(ref key, _)| key == "start")
.map(|(_, ref id)| Oid::from_str(id)
.and_then(|id| context.repository.find_commit(id)));
let referenced_commit = itry!(context.referenced_commit(), status::InternalServerError);
let commits = itry!(CommitTree::new(&context.repository, &referenced_commit.commit), status::InternalServerError);
let initial_commit = if let Some(Ok(ref commit)) = start_commit {
commit
} else {
&referenced_commit.commit
};
let commits = itry!(CommitTree::new(&context.repository, &initial_commit, 50), status::InternalServerError);
Html {
render: RepositoryWrapper(&context, render::Commits(&("/".to_owned() + context.requested_path.to_str().unwrap()), &referenced_commit, commits)),
etag: Some(EntityTag::weak(versioned_sha1!(referenced_commit.commit.id().as_bytes()))),

Modified src/render/commit.rs

@@ -5,6 +5,7 @@ use maud_pulldown_cmark::Markdown;
use commit_tree;
use chrono::naive::datetime::NaiveDateTime;
use referenced_commit::ReferencedCommit;
use super::reference;
fn summary<'a>(commit: &'a git2::Commit<'a>) -> Option<&'a str> {
commit.message()
@@ -91,37 +92,83 @@ renderers! {
^CommitDetails(root, commit)
^super::DiffCommit(repo, commit)
}
NextPage(root: &'a str, commit: &'a ReferencedCommit<'a>, start: &'a git2::Commit<'a>) {
div.block div.block-header {
a href={
^root
"/commits/"
@match commit.reference.as_ref().and_then(|r| r.shorthand()) {
Some(ref reff) => ^reff,
None => ^commit.commit.id()
}
} {
"Back to beginning (" ^reference::Commit(&commit.commit) ")"
}
a.float-right href={
^root
"/commits/"
@match commit.reference.as_ref().and_then(|r| r.shorthand()) {
Some(ref reff) => ^reff,
None => ^commit.commit.id()
}
"?start=" ^start.id()
} {
"Next page (" ^reference::Commit(start) ")"
}
}
}
}
pub struct Commits<'repo, 'a>(pub &'a str, pub &'a ReferencedCommit<'a>, pub commit_tree::CommitTree<'repo>);
impl<'repo, 'a> RenderOnce for Commits<'repo, 'a> {
fn render_once(self, mut w: &mut fmt::Write) -> fmt::Result {
let Commits(root, commit, commits) = self;
let Commits(root, commit, mut commits) = self;
let first = commits.next();
let mut id = 0;
html!(w, {
div.block {
div.block-header {
h3 { "Commits for ref " ^super::Reference(commit) }
@if let Some((first, mut sub)) = first {
div.block {
div.block-header {
h3 {
"Commits for ref " ^super::Reference(commit)
@if first.id() != commit.commit.id() {
small { " (showing from " ^reference::Commit(&first) ")" }
}
}
}
}
^CommitStub(root, &first)
@if !sub.is_empty() {
div.subtree {
input.expander disabled?=(sub.len() == 1) id={ "commits-expander-" ^id } type="checkbox" checked? { }
label for={ "commits-expander-" ^id } { i.fa.fa-fw.chevron {} }
^CommitTree(root, &mut sub, &mut id)
}
}
^CommitTree(root, &mut commits, &mut id)
@if let Some(next) = commits.next_after() {
^NextPage(root, commit, next)
}
}
^CommitTree(root, commits, &mut 0)
})
}
}
pub struct CommitTree<'repo, 'a>(pub &'a str, pub commit_tree::CommitTree<'repo>, pub &'a mut u32);
pub struct CommitTree<'a, 'repo: 'a>(pub &'a str, pub &'a mut commit_tree::CommitTree<'repo>, pub &'a mut u32);
impl<'repo, 'a> RenderOnce for CommitTree<'repo, 'a> {
fn render_once(self, mut w: &mut fmt::Write) -> fmt::Result {
let CommitTree(root, commits, id) = self;
*id = *id + 1;
html!(w, {
div.commits {
@for (commit, sub) in commits {
@for (commit, mut sub) in commits {
^CommitStub(root, &commit)
@if !sub.is_empty() {
div.subtree {
input.expander disabled?=(sub.len() == 1) id={ "commits-expander-" ^id } type="checkbox" checked? { }
label for={ "commits-expander-" ^id } { i.fa.fa-fw.chevron {} }
^CommitTree(root, sub, id)
^CommitTree(root, &mut sub, id)
}
}
}