Repositories

grarr

(mirrored on github)

Wim Looman <wim@nemo157.com>
5891f5 Add config support
Wim Looman committed at 2016-03-09 14:47:12

Modified Cargo.lock

@@ -19,7 +19,9 @@ dependencies = [
"pulldown-cmark 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"router 0.1.0 (git+https://github.com/Nemo157/router?rev=reverse_priority)",
"rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -766,6 +768,14 @@ dependencies = [
]
[[package]]
name = "toml"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "traitobject"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

Modified Cargo.toml

@@ -37,3 +37,5 @@ maud_macros = { git = "https://github.com/lfairy/maud" }
clippy = { version = "*", optional = true }
rust-crypto = { version = "*" }
unicase = { version = "*" }
toml = "0.1.27"
rustc-serialize = "0.3"

Added default_config.toml

@@ -0,0 +1,10 @@
[repos]
root = "."
[avatars.gravatar]
enable = true
[avatars.cache]
enable = true
capacity = 100
ttl_seconds = 60

Added src/config.rs

@@ -0,0 +1,145 @@
use std::{ env, ffi, io, fmt };
use std::borrow::ToOwned;
use std::fs::File;
use std::io::Read;
use std::path::{ Path, PathBuf };
use toml;
use rustc_serialize::{ Decoder, Decodable, Encoder, Encodable };
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Config {
pub repos: Repos,
pub avatars: Avatars,
}
#[derive(Debug)]
// Cannot derive decode/encode as PathBuf by default uses a [u8/u16] for storage...
pub struct Repos {
pub root: PathBuf,
}
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Avatars {
pub cache: Cache,
pub gravatar: Gravatar,
}
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Cache {
pub enable: bool,
pub capacity: usize,
pub ttl_seconds: i64,
}
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Gravatar {
pub enable: bool,
}
#[derive(Debug)]
pub enum Error {
IO(io::Error),
Parse(Vec<toml::ParserError>),
Decode(toml::DecodeError),
Str(String),
}
pub fn load<S: AsRef<ffi::OsStr> + ?Sized>(from: Option<&S>) -> Result<Config, Error> {
let path = if let Some(path) = from.map(Path::new) {
try!(path.canonicalize())
} else {
try!(try!(env::current_dir()).canonicalize())
};
if path.is_dir() {
Ok(Config {
repos: Repos {
root: path,
},
avatars: Avatars {
cache: Cache {
enable: true,
capacity: 100,
ttl_seconds: 60,
},
gravatar: Gravatar {
enable: true,
},
},
})
} else {
load_file(&path).and_then(|mut config| { config.repos.root = try!(config.repos.root.canonicalize()); Ok(config) })
}
}
fn load_file(path: &Path) -> Result<Config, Error> {
let text = try!(read_file(path));
let value = try!(text.parse::<toml::Value>());
Config::decode(&mut toml::Decoder::new(value)).map_err(From::from)
}
fn read_file(path: &Path) -> io::Result<String> {
let mut text = String::new();
let mut file = try!(File::open(path));
try!(file.read_to_string(&mut text));
Ok(text)
}
impl<'a> From<&'a str> for Error {
fn from(s: &'a str) -> Error {
Error::Str(s.to_owned())
}
}
impl From<Vec<toml::ParserError>> for Error {
fn from(v: Vec<toml::ParserError>) -> Error {
Error::Parse(v)
}
}
impl From<toml::DecodeError> for Error {
fn from(error: toml::DecodeError) -> Error {
Error::Decode(error)
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Error {
Error::IO(error)
}
}
impl fmt::Display for Error {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::IO(ref error) => write!(w, "IO Error:\n{}", error),
Error::Parse(ref errors) => {
try!(write!(w, "Parse Error:\n"));
for error in errors {
try!(write!(w, "{}", error));
}
Ok(())
},
Error::Decode(ref error) => write!(w, "Decode Error:\n{}", error),
Error::Str(ref s) => write!(w, "Misc Error:\n{}", s),
}
}
}
impl Decodable for Repos {
fn decode<D: Decoder>(d: &mut D) -> Result<Repos, D::Error> {
d.read_struct("repos", 1, |d| {
Ok(Repos {
root: try!(d.read_struct_field("root", 0, |d| d.read_str().map(From::from))),
})
})
}
}
impl Encodable for Repos {
fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
e.emit_struct("repos", 1, |e| {
e.emit_struct_field("root", 0, |e| e.emit_str(&self.root.to_string_lossy()))
})
}
}

Modified src/main.rs

@@ -28,6 +28,8 @@ extern crate crypto;
extern crate unicase;
extern crate walkdir;
extern crate params;
extern crate toml;
extern crate rustc_serialize;
#[macro_use]
mod macros;
@@ -42,9 +44,9 @@ mod repository_context;
mod repository_extension;
mod settings;
mod referenced_commit;
mod config;
use std::env;
use std::path::Path;
use iron::prelude::*;
use router::*;
use logger::*;
@@ -58,22 +60,33 @@ pub use repository_extension::RepositoryExtension;
include!(concat!(env!("OUT_DIR"), "/version.rs"));
fn main() {
let root = env::args().nth(1).unwrap();
let config = match config::load(env::args_os().nth(1).as_ref()) {
Ok(config) => config,
Err(err) => {
println!("Failed to load config:\n{}", err);
std::process::exit(1)
},
};
println!("Running with config");
println!("===================");
println!("{}", toml::encode_str(&config));
println!("===================");
let mut router = Router::new();
router
.register(inject_repository_context(Path::new(&root), handler::Review))
.register(inject_repository_context(Path::new(&root), handler::Reviews))
.register(inject_repository_context(Path::new(&root), handler::Commit))
.register(inject_repository_context(Path::new(&root), handler::Commits))
.register(inject_repository_context(Path::new(&root), handler::Repository))
.register(handler::Repositories { root: root.clone().into() })
.register(inject_repository_context(&config.repos.root, handler::Review))
.register(inject_repository_context(&config.repos.root, handler::Reviews))
.register(inject_repository_context(&config.repos.root, handler::Commit))
.register(inject_repository_context(&config.repos.root, handler::Commits))
.register(inject_repository_context(&config.repos.root, handler::Repository))
.register(handler::Repositories { root: config.repos.root.clone() })
.register(handler::Settings)
.register(handler::SettingsPost)
.register(handler::About)
// .register(inject_repository_context(Path::new(&root), handler::Tree))
.register(inject_repository_context(Path::new(&root), handler::TreeEntry))
// .register(inject_repository_context(&config.repos.root, handler::Tree))
.register(inject_repository_context(&config.repos.root, handler::TreeEntry))
.register(statics![
prefix: "./static/";
"./static/js/highlight.js",
@@ -90,10 +103,10 @@ fn main() {
"./static/fonts/fontawesome-webfont.woff2",
])
.register(handler::Avatars::new(handler::avatar::Options {
enable_gravatar: true,
enable_cache: true,
cache_capacity: 100,
cache_time_to_live: Duration::minutes(1),
enable_gravatar: config.avatars.gravatar.enable,
enable_cache: config.avatars.cache.enable,
cache_capacity: config.avatars.cache.capacity,
cache_time_to_live: Duration::seconds(config.avatars.cache.ttl_seconds),
}));
let (logger_before, logger_after) = Logger::new(None);