From adab7fdf74ab730f312098bf1843ea776b443842 Mon Sep 17 00:00:00 2001 From: Sam Rijs Date: Sat, 27 Jan 2018 12:40:17 +1100 Subject: [PATCH] implement badges --- assets/badges/outdated.svg | 1 + assets/badges/up-to-date.svg | 1 + src/api.rs | 61 ++++++++++++++++++++++++++++++++---- src/assets.rs | 4 +++ src/main.rs | 1 + src/models/crates.rs | 10 ++++++ 6 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 assets/badges/outdated.svg create mode 100644 assets/badges/up-to-date.svg create mode 100644 src/assets.rs diff --git a/assets/badges/outdated.svg b/assets/badges/outdated.svg new file mode 100644 index 0000000..69434ff --- /dev/null +++ b/assets/badges/outdated.svg @@ -0,0 +1 @@ +dependenciesdependenciesoutdatedoutdated \ No newline at end of file diff --git a/assets/badges/up-to-date.svg b/assets/badges/up-to-date.svg new file mode 100644 index 0000000..42c1200 --- /dev/null +++ b/assets/badges/up-to-date.svg @@ -0,0 +1 @@ +dependenciesdependenciesup-to-dateup-to-date \ No newline at end of file diff --git a/src/api.rs b/src/api.rs index 75bc957..08a9ac9 100644 --- a/src/api.rs +++ b/src/api.rs @@ -10,11 +10,13 @@ use serde_json; use slog::Logger; use tokio_service::Service; -use ::models::repo::RepoPath; +use ::assets; use ::engine::Engine; +use ::models::repo::RepoPath; enum Route { - AnalyzeDependencies + StatusJson, + StatusSvg } #[derive(Clone)] @@ -26,7 +28,8 @@ pub struct Api { impl Api { pub fn new(engine: Engine) -> Api { let mut router = Router::new(); - router.add("/repo/:site/:qual/:name/dependencies.json", Route::AnalyzeDependencies); + router.add("/repo/:site/:qual/:name/status.json", Route::StatusJson); + router.add("/repo/:site/:qual/:name/status.svg", Route::StatusSvg); Api { engine, router: Arc::new(router) } } @@ -62,9 +65,14 @@ impl Service for Api { fn call(&self, req: Request) -> Self::Future { if let Ok(route_match) = self.router.recognize(req.uri().path()) { match route_match.handler { - &Route::AnalyzeDependencies => { + &Route::StatusJson => { if *req.method() == Method::Get { - return Box::new(self.analyze_dependencies(req, route_match.params)); + return Box::new(self.status_json(req, route_match.params)); + } + }, + &Route::StatusSvg => { + if *req.method() == Method::Get { + return Box::new(self.status_svg(req, route_match.params)); } } } @@ -77,7 +85,7 @@ impl Service for Api { } impl Api { - fn analyze_dependencies<'r>(&self, _req: Request, params: Params) -> impl Future { + fn status_json<'r>(&self, _req: Request, params: Params) -> impl Future { let engine = self.engine.clone(); let site = params.find("site").expect("route param 'site' not found"); @@ -136,4 +144,45 @@ impl Api { } }) } + + fn status_svg<'r>(&self, _req: Request, params: Params) -> impl Future { + let engine = self.engine.clone(); + + let site = params.find("site").expect("route param 'site' not found"); + let qual = params.find("qual").expect("route param 'qual' not found"); + let name = params.find("name").expect("route param 'name' not found"); + + RepoPath::from_parts(site, qual, name).into_future().then(move |repo_path_result| { + match repo_path_result { + Err(err) => { + let mut response = Response::new(); + response.set_status(StatusCode::BadRequest); + response.set_body(format!("{:?}", err)); + future::Either::A(future::ok(response)) + }, + Ok(repo_path) => { + future::Either::B(engine.analyze_dependencies(repo_path).then(|analyze_result| { + match analyze_result { + Err(err) => { + let mut response = Response::new(); + response.set_status(StatusCode::InternalServerError); + response.set_body(format!("{:?}", err)); + future::Either::A(future::ok(response)) + }, + Ok(analysis_outcome) => { + let mut response = Response::new() + .with_header(ContentType("image/svg+xml;charset=utf-8".parse().unwrap())); + if analysis_outcome.deps.any_outdated() { + response.set_body(assets::BADGE_OUTDATED_SVG.to_vec()); + } else { + response.set_body(assets::BADGE_UPTODATE_SVG.to_vec()); + } + future::Either::B(future::ok(response)) + } + } + })) + } + } + }) + } } \ No newline at end of file diff --git a/src/assets.rs b/src/assets.rs new file mode 100644 index 0000000..6d23242 --- /dev/null +++ b/src/assets.rs @@ -0,0 +1,4 @@ +pub static BADGE_UPTODATE_SVG: &'static [u8; 978] = + include_bytes!("../assets/badges/up-to-date.svg"); +pub static BADGE_OUTDATED_SVG: &'static [u8; 974] = + include_bytes!("../assets/badges/outdated.svg"); diff --git a/src/main.rs b/src/main.rs index 91a473d..2457794 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ mod models; mod parsers; mod interactors; mod engine; +mod assets; mod api; use std::net::SocketAddr; diff --git a/src/models/crates.rs b/src/models/crates.rs index 03a4a37..7b5a1b9 100644 --- a/src/models/crates.rs +++ b/src/models/crates.rs @@ -92,6 +92,16 @@ impl AnalyzedDependencies { }).collect(); AnalyzedDependencies { main, dev, build } } + + pub fn any_outdated(&self) -> bool { + let main_any_outdated = self.main.iter() + .any(|(_, dep)| dep.is_outdated()); + let dev_any_outdated = self.dev.iter() + .any(|(_, dep)| dep.is_outdated()); + let build_any_outdated = self.build.iter() + .any(|(_, dep)| dep.is_outdated()); + main_any_outdated || dev_any_outdated || build_any_outdated + } } #[derive(Debug)]