Implement generator and use custom result type

This commit is contained in:
Valentin Brandl 2019-05-04 15:45:25 +02:00
parent eb0ee4b31d
commit 791cb38a41
No known key found for this signature in database
GPG Key ID: 30D341DD34118D7D

View File

@ -13,8 +13,8 @@ mod service;
use crate::{ use crate::{
cache::CacheState, cache::CacheState,
error::Error, error::{Error, Result},
service::{Bitbucket, GitHub, Gitlab, Service}, service::{Bitbucket, FormService, GitHub, Gitlab, Service},
}; };
use actix_web::{ use actix_web::{
error::ErrorBadRequest, error::ErrorBadRequest,
@ -27,6 +27,7 @@ use futures::{unsync::mpsc, Stream};
use git2::Repository; use git2::Repository;
use number_prefix::{NumberPrefix, Prefixed, Standalone}; use number_prefix::{NumberPrefix, Prefixed, Standalone};
use std::{ use std::{
borrow::Cow,
fs::create_dir_all, fs::create_dir_all,
path::{Path, PathBuf}, path::{Path, PathBuf},
process::Command, process::Command,
@ -42,6 +43,13 @@ pub struct VersionInfo<'a> {
pub version: &'a str, pub version: &'a str,
} }
#[derive(Deserialize, Serialize)]
struct GeneratorForm<'a> {
service: FormService,
user: Cow<'a, str>,
repo: Cow<'a, str>,
}
const VERSION_INFO: VersionInfo = VersionInfo { const VERSION_INFO: VersionInfo = VersionInfo {
commit: env!("VERGEN_SHA_SHORT"), commit: env!("VERGEN_SHA_SHORT"),
version: env!("CARGO_PKG_VERSION"), version: env!("CARGO_PKG_VERSION"),
@ -106,14 +114,14 @@ struct Opt {
workers: usize, workers: usize,
} }
fn pull(path: impl AsRef<Path>) -> Result<(), Error> { fn pull(path: impl AsRef<Path>) -> Result<()> {
let repo = Repository::open_bare(path)?; let repo = Repository::open_bare(path)?;
let mut origin = repo.find_remote("origin")?; let mut origin = repo.find_remote("origin")?;
origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?; origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?;
Ok(()) Ok(())
} }
fn hoc(repo: &str, repo_dir: &str, cache_dir: &str) -> Result<(u64, String), Error> { fn hoc(repo: &str, repo_dir: &str, cache_dir: &str) -> Result<(u64, String)> {
let repo_dir = format!("{}/{}", repo_dir, repo); let repo_dir = format!("{}/{}", repo_dir, repo);
let cache_dir = format!("{}/{}.json", cache_dir, repo); let cache_dir = format!("{}/{}.json", cache_dir, repo);
let cache_dir = Path::new(&cache_dir); let cache_dir = Path::new(&cache_dir);
@ -164,7 +172,7 @@ fn hoc(repo: &str, repo_dir: &str, cache_dir: &str) -> Result<(u64, String), Err
s.split_whitespace() s.split_whitespace()
.take(2) .take(2)
.map(str::parse::<u64>) .map(str::parse::<u64>)
.filter_map(Result::ok) .filter_map(std::result::Result::ok)
.sum::<u64>() .sum::<u64>()
}) })
.sum(); .sum();
@ -175,7 +183,7 @@ fn hoc(repo: &str, repo_dir: &str, cache_dir: &str) -> Result<(u64, String), Err
Ok((cache.count, head)) Ok((cache.count, head))
} }
fn remote_exists(url: &str) -> Result<bool, Error> { fn remote_exists(url: &str) -> Result<bool> {
Ok(CLIENT.head(url).send()?.status() == reqwest::StatusCode::OK) Ok(CLIENT.head(url).send()?.status() == reqwest::StatusCode::OK)
} }
@ -195,10 +203,10 @@ fn handle_hoc_request<T, F>(
state: web::Data<Arc<State>>, state: web::Data<Arc<State>>,
data: web::Path<(String, String)>, data: web::Path<(String, String)>,
mapper: F, mapper: F,
) -> Result<HttpResponse, Error> ) -> Result<HttpResponse>
where where
T: Service, T: Service,
F: Fn(HocResult) -> Result<HttpResponse, Error>, F: Fn(HocResult) -> Result<HttpResponse>,
{ {
hoc_request::<T>(state, data).and_then(mapper) hoc_request::<T>(state, data).and_then(mapper)
} }
@ -206,7 +214,7 @@ where
fn hoc_request<T: Service>( fn hoc_request<T: Service>(
state: web::Data<Arc<State>>, state: web::Data<Arc<State>>,
data: web::Path<(String, String)>, data: web::Path<(String, String)>,
) -> Result<HocResult, Error> { ) -> Result<HocResult> {
let repo = format!("{}/{}", data.0.to_lowercase(), data.1.to_lowercase()); let repo = format!("{}/{}", data.0.to_lowercase(), data.1.to_lowercase());
let service_path = format!("{}/{}", T::domain(), repo); let service_path = format!("{}/{}", T::domain(), repo);
let path = format!("{}/{}", state.repos, service_path); let path = format!("{}/{}", state.repos, service_path);
@ -242,7 +250,7 @@ fn hoc_request<T: Service>(
fn calculate_hoc<T: Service>( fn calculate_hoc<T: Service>(
state: web::Data<Arc<State>>, state: web::Data<Arc<State>>,
data: web::Path<(String, String)>, data: web::Path<(String, String)>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse> {
let mapper = |r| match r { let mapper = |r| match r {
HocResult::NotFound => Ok(p404()), HocResult::NotFound => Ok(p404()),
HocResult::Hoc { hoc_pretty, .. } => { HocResult::Hoc { hoc_pretty, .. } => {
@ -275,7 +283,7 @@ fn calculate_hoc<T: Service>(
fn overview<T: Service>( fn overview<T: Service>(
state: web::Data<Arc<State>>, state: web::Data<Arc<State>>,
data: web::Path<(String, String)>, data: web::Path<(String, String)>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse> {
let mapper = |r| match r { let mapper = |r| match r {
HocResult::NotFound => Ok(p404()), HocResult::NotFound => Ok(p404()),
HocResult::Hoc { HocResult::Hoc {
@ -317,6 +325,26 @@ fn index() -> HttpResponse {
.body(INDEX.as_slice()) .body(INDEX.as_slice())
} }
#[post("/generate")]
fn generate(params: web::Form<GeneratorForm>) -> Result<HttpResponse> {
let repo = format!("{}/{}", params.user, params.repo);
let mut buf = Vec::new();
templates::generate(
&mut buf,
VERSION_INFO,
&OPT.domain,
params.service.url(),
params.service.service(),
&repo,
)?;
let (tx, rx_body) = mpsc::unbounded();
let _ = tx.unbounded_send(Bytes::from(buf));
Ok(HttpResponse::Ok()
.content_type("text/html")
.streaming(rx_body.map_err(|_| ErrorBadRequest("bad request"))))
}
fn p404() -> HttpResponse { fn p404() -> HttpResponse {
HttpResponse::NotFound() HttpResponse::NotFound()
.content_type("text/html") .content_type("text/html")
@ -343,6 +371,7 @@ fn main() -> std::io::Result<()> {
.wrap(middleware::Logger::default()) .wrap(middleware::Logger::default())
.service(index) .service(index)
.service(css) .service(css)
.service(generate)
.service(web::resource("/github/{user}/{repo}").to(calculate_hoc::<GitHub>)) .service(web::resource("/github/{user}/{repo}").to(calculate_hoc::<GitHub>))
.service(web::resource("/gitlab/{user}/{repo}").to(calculate_hoc::<Gitlab>)) .service(web::resource("/gitlab/{user}/{repo}").to(calculate_hoc::<Gitlab>))
.service(web::resource("/bitbucket/{user}/{repo}").to(calculate_hoc::<Bitbucket>)) .service(web::resource("/bitbucket/{user}/{repo}").to(calculate_hoc::<Bitbucket>))