Repositories

grarr

(mirrored on github)

Modified src/handler/blob.rs

@@ -1,5 +1,5 @@
use super::base::*;
use super::tree_entry;
use tree_entry;
use git2;
use std::path::Path;
@@ -18,13 +18,7 @@ impl Handler for Blob {
match entry.entry.kind() {
Some(git2::ObjectType::Blob) => {
Html {
render: RepositoryWrapper(
&context,
&render::Blob(
&entry.parent,
Path::new(path),
itry!(entry.entry.as_blob().ok_or(Error::from("Wat?")), status::InternalServerError),
&referenced_commit)),
render: RepositoryWrapper(&context, &render::Blob(entry.entry.as_blob().unwrap(), &entry)),
etag: Some(EntityTag::weak(versioned_sha1!(&id))),
req: req,
}.into()

Modified src/handler/mod.rs

@@ -15,7 +15,6 @@ mod repositories;
mod html;
mod base;
pub mod error;
mod tree_entry;
mod settings;
mod about;
mod tree;

Modified src/handler/tree.rs

@@ -1,5 +1,5 @@
use super::base::*;
use super::tree_entry;
use tree_entry;
use git2;
use std::path::Path;
@@ -11,21 +11,12 @@ impl Handler for Tree {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
let router = itry!(req.extensions.get::<Router>().ok_or(Error::MissingExtension), status::InternalServerError);
let context = itry!(req.extensions.get::<RepositoryContext>().ok_or(Error::MissingExtension), status::InternalServerError);
let path = router.find("path").unwrap_or("");
let entry = try!(tree_entry::get_tree_entry(&context, path));
let referenced_commit = itry!(context.referenced_commit(), status::NotFound);
let id = referenced_commit.commit.id();
let entry = try!(tree_entry::get_tree_entry(&context, router.find("path").unwrap_or("")));
match entry.entry.kind() {
Some(git2::ObjectType::Tree) => {
Html {
render: RepositoryWrapper(
&context,
&render::Tree(
&entry.parent,
Path::new(path),
itry!(entry.entry.as_tree().ok_or(Error::from("Wat?")), status::InternalServerError),
&referenced_commit)),
etag: Some(EntityTag::weak(versioned_sha1!(&id))),
render: RepositoryWrapper(&context, &render::Tree(entry.entry.as_tree().unwrap(), &entry)),
etag: Some(EntityTag::weak(versioned_sha1!(&entry.commit.commit.id()))),
req: req,
}.into()
},

Deleted src/handler/tree_entry.rs

@@ -1,28 +0,0 @@
use iron::{ status, IronResult };
use std::path::Path;
use repository_context::RepositoryContext;
use git2;
pub struct TreeEntryContext<'a> {
pub entry: git2::Object<'a>,
pub parent: String,
}
pub fn get_tree_entry<'a>(context: &'a RepositoryContext, path: &str) -> IronResult<TreeEntryContext<'a>> {
let referenced_commit = itry!(context.referenced_commit(), status::NotFound);
let tree = itry!(referenced_commit.commit.tree(), status::InternalServerError);
let entry = if path == "" {
itry!(context.repository.find_object(tree.id(), Some(git2::ObjectType::Tree)))
} else {
let tree_entry = itry!(tree.get_path(Path::new(path)), status::NotFound);
itry!(tree_entry.to_object(&context.repository), status::InternalServerError)
};
let id = referenced_commit.commit.id();
let idstr = format!("{}", id);
let reff = referenced_commit.reference.as_ref().and_then(|r| r.shorthand()).unwrap_or(&*idstr);
let parent = "/".to_owned() + &context.requested_path.to_string_lossy() + "/tree/" + reff;
Ok(TreeEntryContext {
entry: entry,
parent: parent,
})
}

Modified src/main.rs

@@ -45,6 +45,7 @@ mod repository_extension;
mod settings;
mod referenced_commit;
mod config;
mod tree_entry;
use std::env;
use iron::prelude::*;

Modified src/render/tree.rs

@@ -5,26 +5,35 @@ use super::fa::{ FA, FAM };
use git2::{ self, ObjectType };
use std::path::{ self, Path, Component };
use referenced_commit::ReferencedCommit;
use tree_entry::TreeEntryContext;
renderers! {
TreeEntryStub(root: &'a str, entry: &'a git2::TreeEntry<'a>) {
TreeEntryStub(parent: &'a TreeEntryContext<'a>, entry: &'a git2::TreeEntry<'a>) {
@if let Some(name) = entry.name() {
li {
@match entry.kind() {
Some(ObjectType::Tree) => ^FAM::Li(FA::Sitemap),
Some(ObjectType::Blob) => ^FAM::Li(FA::File),
_ => ^FAM::Li(FA::Question),
Some(ObjectType::Tree) => {
^FAM::Li(FA::Sitemap)
a href={ "/" ^parent.repo_path "/tree/" ^parent.reff ^parent.entry_path.trim_right_matches('/') "/" ^name } { ^name }
},
Some(ObjectType::Blob) => {
^FAM::Li(FA::File)
a href={ "/" ^parent.repo_path "/blob/" ^parent.reff ^parent.entry_path.trim_right_matches('/') "/" ^name } { ^name }
},
_ => {
^FAM::Li(FA::Question)
^name
},
}
a href={ ^root "/" ^name } { ^name }
}
}
}
TreeEntry(root: &'a str, path: &'a Path, entry: &'a git2::Object<'a>, commit: &'a ReferencedCommit<'a>) {
TreeEntry(context: &'a TreeEntryContext<'a>) {
div {
@match entry.kind() {
Some(ObjectType::Tree) => ^Tree(root, path, entry.as_tree().unwrap(), commit),
Some(ObjectType::Blob) => ^Blob(root, path, entry.as_blob().unwrap(), commit),
@match context.entry.kind() {
Some(ObjectType::Tree) => ^Tree(context.entry.as_tree().unwrap(), context),
Some(ObjectType::Blob) => ^Blob(context.entry.as_blob().unwrap(), context),
Some(ObjectType::Tag) => "Can't render ObjectType::Tag yet",
Some(ObjectType::Commit) => "Can't render ObjectType::Commit yet",
Some(ObjectType::Any) => "Can't render ObjectType::Any yet",
@@ -33,43 +42,43 @@ renderers! {
}
}
Tree(root: &'a str, path: &'a Path, tree: &'a git2::Tree<'a>, commit: &'a ReferencedCommit<'a>) {
Tree(tree: &'a git2::Tree<'a>, context: &'a TreeEntryContext<'a>) {
div.block {
div.block-header {
h2 {
^FAM::FixedWidth(FA::File) " "
span.path ^Components(root, path.components())
span.path ^Components(context, false)
" at "
^super::Reference(commit)
^super::Reference(&context.commit)
}
}
div.block-details {
ul.fa-ul {
@if path != Path::new("") {
li { ^FAM::Li(FA::LevelUp) a href=^((root.to_owned() + "/" + path.parent().and_then(|p| p.to_str()).unwrap_or("")).trim_right_matches('/')) ".." }
@if let Some(parent) = context.parent() {
li { ^FAM::Li(FA::LevelUp) a href={ "/" ^context.repo_path "/tree/" ^context.reff ^parent } { ".." } }
}
@for entry in tree.iter().collect::<Vec<_>>().tap(|v| v.sort_by_key(|e| Sorter(e.kind()))) {
^TreeEntryStub(&(root.to_owned() + "/" + path.to_str().unwrap()).trim_right_matches('/'), &entry)
^TreeEntryStub(context, &entry)
}
}
}
}
}
Blob(root: &'a str, path: &'a Path, blob: &'a git2::Blob<'a>, commit: &'a ReferencedCommit<'a>) {
Blob(blob: &'a git2::Blob<'a>, context: &'a TreeEntryContext<'a>) {
div.block {
div.block-header {
h2 {
^FAM::FixedWidth(FA::File) " "
span.path ^Components(root, path.components())
span.path ^Components(context, true)
" at "
^super::Reference(commit)
^super::Reference(&context.commit)
}
}
pre.block-details {
@match blob.is_binary() {
true => code { "Binary file" },
false => code class={ "hljs lang-" ^path.extension().map(|s| s.to_string_lossy().into_owned()).unwrap_or("".to_owned()) } {
false => code class={ "hljs lang-" ^context.extension().unwrap_or("") } {
@for (i, line) in str::from_utf8(blob.content()).unwrap().lines().enumerate() {
div.line data-line-num=^(format!("{: >4}", i + 1)) {
span.text ^line
@@ -83,16 +92,24 @@ renderers! {
}
}
pub struct Components<'a>(&'a str, pub path::Components<'a>);
pub struct Components<'a>(pub &'a TreeEntryContext<'a>, pub bool);
impl<'a> ::maud::RenderOnce for Components<'a> {
fn render_once(self, mut w: &mut fmt::Write) -> fmt::Result {
let mut root = self.0.to_owned();
try!(html!(w, { a.path-component href={ ^root } "<root>" }));
for component in self.1 {
if let Component::Normal(component) = component {
try!(html!(w, { "/" a.path-component href={ ^root "/" ^component.to_str().unwrap() } ^component.to_str().unwrap() }));
root = root + "/" + component.to_str().unwrap();
let Components(context, is_blob) = self;
try!(html!(w, { a.path-component href={ "/" ^context.repo_path "/tree/" ^context.reff } ^context.repo_path }));
let mut parent = "/".to_owned();
let components: Vec<_> = context.entry_path.split_terminator('/').collect();
for i in 0..components.len() {
let component = components[i];
if component == "" {
continue;
} else if is_blob && i == components.len() - 1 {
try!(html!(w, { "/" a.path-component href={ "/" ^context.repo_path "/blob/" ^context.reff ^parent ^component } ^component }));
} else {
try!(html!(w, { "/" a.path-component href={ "/" ^context.repo_path "/tree/" ^context.reff ^parent ^component } ^component }));
parent.push_str(component);
parent.push('/');
}
}
Ok(())

Added src/tree_entry.rs

@@ -0,0 +1,56 @@
use std::borrow::Cow;
use iron::{ status, IronResult };
use std::path::Path;
use repository_context::RepositoryContext;
use git2;
use referenced_commit::ReferencedCommit;
pub struct TreeEntryContext<'a> {
pub entry: git2::Object<'a>,
pub repo_path: Cow<'a, str>,
pub entry_path: String,
pub reff: String,
pub commit: ReferencedCommit<'a>,
}
impl<'a> TreeEntryContext<'a> {
pub fn extension(&self) -> Option<&str> {
self.entry_path
.rfind('.')
.and_then(|i|
if i + 1 == self.entry_path.len() || (&self.entry_path[i+1..]).contains('/') {
None
} else {
Some(&self.entry_path[i+1..])
})
}
pub fn parent(&self) -> Option<&str> {
if self.entry_path == "/" {
None
} else {
Some(&self.entry_path[..self.entry_path.rfind('/').unwrap_or(0)])
}
}
}
pub fn get_tree_entry<'a>(context: &'a RepositoryContext, path: &'a str) -> IronResult<TreeEntryContext<'a>> {
let referenced_commit = itry!(context.referenced_commit(), status::NotFound);
let tree = itry!(referenced_commit.commit.tree(), status::InternalServerError);
let entry = if path == "" {
itry!(context.repository.find_object(tree.id(), Some(git2::ObjectType::Tree)))
} else {
let tree_entry = itry!(tree.get_path(Path::new(path)), status::NotFound);
itry!(tree_entry.to_object(&context.repository), status::InternalServerError)
};
let id = referenced_commit.commit.id();
let idstr = format!("{}", id);
let reff = referenced_commit.reference.as_ref().and_then(|r| r.shorthand()).unwrap_or(&*idstr).to_owned();
Ok(TreeEntryContext {
entry: entry,
repo_path: context.requested_path.to_string_lossy(),
entry_path: "/".to_owned() + path,
reff: reff,
commit: referenced_commit,
})
}