From 4556d6a04a240b06a7abc02b25697d5309a997ca Mon Sep 17 00:00:00 2001 From: Valentin Brandl Date: Sat, 4 May 2019 15:33:21 +0200 Subject: [PATCH 1/4] Add custom result type --- src/error.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/error.rs b/src/error.rs index 07845cf..55f27b2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,6 +2,8 @@ use crate::P500; use actix_web::{HttpResponse, ResponseError}; use std::fmt; +pub(crate) type Result = std::result::Result; + #[derive(Debug)] pub(crate) enum Error { Badge(String), From d5e6bf78399f06a757257db33add4957afc67a35 Mon Sep 17 00:00:00 2001 From: Valentin Brandl Date: Sat, 4 May 2019 15:37:29 +0200 Subject: [PATCH 2/4] Add service enum for form data --- src/service.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/service.rs b/src/service.rs index f234ff3..b9300e2 100644 --- a/src/service.rs +++ b/src/service.rs @@ -4,6 +4,34 @@ pub(crate) trait Service { fn commit_url(repo: &str, commit_ref: &str) -> String; } +#[derive(Deserialize, Serialize)] +pub(crate) enum FormService { + #[serde(rename = "github")] + GitHub, + #[serde(rename = "gitlab")] + Gitlab, + #[serde(rename = "bitbucket")] + Bitbucket, +} + +impl FormService { + pub(crate) fn url(&self) -> &str { + match self { + FormService::GitHub => "github.com", + FormService::Gitlab => "gitlab.com", + FormService::Bitbucket => "bitbucket.org", + } + } + + pub(crate) fn service(&self) -> &str { + match self { + FormService::GitHub => "github", + FormService::Gitlab => "gitlab", + FormService::Bitbucket => "bitbucket", + } + } +} + pub(crate) struct GitHub; impl Service for GitHub { From eb0ee4b31de58e0eb4a8d474b517e3e011047e48 Mon Sep 17 00:00:00 2001 From: Valentin Brandl Date: Sat, 4 May 2019 15:38:00 +0200 Subject: [PATCH 3/4] Add generator and result page --- templates/generate.rs.html | 23 +++++++++++++++++++++++ templates/index.rs.html | 15 +++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 templates/generate.rs.html diff --git a/templates/generate.rs.html b/templates/generate.rs.html new file mode 100644 index 0000000..86b2c03 --- /dev/null +++ b/templates/generate.rs.html @@ -0,0 +1,23 @@ +@use super::base; +@use crate::VersionInfo; + +@(version_info: VersionInfo, domain: &str, url: &str, service: &str, path: &str) + +@:base("Hits-of-Code Badges", "Badge Generator", { + +

+Here is the markdown for the badge for @url/@path +

+ +
+[![Hits-of-Code](https://@domain/@service/@path)](https://@domain/view/@service/@path)
+
+ +

+It will be rendered like this +

+ +
+example badge
+
+}, version_info) diff --git a/templates/index.rs.html b/templates/index.rs.html index ec004cc..adbcd91 100644 --- a/templates/index.rs.html +++ b/templates/index.rs.html @@ -45,6 +45,21 @@ would render this badge: alt="example badge" /> +

Badge Generator

+ +
+ + + + + + +
+

Source Code

From 791cb38a41a260679d3acb5d4b423d7f4314f826 Mon Sep 17 00:00:00 2001 From: Valentin Brandl Date: Sat, 4 May 2019 15:45:25 +0200 Subject: [PATCH 4/4] Implement generator and use custom result type --- src/main.rs | 51 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 49c20f4..aad2c5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,8 +13,8 @@ mod service; use crate::{ cache::CacheState, - error::Error, - service::{Bitbucket, GitHub, Gitlab, Service}, + error::{Error, Result}, + service::{Bitbucket, FormService, GitHub, Gitlab, Service}, }; use actix_web::{ error::ErrorBadRequest, @@ -27,6 +27,7 @@ use futures::{unsync::mpsc, Stream}; use git2::Repository; use number_prefix::{NumberPrefix, Prefixed, Standalone}; use std::{ + borrow::Cow, fs::create_dir_all, path::{Path, PathBuf}, process::Command, @@ -42,6 +43,13 @@ pub struct VersionInfo<'a> { 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 { commit: env!("VERGEN_SHA_SHORT"), version: env!("CARGO_PKG_VERSION"), @@ -106,14 +114,14 @@ struct Opt { workers: usize, } -fn pull(path: impl AsRef) -> Result<(), Error> { +fn pull(path: impl AsRef) -> Result<()> { let repo = Repository::open_bare(path)?; let mut origin = repo.find_remote("origin")?; origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?; 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 cache_dir = format!("{}/{}.json", cache_dir, repo); 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() .take(2) .map(str::parse::) - .filter_map(Result::ok) + .filter_map(std::result::Result::ok) .sum::() }) .sum(); @@ -175,7 +183,7 @@ fn hoc(repo: &str, repo_dir: &str, cache_dir: &str) -> Result<(u64, String), Err Ok((cache.count, head)) } -fn remote_exists(url: &str) -> Result { +fn remote_exists(url: &str) -> Result { Ok(CLIENT.head(url).send()?.status() == reqwest::StatusCode::OK) } @@ -195,10 +203,10 @@ fn handle_hoc_request( state: web::Data>, data: web::Path<(String, String)>, mapper: F, -) -> Result +) -> Result where T: Service, - F: Fn(HocResult) -> Result, + F: Fn(HocResult) -> Result, { hoc_request::(state, data).and_then(mapper) } @@ -206,7 +214,7 @@ where fn hoc_request( state: web::Data>, data: web::Path<(String, String)>, -) -> Result { +) -> Result { let repo = format!("{}/{}", data.0.to_lowercase(), data.1.to_lowercase()); let service_path = format!("{}/{}", T::domain(), repo); let path = format!("{}/{}", state.repos, service_path); @@ -242,7 +250,7 @@ fn hoc_request( fn calculate_hoc( state: web::Data>, data: web::Path<(String, String)>, -) -> Result { +) -> Result { let mapper = |r| match r { HocResult::NotFound => Ok(p404()), HocResult::Hoc { hoc_pretty, .. } => { @@ -275,7 +283,7 @@ fn calculate_hoc( fn overview( state: web::Data>, data: web::Path<(String, String)>, -) -> Result { +) -> Result { let mapper = |r| match r { HocResult::NotFound => Ok(p404()), HocResult::Hoc { @@ -317,6 +325,26 @@ fn index() -> HttpResponse { .body(INDEX.as_slice()) } +#[post("/generate")] +fn generate(params: web::Form) -> Result { + 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 { HttpResponse::NotFound() .content_type("text/html") @@ -343,6 +371,7 @@ fn main() -> std::io::Result<()> { .wrap(middleware::Logger::default()) .service(index) .service(css) + .service(generate) .service(web::resource("/github/{user}/{repo}").to(calculate_hoc::)) .service(web::resource("/gitlab/{user}/{repo}").to(calculate_hoc::)) .service(web::resource("/bitbucket/{user}/{repo}").to(calculate_hoc::))