diff options
author | Martin Fischer <martin@push-f.com> | 2021-06-24 11:47:48 +0200 |
---|---|---|
committer | Martin Fischer <martin@push-f.com> | 2021-06-24 11:49:25 +0200 |
commit | d24f51baf6e4e97e6f3e9ff3ce83274f353e82f9 (patch) | |
tree | c605de9066d6297655b1bceb47db2a64f96fbf94 | |
parent | de3437e4a2b357c9774dbef37ee7f76f50a3fabf (diff) |
log: allow diffing specific revisions
-rw-r--r-- | src/get_routes.rs | 98 | ||||
-rw-r--r-- | src/static/style.css | 5 | ||||
-rw-r--r-- | src/static/style.css.sha256 | 2 |
3 files changed, 72 insertions, 33 deletions
diff --git a/src/get_routes.rs b/src/get_routes.rs index 73c9301..17b7941 100644 --- a/src/get_routes.rs +++ b/src/get_routes.rs @@ -1,7 +1,9 @@ use chrono::NaiveDateTime; +use git2::Commit; use git2::FileMode; use git2::ObjectType; use git2::Oid; +use git2::Repository; use git2::Tree; use git2::TreeEntry; use hyper::header; @@ -166,7 +168,10 @@ fn log_blob<C: Controller>( // the very first commit of the branch commits.push(prev_commit); } - page.body.push_str("<div>"); + page.body.push_str( + "<form><input type=hidden name=action value=diff>\ + <button>Compare selected revisions</button>", + ); let mut prev_date = None; for c in commits { let date = NaiveDateTime::from_timestamp(c.time().seconds(), 0).date(); @@ -175,50 +180,71 @@ fn log_blob<C: Controller>( page.body.push_str("</ul>"); } page.body.push_str(&format!( - "<h2 class=regular-text>{}</h2><ul>", + "<h2 class=regular-text>{}</h2><ul class=rev-list>", date.format("%b %d, %Y") )); } page.body.push_str(&format!( - "<li><a href='?action=diff&id={}'>{}: {}</a></li>", + "<li>\ + <input type=radio name=oldid required value={0}>\ + <input type=radio name=id required value={0}> ", + c.id().to_string() + )); + page.body.push_str(&format!( + "<a href='?action=diff&id={}'>{}: {}</a></li>", html_escape(c.id().to_string()), html_escape(c.author().name().unwrap_or_default()), html_escape(c.summary().unwrap_or_default()), )); prev_date = Some(date); } - page.body.push_str("</ul></div>"); + page.body.push_str("</ul></form>"); Ok(page.into()) } #[derive(Deserialize)] -struct DiffParam { +struct DiffParams { id: String, + oldid: Option<String>, +} + +fn find_commit<'a>(repo: &'a Repository, id: &str, branch_head: &Oid) -> Option<Commit<'a>> { + let oid = Oid::from_str(id).ok()?; + repo.find_commit(oid) + .ok() + // disallow viewing commits from other branches you shouldn't have access to + .filter(|c| oid == *branch_head || repo.graph_descendant_of(*branch_head, c.id()).unwrap()) } fn diff_blob<C: Controller>( _entr: TreeEntry, - params: ActionParam, + action_param: ActionParam, controller: &C, ctx: Context, ) -> Result<Response, Error> { - let param: DiffParam = ctx.parts.query()?; + let params: DiffParams = ctx.parts.query()?; let branch_commit = ctx.branch_head()?; - let commit = ctx - .repo - .find_commit(Oid::from_str(¶m.id)?) - .map_err(|_| Error::NotFound("commit not found".into()))?; + let mut commit = find_commit(&ctx.repo, ¶ms.id, &branch_commit.id()) + .ok_or_else(|| Error::NotFound("commit not found".into()))?; - if branch_commit.id() != commit.id() - && !ctx - .repo - .graph_descendant_of(branch_commit.id(), commit.id())? - { - // disallow viewing commits from other branches you shouldn't have access to - return Err(Error::NotFound("commit not found".into())); - } + let old_commit = if let Some(oldid) = ¶ms.oldid { + let other_commit = find_commit(&ctx.repo, &oldid, &branch_commit.id()) + .ok_or_else(|| Error::NotFound("commit not found".into()))?; + + if other_commit.time() > commit.time() { + // TODO: redirect instead + let c = commit; + commit = other_commit; + Some(c) + } else { + Some(other_commit) + } + } else { + // TODO: what if there are multiple parents? + commit.parents().next() + }; let blob_id = if let Ok(entry) = commit.tree()?.get_path(&ctx.path) { entry.id() @@ -226,36 +252,44 @@ fn diff_blob<C: Controller>( return Ok(Page { title: format!("Commit for {}", ctx.file_name().unwrap()), body: "file removed".into(), - header: Some(action_links(¶ms.action, controller, &ctx)), + header: Some(action_links(&action_param.action, controller, &ctx)), controller, parts: &ctx.parts, } .into()); }; - // TODO: what if there are multiple parents? - let old_blob_id = commit - .parents() - .next() + let old_blob_id = old_commit .and_then(|p| p.tree().unwrap().get_path(&ctx.path).ok()) .map(|e| e.id()); if Some(blob_id) == old_blob_id { - return Err(Error::NotFound("commit not found".into())); + return Err(Error::NotFound("no difference".into())); } let mut page = Page { - title: format!("Commit for {}", ctx.file_name().unwrap()), - header: Some(action_links(¶ms.action, controller, &ctx)), - body: format!( - "<h1>{}</h1>{} committed on {}", - html_escape(commit.summary().unwrap_or_default()), - html_escape(commit.author().name().unwrap_or_default()), - NaiveDateTime::from_timestamp(commit.time().seconds(), 0).format("%b %d, %Y, %H:%M") + title: format!( + "{} for {}", + if params.oldid.is_some() { + "Diff" + } else { + "Commit" + }, + ctx.file_name().unwrap() ), + header: Some(action_links(&action_param.action, controller, &ctx)), + body: String::new(), controller, parts: &ctx.parts, }; + if params.oldid.is_none() { + page.body.push_str(&format!( + "<h1>{}</h1>{} committed on {}", + html_escape(commit.summary().unwrap_or_default()), + html_escape(commit.author().name().unwrap_or_default()), + NaiveDateTime::from_timestamp(commit.time().seconds(), 0).format("%b %d, %Y, %H:%M") + )); + } // TODO: if UTF-8 decoding fails, link ?action=raw&rev= if let Some(old_blob_id) = old_blob_id { diff --git a/src/static/style.css b/src/static/style.css index a91b9df..0733d56 100644 --- a/src/static/style.css +++ b/src/static/style.css @@ -81,6 +81,11 @@ label { font-weight: inherit; } +.rev-list { + list-style: none; + padding-left: 0; +} + .addition { background: #e6ffed; } .deletion { background: #ffeef0; } .addition ins {background: #acf2bd; text-decoration: none; } diff --git a/src/static/style.css.sha256 b/src/static/style.css.sha256 index 434cce7..17a3812 100644 --- a/src/static/style.css.sha256 +++ b/src/static/style.css.sha256 @@ -1 +1 @@ -nNLYarzU1i7D9yDyQw5R+15yNbfgxY838qGt/MH3I0E=
\ No newline at end of file +pVajQAgXar+xHqEuGZsATyQGTVFvnr82Sf28zZ3g4e0=
\ No newline at end of file |