mirror of
https://github.com/deps-rs/deps.rs.git
synced 2024-11-22 10:26:30 +00:00
first simple version of crate dependency reports
This commit is contained in:
parent
12e4d7df51
commit
7fff95203e
6 changed files with 182 additions and 41 deletions
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use futures::Future;
|
use futures::{Future, future};
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use hyper::Client;
|
use hyper::Client;
|
||||||
use hyper::client::HttpConnector;
|
use hyper::client::HttpConnector;
|
||||||
|
@ -18,7 +18,7 @@ mod futures;
|
||||||
use ::utils::cache::Cache;
|
use ::utils::cache::Cache;
|
||||||
|
|
||||||
use ::models::repo::{Repository, RepoPath};
|
use ::models::repo::{Repository, RepoPath};
|
||||||
use ::models::crates::{CrateName, CrateRelease, AnalyzedDependencies};
|
use ::models::crates::{CrateName, CratePath, CrateRelease, AnalyzedDependencies};
|
||||||
|
|
||||||
use ::interactors::crates::QueryCrate;
|
use ::interactors::crates::QueryCrate;
|
||||||
use ::interactors::RetrieveFileAtPath;
|
use ::interactors::RetrieveFileAtPath;
|
||||||
|
@ -83,7 +83,7 @@ impl Engine {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyze_dependencies(&self, repo_path: RepoPath) ->
|
pub fn analyze_repo_dependencies(&self, repo_path: RepoPath) ->
|
||||||
impl Future<Item=AnalyzeDependenciesOutcome, Error=Error>
|
impl Future<Item=AnalyzeDependenciesOutcome, Error=Error>
|
||||||
{
|
{
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
@ -109,6 +109,33 @@ impl Engine {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn analyze_crate_dependencies(&self, crate_path: CratePath) ->
|
||||||
|
impl Future<Item=AnalyzeDependenciesOutcome, Error=Error>
|
||||||
|
{
|
||||||
|
let start = Instant::now();
|
||||||
|
|
||||||
|
let query_future = self.query_crate.call(crate_path.name.clone()).from_err();
|
||||||
|
|
||||||
|
let engine = self.clone();
|
||||||
|
query_future.and_then(move |query_response| {
|
||||||
|
match query_response.releases.iter().find(|release| release.version == crate_path.version) {
|
||||||
|
None => future::Either::A(future::err(format_err!("could not find crate release with version {}", crate_path.version))),
|
||||||
|
Some(release) => {
|
||||||
|
let analyzed_deps_future = AnalyzeDependenciesFuture::new(&engine, release.deps.clone());
|
||||||
|
|
||||||
|
future::Either::B(analyzed_deps_future.map(move |analyzed_deps| {
|
||||||
|
let crates = vec![(crate_path.name, analyzed_deps)].into_iter().collect();
|
||||||
|
let duration = start.elapsed();
|
||||||
|
|
||||||
|
AnalyzeDependenciesOutcome {
|
||||||
|
crates, duration
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn fetch_releases<I: IntoIterator<Item=CrateName>>(&self, names: I) ->
|
fn fetch_releases<I: IntoIterator<Item=CrateName>>(&self, names: I) ->
|
||||||
impl Iterator<Item=impl Future<Item=Vec<CrateRelease>, Error=Error>>
|
impl Iterator<Item=impl Future<Item=Vec<CrateRelease>, Error=Error>>
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,28 +4,49 @@ use failure::Error;
|
||||||
use futures::{Future, Stream, IntoFuture, future};
|
use futures::{Future, Stream, IntoFuture, future};
|
||||||
use hyper::{Error as HyperError, Method, Request, Response, Uri};
|
use hyper::{Error as HyperError, Method, Request, Response, Uri};
|
||||||
use tokio_service::Service;
|
use tokio_service::Service;
|
||||||
use semver::Version;
|
use semver::{Version, VersionReq};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
use ::models::crates::{CrateName, CrateRelease};
|
use ::models::crates::{CrateName, CrateRelease, CrateDeps, CrateDep};
|
||||||
|
|
||||||
const CRATES_INDEX_BASE_URI: &str = "https://raw.githubusercontent.com/rust-lang/crates.io-index";
|
const CRATES_INDEX_BASE_URI: &str = "https://raw.githubusercontent.com/rust-lang/crates.io-index";
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct RegistryPackageDep {
|
||||||
|
name: String,
|
||||||
|
req: VersionReq,
|
||||||
|
#[serde(default)]
|
||||||
|
kind: Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct RegistryPackage {
|
struct RegistryPackage {
|
||||||
vers: Version,
|
vers: Version,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
deps: Vec<RegistryPackageDep>,
|
||||||
|
#[serde(default)]
|
||||||
yanked: bool
|
yanked: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_pkgs(name: &CrateName, packages: Vec<RegistryPackage>) -> Result<QueryCrateResponse, Error> {
|
fn convert_pkgs(name: &CrateName, packages: Vec<RegistryPackage>) -> Result<QueryCrateResponse, Error> {
|
||||||
let releases = packages.into_iter().map(|package| {
|
let releases = packages.into_iter().map(|package| {
|
||||||
CrateRelease {
|
let mut deps = CrateDeps::default();
|
||||||
|
for dep in package.deps {
|
||||||
|
match dep.kind.map(|k| k.clone()).unwrap_or_else(|| "normal".into()).as_ref() {
|
||||||
|
"normal" =>
|
||||||
|
deps.main.insert(dep.name.parse()?, CrateDep::External(dep.req)),
|
||||||
|
"dev" =>
|
||||||
|
deps.dev.insert(dep.name.parse()?, CrateDep::External(dep.req)),
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(CrateRelease {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
version: package.vers,
|
version: package.vers,
|
||||||
|
deps: deps,
|
||||||
yanked: package.yanked
|
yanked: package.yanked
|
||||||
}
|
})
|
||||||
}).collect();
|
}).collect::<Result<_, Error>>()?;
|
||||||
|
|
||||||
Ok(QueryCrateResponse {
|
Ok(QueryCrateResponse {
|
||||||
releases: releases
|
releases: releases
|
||||||
|
@ -72,7 +93,7 @@ impl<S> Service for QueryCrate<S>
|
||||||
future::Either::A(future::err(format_err!("Status code {} for URI {}", status, uri)))
|
future::Either::A(future::err(format_err!("Status code {} for URI {}", status, uri)))
|
||||||
} else {
|
} else {
|
||||||
let body_future = response.body().concat2().from_err();
|
let body_future = response.body().concat2().from_err();
|
||||||
let decode_future = body_future.and_then(|body| {
|
let decode_future = body_future.and_then(move |body| {
|
||||||
let string_body = str::from_utf8(body.as_ref())?;
|
let string_body = str::from_utf8(body.as_ref())?;
|
||||||
let packages = string_body.lines()
|
let packages = string_body.lines()
|
||||||
.map(|s| s.trim())
|
.map(|s| s.trim())
|
||||||
|
|
|
@ -6,6 +6,21 @@ use ordermap::OrderMap;
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use semver::{Version, VersionReq};
|
use semver::{Version, VersionReq};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct CratePath {
|
||||||
|
pub name: CrateName,
|
||||||
|
pub version: Version
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CratePath {
|
||||||
|
pub fn from_parts(name: &str, version: &str) -> Result<CratePath, Error> {
|
||||||
|
Ok(CratePath {
|
||||||
|
name: name.parse()?,
|
||||||
|
version: version.parse()?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct CrateName(String);
|
pub struct CrateName(String);
|
||||||
|
|
||||||
|
@ -47,6 +62,7 @@ impl FromStr for CrateName {
|
||||||
pub struct CrateRelease {
|
pub struct CrateRelease {
|
||||||
pub name: CrateName,
|
pub name: CrateName,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
|
pub deps: CrateDeps,
|
||||||
pub yanked: bool
|
pub yanked: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,7 @@
|
||||||
pub mod crates;
|
pub mod crates;
|
||||||
pub mod repo;
|
pub mod repo;
|
||||||
|
|
||||||
|
pub enum SubjectPath {
|
||||||
|
Repo(self::repo::RepoPath),
|
||||||
|
Crate(self::crates::CratePath)
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ mod assets;
|
||||||
mod views;
|
mod views;
|
||||||
|
|
||||||
use ::engine::{Engine, AnalyzeDependenciesOutcome};
|
use ::engine::{Engine, AnalyzeDependenciesOutcome};
|
||||||
|
use ::models::crates::CratePath;
|
||||||
use ::models::repo::RepoPath;
|
use ::models::repo::RepoPath;
|
||||||
|
use ::models::SubjectPath;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
enum StatusFormat {
|
enum StatusFormat {
|
||||||
|
@ -28,7 +30,8 @@ enum StaticFile {
|
||||||
enum Route {
|
enum Route {
|
||||||
Index,
|
Index,
|
||||||
Static(StaticFile),
|
Static(StaticFile),
|
||||||
Status(StatusFormat)
|
RepoStatus(StatusFormat),
|
||||||
|
CrateStatus(StatusFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -47,8 +50,11 @@ impl Server {
|
||||||
router.add("/static/style.css", Route::Static(StaticFile::StyleCss));
|
router.add("/static/style.css", Route::Static(StaticFile::StyleCss));
|
||||||
router.add("/static/favicon.png", Route::Static(StaticFile::FaviconPng));
|
router.add("/static/favicon.png", Route::Static(StaticFile::FaviconPng));
|
||||||
|
|
||||||
router.add("/repo/:site/:qual/:name", Route::Status(StatusFormat::Html));
|
router.add("/repo/:site/:qual/:name", Route::RepoStatus(StatusFormat::Html));
|
||||||
router.add("/repo/:site/:qual/:name/status.svg", Route::Status(StatusFormat::Svg));
|
router.add("/repo/:site/:qual/:name/status.svg", Route::RepoStatus(StatusFormat::Svg));
|
||||||
|
|
||||||
|
router.add("/crate/:name/:version", Route::CrateStatus(StatusFormat::Html));
|
||||||
|
router.add("/crate/:name/:version/status.svg", Route::CrateStatus(StatusFormat::Svg));
|
||||||
|
|
||||||
Server { logger, engine, router: Arc::new(router) }
|
Server { logger, engine, router: Arc::new(router) }
|
||||||
}
|
}
|
||||||
|
@ -70,9 +76,14 @@ impl Service for Server {
|
||||||
return Box::new(self.index(req, route_match.params, logger));
|
return Box::new(self.index(req, route_match.params, logger));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&Route::Status(format) => {
|
&Route::RepoStatus(format) => {
|
||||||
if *req.method() == Method::Get {
|
if *req.method() == Method::Get {
|
||||||
return Box::new(self.status(req, route_match.params, logger, format));
|
return Box::new(self.repo_status(req, route_match.params, logger, format));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&Route::CrateStatus(format) => {
|
||||||
|
if *req.method() == Method::Get {
|
||||||
|
return Box::new(self.crate_status(req, route_match.params, logger, format));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&Route::Static(file) => {
|
&Route::Static(file) => {
|
||||||
|
@ -108,7 +119,7 @@ impl Server {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn status(&self, _req: Request, params: Params, logger: Logger, format: StatusFormat) ->
|
fn repo_status(&self, _req: Request, params: Params, logger: Logger, format: StatusFormat) ->
|
||||||
impl Future<Item=Response, Error=HyperError>
|
impl Future<Item=Response, Error=HyperError>
|
||||||
{
|
{
|
||||||
let server = self.clone();
|
let server = self.clone();
|
||||||
|
@ -127,15 +138,15 @@ impl Server {
|
||||||
future::Either::A(future::ok(response))
|
future::Either::A(future::ok(response))
|
||||||
},
|
},
|
||||||
Ok(repo_path) => {
|
Ok(repo_path) => {
|
||||||
future::Either::B(server.engine.analyze_dependencies(repo_path.clone()).then(move |analyze_result| {
|
future::Either::B(server.engine.analyze_repo_dependencies(repo_path.clone()).then(move |analyze_result| {
|
||||||
match analyze_result {
|
match analyze_result {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(logger, "error: {}", err);
|
error!(logger, "error: {}", err);
|
||||||
let response = Server::status_format_analysis(None, format, repo_path);
|
let response = Server::status_format_analysis(None, format, SubjectPath::Repo(repo_path));
|
||||||
future::ok(response)
|
future::ok(response)
|
||||||
},
|
},
|
||||||
Ok(analysis_outcome) => {
|
Ok(analysis_outcome) => {
|
||||||
let response = Server::status_format_analysis(Some(analysis_outcome), format, repo_path);
|
let response = Server::status_format_analysis(Some(analysis_outcome), format, SubjectPath::Repo(repo_path));
|
||||||
future::ok(response)
|
future::ok(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,12 +156,48 @@ impl Server {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn status_format_analysis(analysis_outcome: Option<AnalyzeDependenciesOutcome>, format: StatusFormat, repo_path: RepoPath) -> Response {
|
fn crate_status(&self, _req: Request, params: Params, logger: Logger, format: StatusFormat) ->
|
||||||
|
impl Future<Item=Response, Error=HyperError>
|
||||||
|
{
|
||||||
|
let server = self.clone();
|
||||||
|
|
||||||
|
let name = params.find("name").expect("route param 'name' not found");
|
||||||
|
let version = params.find("version").expect("route param 'version' not found");
|
||||||
|
|
||||||
|
CratePath::from_parts(name, version).into_future().then(move |crate_path_result| {
|
||||||
|
match crate_path_result {
|
||||||
|
Err(err) => {
|
||||||
|
error!(logger, "error: {}", err);
|
||||||
|
let mut response = views::html::error::render("Could not parse crate path",
|
||||||
|
"Please make sure to provide a valid crate name and version.");
|
||||||
|
response.set_status(StatusCode::BadRequest);
|
||||||
|
future::Either::A(future::ok(response))
|
||||||
|
},
|
||||||
|
Ok(crate_path) => {
|
||||||
|
future::Either::B(server.engine.analyze_crate_dependencies(crate_path.clone()).then(move |analyze_result| {
|
||||||
|
match analyze_result {
|
||||||
|
Err(err) => {
|
||||||
|
error!(logger, "error: {}", err);
|
||||||
|
let response = Server::status_format_analysis(None, format, SubjectPath::Crate(crate_path));
|
||||||
|
future::ok(response)
|
||||||
|
},
|
||||||
|
Ok(analysis_outcome) => {
|
||||||
|
let response = Server::status_format_analysis(Some(analysis_outcome), format, SubjectPath::Crate(crate_path));
|
||||||
|
future::ok(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status_format_analysis(analysis_outcome: Option<AnalyzeDependenciesOutcome>, format: StatusFormat, subject_path: SubjectPath) -> Response {
|
||||||
match format {
|
match format {
|
||||||
StatusFormat::Svg =>
|
StatusFormat::Svg =>
|
||||||
views::badge::response(analysis_outcome.as_ref()),
|
views::badge::response(analysis_outcome.as_ref()),
|
||||||
StatusFormat::Html =>
|
StatusFormat::Html =>
|
||||||
views::html::status::render(analysis_outcome, repo_path)
|
views::html::status::render(analysis_outcome, subject_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ use ordermap::OrderMap;
|
||||||
|
|
||||||
use ::engine::AnalyzeDependenciesOutcome;
|
use ::engine::AnalyzeDependenciesOutcome;
|
||||||
use ::models::crates::{CrateName, AnalyzedDependency, AnalyzedDependencies};
|
use ::models::crates::{CrateName, AnalyzedDependency, AnalyzedDependencies};
|
||||||
use ::models::repo::{RepoSite, RepoPath};
|
use ::models::SubjectPath;
|
||||||
|
use ::models::repo::RepoSite;
|
||||||
|
|
||||||
use super::super::badge;
|
use super::super::badge;
|
||||||
|
|
||||||
|
@ -84,26 +85,44 @@ fn dependency_table(title: &str, deps: OrderMap<CrateName, AnalyzedDependency>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_site_icon(repo_site: &RepoSite) -> &'static str {
|
fn get_site_icon(site: &RepoSite) -> &'static str {
|
||||||
match *repo_site {
|
match *site {
|
||||||
RepoSite::Github => "fa-github",
|
RepoSite::Github => "fa-github",
|
||||||
RepoSite::Gitlab => "fa-gitlab",
|
RepoSite::Gitlab => "fa-gitlab",
|
||||||
RepoSite::Bitbucket => "fa-bitbucket",
|
RepoSite::Bitbucket => "fa-bitbucket"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_failure(repo_path: RepoPath) -> Markup {
|
fn render_title(subject_path: &SubjectPath) -> Markup {
|
||||||
let site_icon = get_site_icon(&repo_path.site);
|
match *subject_path {
|
||||||
|
SubjectPath::Repo(ref repo_path) => {
|
||||||
|
let site_icon = get_site_icon(&repo_path.site);
|
||||||
|
html! {
|
||||||
|
a href=(format!("{}/{}/{}", repo_path.site.to_base_uri(), repo_path.qual.as_ref(), repo_path.name.as_ref())) {
|
||||||
|
i class=(format!("fa {}", site_icon)) ""
|
||||||
|
(format!(" {} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SubjectPath::Crate(ref crate_path) => {
|
||||||
|
html! {
|
||||||
|
a href=(format!("https://crates.io/crates/{}/{}", crate_path.name.as_ref(), crate_path.version)) {
|
||||||
|
i class="fa fa-cube" ""
|
||||||
|
(format!(" {} {}", crate_path.name.as_ref(), crate_path.version))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_failure(subject_path: SubjectPath) -> Markup {
|
||||||
html! {
|
html! {
|
||||||
section class="hero is-light" {
|
section class="hero is-light" {
|
||||||
div class="hero-head" (super::render_navbar())
|
div class="hero-head" (super::render_navbar())
|
||||||
div class="hero-body" {
|
div class="hero-body" {
|
||||||
div class="container" {
|
div class="container" {
|
||||||
h1 class="title is-1" {
|
h1 class="title is-1" {
|
||||||
a href=(format!("{}/{}/{}", repo_path.site.to_base_uri(), repo_path.qual.as_ref(), repo_path.name.as_ref())) {
|
(render_title(&subject_path))
|
||||||
i class=(format!("fa {}", site_icon)) ""
|
|
||||||
(format!(" {} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,10 +139,14 @@ fn render_failure(repo_path: RepoPath) -> Markup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoPath) -> Markup {
|
fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, subject_path: SubjectPath) -> Markup {
|
||||||
let self_path = format!("repo/{}/{}/{}", repo_path.site.as_ref(), repo_path.qual.as_ref(), repo_path.name.as_ref());
|
let self_path = match subject_path {
|
||||||
|
SubjectPath::Repo(ref repo_path) =>
|
||||||
|
format!("repo/{}/{}/{}", repo_path.site.as_ref(), repo_path.qual.as_ref(), repo_path.name.as_ref()),
|
||||||
|
SubjectPath::Crate(ref crate_path) =>
|
||||||
|
format!("crate/{}/{}", crate_path.name.as_ref(), crate_path.version)
|
||||||
|
};
|
||||||
let status_base_url = format!("{}/{}", &super::SELF_BASE_URL as &str, self_path);
|
let status_base_url = format!("{}/{}", &super::SELF_BASE_URL as &str, self_path);
|
||||||
let site_icon = get_site_icon(&repo_path.site);
|
|
||||||
|
|
||||||
let status_data_uri = badge::badge(Some(&analysis_outcome)).to_svg_data_uri();
|
let status_data_uri = badge::badge(Some(&analysis_outcome)).to_svg_data_uri();
|
||||||
|
|
||||||
|
@ -139,10 +162,7 @@ fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoP
|
||||||
div class="hero-body" {
|
div class="hero-body" {
|
||||||
div class="container" {
|
div class="container" {
|
||||||
h1 class="title is-1" {
|
h1 class="title is-1" {
|
||||||
a href=(format!("{}/{}/{}", repo_path.site.to_base_uri(), repo_path.qual.as_ref(), repo_path.name.as_ref())) {
|
(render_title(&subject_path))
|
||||||
i class=(format!("fa {}", site_icon)) ""
|
|
||||||
(format!(" {} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
img src=(status_data_uri);
|
img src=(status_data_uri);
|
||||||
|
@ -167,12 +187,17 @@ fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(analysis_outcome: Option<AnalyzeDependenciesOutcome>, repo_path: RepoPath) -> Response {
|
pub fn render(analysis_outcome: Option<AnalyzeDependenciesOutcome>, subject_path: SubjectPath) -> Response {
|
||||||
let title = format!("{} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref());
|
let title = match subject_path {
|
||||||
|
SubjectPath::Repo(ref repo_path) =>
|
||||||
|
format!("{} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()),
|
||||||
|
SubjectPath::Crate(ref crate_path) =>
|
||||||
|
format!("{} {}", crate_path.name.as_ref(), crate_path.version)
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(outcome) = analysis_outcome {
|
if let Some(outcome) = analysis_outcome {
|
||||||
super::render_html(&title, render_success(outcome, repo_path))
|
super::render_html(&title, render_success(outcome, subject_path))
|
||||||
} else {
|
} else {
|
||||||
super::render_html(&title, render_failure(repo_path))
|
super::render_html(&title, render_failure(subject_path))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue