Repositories

grarr

(mirrored on github)

Modified Cargo.lock

@@ -21,6 +21,7 @@ dependencies = [
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -684,6 +685,15 @@ dependencies = [
]
[[package]]
name = "walkdir"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"

Modified Cargo.toml

@@ -16,6 +16,7 @@ typemap = "*"
mime = "*"
lru_time_cache = "*"
time = "*"
walkdir = "*"
chrono = "*"
pulldown-cmark = "*"

Modified src/handler/repositories.rs

@@ -1,58 +1,47 @@
use super::base::*;
use std::fs;
use std::path::PathBuf;
use git2::Repository;
use repository_tree::RepositoryTreeEntry;
use git2;
use walkdir::{ WalkDir, DirEntry, WalkDirIterator };
use std::path::{ Path, PathBuf };
#[derive(Clone)]
pub struct Repositories {
pub root: PathBuf,
}
fn get_repos(root: &PathBuf, dir: &PathBuf) -> Option<Vec<RepositoryTreeEntry>> {
fs::read_dir(dir).ok()
.and_then(|entries| {
let result: Vec<_> = entries.filter_map(|entry| {
entry.ok().and_then(|entry| {
entry.file_name().into_string().ok().and_then(|filename| {
entry.file_type().ok().and_then(|ty| {
if ty.is_dir() || (ty.is_symlink() && fs::metadata(entry.path()).map(|meta| meta.is_dir()).unwrap_or(false)) {
Repository::open(entry.path()).ok()
.map(|repo| {
let actual = fs::canonicalize(&entry.path()).unwrap_or(entry.path());
if actual == entry.path() {
RepositoryTreeEntry::Repo(filename.clone(), repo)
} else {
let actual = actual.strip_prefix(root).ok().and_then(|stripped| stripped.to_str().map(|s| s.to_owned()));
match actual {
Some(actual) => RepositoryTreeEntry::Alias(filename.clone(), actual),
None => RepositoryTreeEntry::Repo(filename.clone(), repo),
}
}
})
.or_else(|| get_repos(root, &entry.path()).map(|repos| RepositoryTreeEntry::Dir(filename, repos)))
} else {
None
}
})
})
})
}).collect();
if result.is_empty() {
None
} else {
Some(result)
fn get_repo(root: &Path, dir: DirEntry) -> Option<(String, git2::Repository)> {
let path = dir.path();
let relative_dir = expect!(path.strip_prefix(root).ok());
let relative = expect!(relative_dir.to_str()).to_owned();
let repo = expect!(git2::Repository::open(&path).ok());
Some((relative, repo))
}
fn get_repos(root: &Path) -> Vec<(String, git2::Repository)> {
let mut repos = Vec::new();
let mut it = WalkDir::new(root).into_iter();
loop {
let entry = match it.next() {
None => break,
Some(Err(_)) => continue,
Some(Ok(entry)) => entry,
};
if entry.file_type().is_dir() {
if let Some(repo) = get_repo(root, entry) {
repos.push(repo);
it.skip_current_dir();
}
})
}
}
repos
}
impl Handler for Repositories {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
let root = fs::canonicalize(&self.root).unwrap_or(self.root.clone());
let repos = get_repos(&root, &root).unwrap_or_default();
let repos = get_repos(&self.root);
Html {
render: Wrapper(&render::Repositories("", &repos)),
render: Wrapper(render::Repositories(repos)),
etag: None,
req: req,
}.into()

Modified src/main.rs

@@ -26,6 +26,7 @@ extern crate time;
extern crate pulldown_cmark;
extern crate crypto;
extern crate unicase;
extern crate walkdir;
#[macro_use]
mod macros;
@@ -35,7 +36,6 @@ pub mod render;
#[macro_use]
pub mod handler;
mod error;
mod repository_tree;
mod commit_tree;
mod repository_context;
mod repository_extension;
@@ -49,7 +49,6 @@ use handler::Register;
use time::Duration;
use repository_context::inject_repository_context;
pub use repository_tree::RepositoryTreeEntry;
pub use repository_context::RepositoryContext;
pub use repository_extension::RepositoryExtension;

Modified src/render/fa.rs

@@ -17,6 +17,7 @@ pub enum FA {
pub enum FAM {
Li(FA),
FixedWidth(FA),
X(u8, FA),
}
impl FA {
@@ -37,8 +38,9 @@ impl FA {
impl FAM {
fn class(self) -> String {
match self {
FAM::Li(fa) => "fa-li ".to_owned() + fa.class(),
FAM::FixedWidth(fa) => "fa-fw ".to_owned() + fa.class(),
FAM::Li(fa) => format!("fa-li {}", fa.class()),
FAM::FixedWidth(fa) => format!("fa-fw {}", fa.class()),
FAM::X(mul, fa) => format!("fa-fw fa-{}x {}", mul, fa.class()),
}
}
}

Modified src/render/mod.rs

@@ -30,7 +30,7 @@ pub use self::ci_status::{ CIStatus };
pub use self::analysis::{ Analysis };
pub use self::avatar::{ Avatar };
pub use self::commit::{ Commit, Commits };
pub use self::repository::{ Repository, Repositories };
pub use self::repository::{ Repository, Repositories, RepositoryHeader };
pub use self::repository_wrapper::{ RepositoryWrapper };
pub use self::error::{ Error };
pub use self::tree::{ TreeEntry };

Modified src/render/repository.rs

@@ -4,7 +4,7 @@ use pulldown_cmark::{ Parser, html, Event, Tag };
use maud::{ PreEscaped };
use maud_pulldown_cmark::Markdown;
use super::fa::{ FA, FAM };
use { RepositoryTreeEntry, RepositoryExtension };
use { RepositoryExtension };
fn find_readme(head_id: Oid, repo: &git2::Repository) -> Option<String> {
let head = try_expect!(repo.find_commit(head_id));
@@ -47,62 +47,52 @@ renderers! {
}
}
RepositoryStub(path: &'a str, name: &'a str, repo: &'a git2::Repository) {
li.repo-stub {
@match repo.origin_url() {
Some(_) => ^FAM::Li(FA::CodeFork),
None => ^FAM::Li(FA::Home),
}
a href={ ^path "/" ^name } {
^name
RepositoryIcon(mul: &'a u8, repo: &'a git2::Repository) {
@match repo.origin_url() {
Some(_) => ^FAM::X(*mul, FA::CodeFork),
None => ^FAM::X(*mul, FA::Home),
}
}
RepositoryHeader(path: &'a str, repo: &'a git2::Repository) {
div.block-header {
div.row.center {
^RepositoryIcon(&3, repo)
div.column {
h1 { a href={ "/" ^path } { ^path } }
@if let Some(origin) = repo.origin_url() {
h4 { "(fork of " ^super::MaybeLink(&origin, &origin) ")" }
}
}
}
@if let Some(origin) = repo.origin_url() {
" "
small {
"(fork of " ^super::MaybeLink(&origin, &origin) ")"
}
}
RepositoryStub(path: &'a str, repo: &'a git2::Repository) {
div.block {
div.block-header {
div.row.center {
^RepositoryIcon(&2, repo)
div.column {
h3 { a href={ "/" ^path } { ^path } }
@if let Some(origin) = repo.origin_url() {
h6 { "(fork of " ^super::MaybeLink(&origin, &origin) ")" }
}
}
}
}
@if let Some(description) = description(repo) {
blockquote {
div.block-details {
^PreEscaped(description)
}
}
}
}
Repositories(path: &'a str, repos: &'a Vec<RepositoryTreeEntry>) {
Repositories(repos: Vec<(String, git2::Repository)>) {
h1 { "Repositories" }
^RepositoriesList(path, repos)
}
RepositoriesList(path: &'a str, repos: &'a Vec<RepositoryTreeEntry>) {
ul.fa-ul {
@for entry in repos {
@match *entry {
RepositoryTreeEntry::Dir(ref name, ref repos) => {
li {
^FAM::Li(FA::Sitemap)
^name
^RepositoriesList(&*(path.to_owned() + "/" + name), repos)
}
},
RepositoryTreeEntry::Alias(ref alias, ref actual) => {
li {
^FAM::Li(FA::Tag)
a href={ ^path "/" ^alias } {
^alias
}
" alias of "
a href=^actual {
^actual
}
}
},
RepositoryTreeEntry::Repo(ref name, ref repo) => {
^RepositoryStub(path, name, repo)
},
}
}
@for (path, repo) in repos {
^RepositoryStub(&path, &repo)
}
}
}

Modified src/render/repository_wrapper.rs

@@ -1,7 +1,7 @@
use std::fmt;
use maud::RenderOnce;
use super::fa::{ FA };
use { RepositoryContext, RepositoryExtension };
use { RepositoryContext };
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Tab {
@@ -32,30 +32,12 @@ impl<'a, R: RenderOnce + RepositoryTab> RenderOnce for RepositoryWrapper<'a, R>
fn render_once(self, mut w: &mut fmt::Write) -> fmt::Result {
let tab = R::tab();
let RepositoryWrapper(context, content) = self;
let requested_path = context.requested_path.to_string_lossy().into_owned();
let canonical_path = context.canonical_path.to_string_lossy().into_owned();
let path = context.requested_path.to_string_lossy().into_owned();
html!(w, {
^FA::LevelUp " " a href="/" { "Repositories" }
div.repository-header {
h1 {
@match context.repository.origin_url() {
Some(_) => ^FA::CodeFork,
None => ^FA::Home,
}
" "
a href={ "/" ^requested_path } { ^requested_path }
}
@if requested_path != canonical_path {
h4 {
"(alias of " a href={ "/" ^canonical_path } { ^canonical_path } ")"
}
}
@if let Some(origin) = context.repository.origin_url() {
h4 {
"(fork of " ^super::MaybeLink(&origin, &origin) ")"
}
}
^RepositoryWrapperTabs(tab, requested_path, context.repository.head().unwrap().shorthand().unwrap().to_owned())
div.block {
^super::RepositoryHeader(&path, &context.repository)
^RepositoryWrapperTabs(tab, path, context.repository.head().unwrap().shorthand().unwrap().to_owned())
}
^content
})

Deleted src/repository_tree.rs

@@ -1,7 +0,0 @@
use git2::Repository;
pub enum RepositoryTreeEntry {
Dir(String, Vec<RepositoryTreeEntry>),
Repo(String, Repository),
Alias(String, String),
}

Modified src/static/css/style.css

@@ -46,8 +46,6 @@ a:hover {
.block-header h1, .block-header h2, .block-header h3, .block-header h4, .block-header h5 {
margin: 0 0 0.2rem 0;
padding: 0;
display: flex;
align-items: center;
}
.repository-header h1, .repository-header h4 {
@@ -344,5 +342,6 @@ pre.block-details {
border: none;
}
.row { display: flex; flex-direction: row; }
.row { display: flex; flex-direction: row; }
.column { display: flex; flex-direction: column; }
.center { align-items: center; }