diff --git a/Cargo.lock b/Cargo.lock index 6e65ac9..ce460e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1170,6 +1170,9 @@ name = "serde" version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_derive" @@ -1258,7 +1261,6 @@ dependencies = [ "sass-rs", "semver 0.11.0", "serde 1.0.116", - "serde_derive", "serde_json 1.0.57", "shared_failure", "slog", diff --git a/Cargo.toml b/Cargo.toml index c2ff028..dd94df1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,15 +19,14 @@ futures = "0.1.18" hyper = "0.11.15" hyper-tls = "0.1.2" indexmap = { version = "1.0.0", features = ["serde-1"] } -lru-cache = "0.1.1" +lru-cache = "0.1" maud = "0.22" once_cell = "1.4" relative-path = { version = "0.3.7", features = ["serde"] } route-recognizer = "0.1.12" rustsec = "0.6.0" semver = { version = "0.11", features = ["serde"] } -serde = "1.0.27" -serde_derive = "1.0.27" +serde = { version = "1", features = ["derive"] } serde_json = "1.0.9" shared_failure = "0.1.0" slog = "2.1.1" diff --git a/build.rs b/build.rs index 24305cb..3fb6176 100644 --- a/build.rs +++ b/build.rs @@ -11,8 +11,7 @@ fn build_style() -> String { ..Default::default() }; - sass::compile_file("./assets/styles/main.sass", options) - .expect("failed to compile style sheet") + sass::compile_file("./assets/styles/main.sass", options).expect("failed to compile style sheet") } fn main() { diff --git a/libs/badge/badge.rs b/libs/badge/badge.rs index 3a49580..c28310c 100644 --- a/libs/badge/badge.rs +++ b/libs/badge/badge.rs @@ -39,7 +39,7 @@ struct BadgeStaticData { static DATA: Lazy = Lazy::new(|| { let font = Font::try_from_bytes(FONT_DATA).expect("failed to parse font collection"); - + let v_metrics = font.v_metrics(SCALE); let offset = point(0.0, v_metrics.ascent); diff --git a/src/engine/fut/analyze.rs b/src/engine/fut/analyze.rs index d1d0427..43aed2b 100644 --- a/src/engine/fut/analyze.rs +++ b/src/engine/fut/analyze.rs @@ -1,40 +1,57 @@ use failure::Error; -use futures::{Future, Poll, Stream}; use futures::stream::futures_unordered; +use futures::{Future, Poll, Stream}; use crate::models::crates::{AnalyzedDependencies, CrateDeps}; -use super::super::Engine; use super::super::machines::analyzer::DependencyAnalyzer; +use super::super::Engine; pub struct AnalyzeDependenciesFuture { - inner: Box> + inner: Box>, } impl AnalyzeDependenciesFuture { pub fn new(engine: Engine, deps: CrateDeps) -> Self { - let future = engine.fetch_advisory_db().and_then(move |advisory_db| { - let analyzer = DependencyAnalyzer::new(&deps, Some(advisory_db)); + let future = + engine.fetch_advisory_db().and_then(move |advisory_db| { + let analyzer = DependencyAnalyzer::new(&deps, Some(advisory_db)); - let main_deps = deps.main.into_iter().filter_map(|(name, dep)| { - if dep.is_external() { Some(name) } else { None } - }); - let dev_deps = deps.dev.into_iter().filter_map(|(name, dep)| { - if dep.is_external() { Some(name) } else { None } - }); - let build_deps = deps.build.into_iter().filter_map(|(name, dep)| { - if dep.is_external() { Some(name) } else { None } - }); + let main_deps = deps.main.into_iter().filter_map(|(name, dep)| { + if dep.is_external() { + Some(name) + } else { + None + } + }); + let dev_deps = deps.dev.into_iter().filter_map(|(name, dep)| { + if dep.is_external() { + Some(name) + } else { + None + } + }); + let build_deps = deps.build.into_iter().filter_map(|(name, dep)| { + if dep.is_external() { + Some(name) + } else { + None + } + }); - let release_futures = engine.fetch_releases(main_deps.chain(dev_deps).chain(build_deps)); + let release_futures = + engine.fetch_releases(main_deps.chain(dev_deps).chain(build_deps)); - futures_unordered(release_futures) - .fold(analyzer, |mut analyzer, releases| { analyzer.process(releases); Ok(analyzer) as Result<_, Error> }) - .map(|analyzer| analyzer.finalize()) - }); + futures_unordered(release_futures) + .fold(analyzer, |mut analyzer, releases| { + analyzer.process(releases); + Ok(analyzer) as Result<_, Error> + }) + .map(|analyzer| analyzer.finalize()) + }); AnalyzeDependenciesFuture { - inner: Box::new(future) + inner: Box::new(future), } } } diff --git a/src/engine/fut/crawl.rs b/src/engine/fut/crawl.rs index f5111f4..179ffcb 100644 --- a/src/engine/fut/crawl.rs +++ b/src/engine/fut/crawl.rs @@ -1,34 +1,40 @@ use std::mem; use failure::Error; -use futures::{Async, Future, Poll, Stream, try_ready}; use futures::stream::FuturesOrdered; +use futures::{try_ready, Async, Future, Poll, Stream}; use relative_path::RelativePathBuf; use crate::models::repo::RepoPath; -use super::super::Engine; use super::super::machines::crawler::ManifestCrawler; pub use super::super::machines::crawler::ManifestCrawlerOutput; +use super::super::Engine; pub struct CrawlManifestFuture { repo_path: RepoPath, engine: Engine, crawler: ManifestCrawler, - futures: FuturesOrdered>> + futures: FuturesOrdered>>, } impl CrawlManifestFuture { pub fn new(engine: &Engine, repo_path: RepoPath, entry_point: RelativePathBuf) -> Self { - let future: Box> = Box::new(engine.retrieve_manifest_at_path(&repo_path, &entry_point) - .map(move |contents| (entry_point, contents))); + let future: Box> = Box::new( + engine + .retrieve_manifest_at_path(&repo_path, &entry_point) + .map(move |contents| (entry_point, contents)), + ); let engine = engine.clone(); let crawler = ManifestCrawler::new(); let mut futures = FuturesOrdered::new(); futures.push(future); CrawlManifestFuture { - repo_path, engine, crawler, futures + repo_path, + engine, + crawler, + futures, } } } @@ -42,12 +48,15 @@ impl Future for CrawlManifestFuture { None => { let crawler = mem::replace(&mut self.crawler, ManifestCrawler::new()); Ok(Async::Ready(crawler.finalize())) - }, + } Some((path, raw_manifest)) => { let output = self.crawler.step(path, raw_manifest)?; for path in output.paths_of_interest.into_iter() { - let future: Box> = Box::new(self.engine.retrieve_manifest_at_path(&self.repo_path, &path) - .map(move |contents| (path, contents))); + let future: Box> = Box::new( + self.engine + .retrieve_manifest_at_path(&self.repo_path, &path) + .map(move |contents| (path, contents)), + ); self.futures.push(future); } self.poll() diff --git a/src/engine/fut/mod.rs b/src/engine/fut/mod.rs index 651f8c3..f902460 100644 --- a/src/engine/fut/mod.rs +++ b/src/engine/fut/mod.rs @@ -1,5 +1,5 @@ -mod crawl; mod analyze; +mod crawl; -pub use self::crawl::CrawlManifestFuture; pub use self::analyze::AnalyzeDependenciesFuture; +pub use self::crawl::CrawlManifestFuture; diff --git a/src/engine/machines/analyzer.rs b/src/engine/machines/analyzer.rs index 720d24c..b7f5be8 100644 --- a/src/engine/machines/analyzer.rs +++ b/src/engine/machines/analyzer.rs @@ -3,22 +3,29 @@ use std::sync::Arc; use rustsec::db::AdvisoryDatabase; use semver::Version; -use crate::models::crates::{CrateDeps, CrateRelease, CrateName, AnalyzedDependency, AnalyzedDependencies}; +use crate::models::crates::{ + AnalyzedDependencies, AnalyzedDependency, CrateDeps, CrateName, CrateRelease, +}; pub struct DependencyAnalyzer { deps: AnalyzedDependencies, - advisory_db: Option> + advisory_db: Option>, } impl DependencyAnalyzer { pub fn new(deps: &CrateDeps, advisory_db: Option>) -> DependencyAnalyzer { DependencyAnalyzer { deps: AnalyzedDependencies::new(deps), - advisory_db + advisory_db, } } - fn process_single(name: &CrateName, dep: &mut AnalyzedDependency, ver: &Version, advisory_db: Option<&AdvisoryDatabase>) { + fn process_single( + name: &CrateName, + dep: &mut AnalyzedDependency, + ver: &Version, + advisory_db: Option<&AdvisoryDatabase>, + ) { if dep.required.matches(&ver) { if let Some(ref mut current_latest_that_matches) = dep.latest_that_matches { if *current_latest_that_matches < *ver { @@ -28,7 +35,10 @@ impl DependencyAnalyzer { dep.latest_that_matches = Some(ver.clone()); } - if !advisory_db.map(|db| db.find_vulns_for_crate(name.as_ref(), ver).is_empty()).unwrap_or(true) { + if !advisory_db + .map(|db| db.find_vulns_for_crate(name.as_ref(), ver).is_empty()) + .unwrap_or(true) + { dep.insecure = true; } } @@ -43,17 +53,32 @@ impl DependencyAnalyzer { } } - pub fn process>(&mut self, releases: I) { + pub fn process>(&mut self, releases: I) { let advisory_db = self.advisory_db.as_ref().map(|r| r.as_ref()); for release in releases.into_iter().filter(|r| !r.yanked) { if let Some(main_dep) = self.deps.main.get_mut(&release.name) { - DependencyAnalyzer::process_single(&release.name, main_dep, &release.version, advisory_db) + DependencyAnalyzer::process_single( + &release.name, + main_dep, + &release.version, + advisory_db, + ) } if let Some(dev_dep) = self.deps.dev.get_mut(&release.name) { - DependencyAnalyzer::process_single(&release.name, dev_dep, &release.version, advisory_db) + DependencyAnalyzer::process_single( + &release.name, + dev_dep, + &release.version, + advisory_db, + ) } if let Some(build_dep) = self.deps.build.get_mut(&release.name) { - DependencyAnalyzer::process_single(&release.name, build_dep, &release.version, advisory_db) + DependencyAnalyzer::process_single( + &release.name, + build_dep, + &release.version, + advisory_db, + ) } } } @@ -65,75 +90,156 @@ impl DependencyAnalyzer { #[cfg(test)] mod tests { - use models::crates::{CrateDep, CrateDeps, CrateRelease}; use super::DependencyAnalyzer; + use models::crates::{CrateDep, CrateDeps, CrateRelease}; #[test] fn tracks_latest_without_matching() { let mut deps = CrateDeps::default(); - deps.main.insert("hyper".parse().unwrap(), CrateDep::External("^0.11.0".parse().unwrap())); + deps.main.insert( + "hyper".parse().unwrap(), + CrateDep::External("^0.11.0".parse().unwrap()), + ); let mut analyzer = DependencyAnalyzer::new(&deps, None); analyzer.process(vec![ - CrateRelease { name: "hyper".parse().unwrap(), version: "0.10.0".parse().unwrap(), deps: Default::default(), yanked: false }, - CrateRelease { name: "hyper".parse().unwrap(), version: "0.10.1".parse().unwrap(), deps: Default::default(), yanked: false } + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.10.0".parse().unwrap(), + deps: Default::default(), + yanked: false, + }, + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.10.1".parse().unwrap(), + deps: Default::default(), + yanked: false, + }, ]); let analyzed = analyzer.finalize(); - assert_eq!(analyzed.main.get("hyper").unwrap().latest_that_matches, None); - assert_eq!(analyzed.main.get("hyper").unwrap().latest, Some("0.10.1".parse().unwrap())); + assert_eq!( + analyzed.main.get("hyper").unwrap().latest_that_matches, + None + ); + assert_eq!( + analyzed.main.get("hyper").unwrap().latest, + Some("0.10.1".parse().unwrap()) + ); } #[test] fn tracks_latest_that_matches() { let mut deps = CrateDeps::default(); - deps.main.insert("hyper".parse().unwrap(), CrateDep::External("^0.10.0".parse().unwrap())); + deps.main.insert( + "hyper".parse().unwrap(), + CrateDep::External("^0.10.0".parse().unwrap()), + ); let mut analyzer = DependencyAnalyzer::new(&deps, None); analyzer.process(vec![ - CrateRelease { name: "hyper".parse().unwrap(), version: "0.10.0".parse().unwrap(), deps: Default::default(), yanked: false }, - CrateRelease { name: "hyper".parse().unwrap(), version: "0.10.1".parse().unwrap(), deps: Default::default(), yanked: false }, - CrateRelease { name: "hyper".parse().unwrap(), version: "0.11.0".parse().unwrap(), deps: Default::default(), yanked: false } + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.10.0".parse().unwrap(), + deps: Default::default(), + yanked: false, + }, + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.10.1".parse().unwrap(), + deps: Default::default(), + yanked: false, + }, + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.11.0".parse().unwrap(), + deps: Default::default(), + yanked: false, + }, ]); let analyzed = analyzer.finalize(); - assert_eq!(analyzed.main.get("hyper").unwrap().latest_that_matches, Some("0.10.1".parse().unwrap())); - assert_eq!(analyzed.main.get("hyper").unwrap().latest, Some("0.11.0".parse().unwrap())); + assert_eq!( + analyzed.main.get("hyper").unwrap().latest_that_matches, + Some("0.10.1".parse().unwrap()) + ); + assert_eq!( + analyzed.main.get("hyper").unwrap().latest, + Some("0.11.0".parse().unwrap()) + ); } #[test] fn skips_yanked_releases() { let mut deps = CrateDeps::default(); - deps.main.insert("hyper".parse().unwrap(), CrateDep::External("^0.10.0".parse().unwrap())); + deps.main.insert( + "hyper".parse().unwrap(), + CrateDep::External("^0.10.0".parse().unwrap()), + ); let mut analyzer = DependencyAnalyzer::new(&deps, None); analyzer.process(vec![ - CrateRelease { name: "hyper".parse().unwrap(), version: "0.10.0".parse().unwrap(), deps: Default::default(), yanked: false }, - CrateRelease { name: "hyper".parse().unwrap(), version: "0.10.1".parse().unwrap(), deps: Default::default(), yanked: true }, + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.10.0".parse().unwrap(), + deps: Default::default(), + yanked: false, + }, + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.10.1".parse().unwrap(), + deps: Default::default(), + yanked: true, + }, ]); let analyzed = analyzer.finalize(); - assert_eq!(analyzed.main.get("hyper").unwrap().latest_that_matches, Some("0.10.0".parse().unwrap())); - assert_eq!(analyzed.main.get("hyper").unwrap().latest, Some("0.10.0".parse().unwrap())); + assert_eq!( + analyzed.main.get("hyper").unwrap().latest_that_matches, + Some("0.10.0".parse().unwrap()) + ); + assert_eq!( + analyzed.main.get("hyper").unwrap().latest, + Some("0.10.0".parse().unwrap()) + ); } #[test] fn skips_prereleases() { let mut deps = CrateDeps::default(); - deps.main.insert("hyper".parse().unwrap(), CrateDep::External("^0.10.0".parse().unwrap())); + deps.main.insert( + "hyper".parse().unwrap(), + CrateDep::External("^0.10.0".parse().unwrap()), + ); let mut analyzer = DependencyAnalyzer::new(&deps, None); analyzer.process(vec![ - CrateRelease { name: "hyper".parse().unwrap(), version: "0.10.0".parse().unwrap(), deps: Default::default(), yanked: false }, - CrateRelease { name: "hyper".parse().unwrap(), version: "0.10.1-alpha".parse().unwrap(), deps: Default::default(), yanked: false }, + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.10.0".parse().unwrap(), + deps: Default::default(), + yanked: false, + }, + CrateRelease { + name: "hyper".parse().unwrap(), + version: "0.10.1-alpha".parse().unwrap(), + deps: Default::default(), + yanked: false, + }, ]); let analyzed = analyzer.finalize(); - assert_eq!(analyzed.main.get("hyper").unwrap().latest_that_matches, Some("0.10.0".parse().unwrap())); - assert_eq!(analyzed.main.get("hyper").unwrap().latest, Some("0.10.0".parse().unwrap())); + assert_eq!( + analyzed.main.get("hyper").unwrap().latest_that_matches, + Some("0.10.0".parse().unwrap()) + ); + assert_eq!( + analyzed.main.get("hyper").unwrap().latest, + Some("0.10.0".parse().unwrap()) + ); } } diff --git a/src/engine/machines/crawler.rs b/src/engine/machines/crawler.rs index 7c436b9..3fc3768 100644 --- a/src/engine/machines/crawler.rs +++ b/src/engine/machines/crawler.rs @@ -1,49 +1,57 @@ use std::collections::HashMap; use failure::Error; -use relative_path::RelativePathBuf; use indexmap::IndexMap; +use relative_path::RelativePathBuf; +use crate::models::crates::{CrateDep, CrateDeps, CrateManifest, CrateName}; use crate::parsers::manifest::parse_manifest_toml; -use crate::models::crates::{CrateDep, CrateDeps, CrateName, CrateManifest}; pub struct ManifestCrawlerOutput { - pub crates: IndexMap + pub crates: IndexMap, } pub struct ManifestCrawlerStepOutput { - pub paths_of_interest: Vec + pub paths_of_interest: Vec, } pub struct ManifestCrawler { manifests: HashMap, - leaf_crates: IndexMap + leaf_crates: IndexMap, } impl ManifestCrawler { pub fn new() -> ManifestCrawler { ManifestCrawler { manifests: HashMap::new(), - leaf_crates: IndexMap::new() + leaf_crates: IndexMap::new(), } } - pub fn step(&mut self, path: RelativePathBuf, raw_manifest: String) -> Result { + pub fn step( + &mut self, + path: RelativePathBuf, + raw_manifest: String, + ) -> Result { let manifest = parse_manifest_toml(&raw_manifest)?; self.manifests.insert(path.clone(), manifest.clone()); let mut output = ManifestCrawlerStepOutput { - paths_of_interest: vec![] + paths_of_interest: vec![], }; match manifest { CrateManifest::Package(name, deps) => { self.process_package(&path, name, deps, &mut output); - }, + } CrateManifest::Workspace { members } => { self.process_workspace(&path, &members, &mut output); - }, - CrateManifest::Mixed { name, deps, members } => { + } + CrateManifest::Mixed { + name, + deps, + members, + } => { self.process_package(&path, name, deps, &mut output); self.process_workspace(&path, &members, &mut output); } @@ -52,15 +60,31 @@ impl ManifestCrawler { Ok(output) } - fn register_interest(&mut self, base_path: &RelativePathBuf, path: &RelativePathBuf, output: &mut ManifestCrawlerStepOutput) { + fn register_interest( + &mut self, + base_path: &RelativePathBuf, + path: &RelativePathBuf, + output: &mut ManifestCrawlerStepOutput, + ) { let full_path = base_path.join_normalized(path); if !self.manifests.contains_key(&full_path) { output.paths_of_interest.push(full_path); } } - fn process_package(&mut self, base_path: &RelativePathBuf, name: CrateName, deps: CrateDeps, output: &mut ManifestCrawlerStepOutput) { - for (_, dep) in deps.main.iter().chain(deps.dev.iter()).chain(deps.build.iter()) { + fn process_package( + &mut self, + base_path: &RelativePathBuf, + name: CrateName, + deps: CrateDeps, + output: &mut ManifestCrawlerStepOutput, + ) { + for (_, dep) in deps + .main + .iter() + .chain(deps.dev.iter()) + .chain(deps.build.iter()) + { if let &CrateDep::Internal(ref path) = dep { self.register_interest(base_path, path, output); } @@ -69,7 +93,12 @@ impl ManifestCrawler { self.leaf_crates.insert(name, deps); } - fn process_workspace(&mut self, base_path: &RelativePathBuf, members: &[RelativePathBuf], output: &mut ManifestCrawlerStepOutput) { + fn process_workspace( + &mut self, + base_path: &RelativePathBuf, + members: &[RelativePathBuf], + output: &mut ManifestCrawlerStepOutput, + ) { for path in members { if !path.ends_with("*") { self.register_interest(base_path, path, output); @@ -79,7 +108,7 @@ impl ManifestCrawler { pub fn finalize(self) -> ManifestCrawlerOutput { ManifestCrawlerOutput { - crates: self.leaf_crates + crates: self.leaf_crates, } } } @@ -89,8 +118,8 @@ mod tests { use relative_path::RelativePath; use semver::VersionReq; - use models::crates::CrateDep; use super::ManifestCrawler; + use models::crates::CrateDep; #[test] fn simple_package_manifest() { @@ -99,7 +128,9 @@ mod tests { name = "simpleton" "#; let mut crawler = ManifestCrawler::new(); - let step_output = crawler.step("Cargo.toml".into(), manifest.to_string()).unwrap(); + let step_output = crawler + .step("Cargo.toml".into(), manifest.to_string()) + .unwrap(); assert_eq!(step_output.paths_of_interest.len(), 0); let output = crawler.finalize(); assert_eq!(output.crates.len(), 1); @@ -127,16 +158,24 @@ codegen = "0.0.1" let output = crawler.finalize(); assert_eq!(output.crates.len(), 1); assert_eq!(output.crates["more-complex"].main.len(), 2); - assert_eq!(output.crates["more-complex"].main.get("foo").unwrap(), - &CrateDep::External(VersionReq::parse("0.30.0").unwrap())); - assert_eq!(output.crates["more-complex"].main.get("bar").unwrap(), - &CrateDep::External(VersionReq::parse("1.2.0").unwrap())); + assert_eq!( + output.crates["more-complex"].main.get("foo").unwrap(), + &CrateDep::External(VersionReq::parse("0.30.0").unwrap()) + ); + assert_eq!( + output.crates["more-complex"].main.get("bar").unwrap(), + &CrateDep::External(VersionReq::parse("1.2.0").unwrap()) + ); assert_eq!(output.crates["more-complex"].dev.len(), 1); - assert_eq!(output.crates["more-complex"].dev.get("quickcheck").unwrap(), - &CrateDep::External(VersionReq::parse("0.5").unwrap())); + assert_eq!( + output.crates["more-complex"].dev.get("quickcheck").unwrap(), + &CrateDep::External(VersionReq::parse("0.5").unwrap()) + ); assert_eq!(output.crates["more-complex"].build.len(), 1); - assert_eq!(output.crates["more-complex"].build.get("codegen").unwrap(), - &CrateDep::External(VersionReq::parse("0.0.1").unwrap())); + assert_eq!( + output.crates["more-complex"].build.get("codegen").unwrap(), + &CrateDep::External(VersionReq::parse("0.0.1").unwrap()) + ); } #[test] @@ -226,10 +265,17 @@ features = ["use_std"] "#; let mut crawler = ManifestCrawler::new(); - let step_output = crawler.step("".into(), futures_manifest.to_string()).unwrap(); + let step_output = crawler + .step("".into(), futures_manifest.to_string()) + .unwrap(); assert_eq!(step_output.paths_of_interest.len(), 1); assert_eq!(step_output.paths_of_interest[0].as_str(), "futures-cpupool"); - let step_output = crawler.step("futures-cpupool".into(), futures_cpupool_manifest.to_string()).unwrap(); + let step_output = crawler + .step( + "futures-cpupool".into(), + futures_cpupool_manifest.to_string(), + ) + .unwrap(); assert_eq!(step_output.paths_of_interest.len(), 0); let output = crawler.finalize(); assert_eq!(output.crates.len(), 2); @@ -237,10 +283,20 @@ features = ["use_std"] assert_eq!(output.crates["futures"].dev.len(), 0); assert_eq!(output.crates["futures"].build.len(), 0); assert_eq!(output.crates["futures-cpupool"].main.len(), 2); - assert_eq!(output.crates["futures-cpupool"].main.get("num_cpus").unwrap(), - &CrateDep::External(VersionReq::parse("1.0").unwrap())); - assert_eq!(output.crates["futures-cpupool"].main.get("futures").unwrap(), - &CrateDep::Internal(RelativePath::new("..").to_relative_path_buf())); + assert_eq!( + output.crates["futures-cpupool"] + .main + .get("num_cpus") + .unwrap(), + &CrateDep::External(VersionReq::parse("1.0").unwrap()) + ); + assert_eq!( + output.crates["futures-cpupool"] + .main + .get("futures") + .unwrap(), + &CrateDep::Internal(RelativePath::new("..").to_relative_path_buf()) + ); assert_eq!(output.crates["futures-cpupool"].dev.len(), 0); assert_eq!(output.crates["futures-cpupool"].build.len(), 0); } diff --git a/src/engine/machines/mod.rs b/src/engine/machines/mod.rs index c04cbd9..a1f328e 100644 --- a/src/engine/machines/mod.rs +++ b/src/engine/machines/mod.rs @@ -1,2 +1,2 @@ -pub mod crawler; pub mod analyzer; +pub mod crawler; diff --git a/src/interactors/bitbucket.rs b/src/interactors/bitbucket.rs index 00bd678..d695949 100644 --- a/src/interactors/bitbucket.rs +++ b/src/interactors/bitbucket.rs @@ -8,10 +8,12 @@ const BITBUCKET_USER_CONTENT_BASE_URI: &'static str = "https://bitbucket.org"; pub fn get_manifest_uri(repo_path: &RepoPath, path: &RelativePathBuf) -> Result { let path_str: &str = path.as_ref(); - Ok(format!("{}/{}/{}/raw/HEAD/{}", + Ok(format!( + "{}/{}/{}/raw/HEAD/{}", BITBUCKET_USER_CONTENT_BASE_URI, repo_path.qual.as_ref(), repo_path.name.as_ref(), path_str - ).parse::()?) + ) + .parse::()?) } diff --git a/src/interactors/crates.rs b/src/interactors/crates.rs index 7465336..5234425 100644 --- a/src/interactors/crates.rs +++ b/src/interactors/crates.rs @@ -1,13 +1,13 @@ use std::str; use failure::Error; -use futures::{Future, Stream, IntoFuture, future}; +use futures::{future, Future, IntoFuture, Stream}; use hyper::{Error as HyperError, Method, Request, Response, Uri}; -use tokio_service::Service; use semver::{Version, VersionReq}; -use serde_json; +use serde::Deserialize; +use tokio_service::Service; -use crate::models::crates::{CrateName, CrateRelease, CrateDeps, CrateDep, CratePath}; +use crate::models::crates::{CrateDep, CrateDeps, CrateName, CratePath, CrateRelease}; const CRATES_INDEX_BASE_URI: &str = "https://raw.githubusercontent.com/rust-lang/crates.io-index"; const CRATES_API_BASE_URI: &str = "https://crates.io/api/v1"; @@ -17,7 +17,7 @@ struct RegistryPackageDep { name: String, req: VersionReq, #[serde(default)] - kind: Option + kind: Option, } #[derive(Deserialize, Debug)] @@ -26,51 +26,63 @@ struct RegistryPackage { #[serde(default)] deps: Vec, #[serde(default)] - yanked: bool + yanked: bool, } -fn convert_pkgs(name: &CrateName, packages: Vec) -> Result { - let releases = packages.into_iter().map(|package| { - 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(), - version: package.vers, - deps: deps, - yanked: package.yanked +fn convert_pkgs( + name: &CrateName, + packages: Vec, +) -> Result { + let releases = packages + .into_iter() + .map(|package| { + 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(), + version: package.vers, + deps: deps, + yanked: package.yanked, + }) }) - }).collect::>()?; + .collect::>()?; - Ok(QueryCrateResponse { - releases: releases - }) + Ok(QueryCrateResponse { releases: releases }) } pub struct QueryCrateResponse { - pub releases: Vec + pub releases: Vec, } #[derive(Debug, Clone)] pub struct QueryCrate(pub S); impl Service for QueryCrate - where S: Service + Clone + 'static, - S::Future: 'static +where + S: Service + Clone + 'static, + S::Future: 'static, { type Request = CrateName; type Response = QueryCrateResponse; type Error = Error; - type Future = Box>; + type Future = Box>; - fn call(&self, crate_name: CrateName) -> Self::Future { + fn call(&self, crate_name: CrateName) -> Self::Future { let lower_name = crate_name.as_ref().to_lowercase(); let path = match lower_name.len() { @@ -80,8 +92,8 @@ impl Service for QueryCrate _ => format!("{}/{}/{}", &lower_name[0..2], &lower_name[2..4], lower_name), }; - let uri = try_future_box!(format!("{}/master/{}", CRATES_INDEX_BASE_URI, path) - .parse::()); + let uri = + try_future_box!(format!("{}/master/{}", CRATES_INDEX_BASE_URI, path).parse::()); let request = Request::new(Method::Get, uri.clone()); @@ -94,7 +106,8 @@ impl Service for QueryCrate let body_future = response.body().concat2().from_err(); let decode_future = body_future.and_then(move |body| { let string_body = str::from_utf8(body.as_ref())?; - let packages = string_body.lines() + let packages = string_body + .lines() .map(|s| s.trim()) .filter(|s| !s.is_empty()) .map(|s| serde_json::from_str::(s)) @@ -112,38 +125,48 @@ impl Service for QueryCrate #[derive(Deserialize)] struct SummaryResponseDetail { name: String, - max_version: Version + max_version: Version, } #[derive(Deserialize)] struct SummaryResponse { - most_downloaded: Vec + most_downloaded: Vec, } fn convert_summary(response: SummaryResponse) -> Result, Error> { - response.most_downloaded.into_iter().map(|detail| { - let name = detail.name.parse()?; - Ok(CratePath { name, version: detail.max_version }) - }).collect() + response + .most_downloaded + .into_iter() + .map(|detail| { + let name = detail.name.parse()?; + Ok(CratePath { + name, + version: detail.max_version, + }) + }) + .collect() } #[derive(Debug, Clone)] pub struct GetPopularCrates(pub S); impl Service for GetPopularCrates - where S: Service + Clone + 'static, - S::Future: 'static +where + S: Service + Clone + 'static, + S::Future: 'static, { type Request = (); type Response = Vec; type Error = Error; - type Future = Box>; + type Future = Box>; fn call(&self, _req: ()) -> Self::Future { let service = self.0.clone(); let uri_future = format!("{}/summary", CRATES_API_BASE_URI) - .parse::().into_future().from_err(); + .parse::() + .into_future() + .from_err(); Box::new(uri_future.and_then(move |uri| { let request = Request::new(Method::Get, uri.clone()); @@ -151,7 +174,11 @@ impl Service for GetPopularCrates service.call(request).from_err().and_then(move |response| { let status = response.status(); if !status.is_success() { - 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 { let body_future = response.body().concat2().from_err(); let decode_future = body_future.and_then(|body| { diff --git a/src/interactors/github.rs b/src/interactors/github.rs index 9419d17..3725046 100644 --- a/src/interactors/github.rs +++ b/src/interactors/github.rs @@ -1,58 +1,64 @@ use failure::Error; use futures::{Future, Stream}; -use hyper::{Error as HyperError, Method, Request, Response, Uri}; use hyper::header::UserAgent; +use hyper::{Error as HyperError, Method, Request, Response, Uri}; use relative_path::RelativePathBuf; +use serde::Deserialize; use tokio_service::Service; -use serde_json; -use crate::models::repo::{Repository, RepoPath}; +use crate::models::repo::{RepoPath, Repository}; const GITHUB_API_BASE_URI: &'static str = "https://api.github.com"; const GITHUB_USER_CONTENT_BASE_URI: &'static str = "https://raw.githubusercontent.com"; pub fn get_manifest_uri(repo_path: &RepoPath, path: &RelativePathBuf) -> Result { let path_str: &str = path.as_ref(); - Ok(format!("{}/{}/{}/HEAD/{}", + Ok(format!( + "{}/{}/{}/HEAD/{}", GITHUB_USER_CONTENT_BASE_URI, repo_path.qual.as_ref(), repo_path.name.as_ref(), path_str - ).parse::()?) + ) + .parse::()?) } #[derive(Deserialize)] struct GithubSearchResponse { - items: Vec + items: Vec, } #[derive(Deserialize)] struct GithubRepo { name: String, owner: GithubOwner, - description: String + description: String, } #[derive(Deserialize)] struct GithubOwner { - login: String + login: String, } #[derive(Debug, Clone)] pub struct GetPopularRepos(pub S); impl Service for GetPopularRepos - where S: Service + Clone + 'static, - S::Future: 'static +where + S: Service + Clone + 'static, + S::Future: 'static, { type Request = (); type Response = Vec; type Error = Error; - type Future = Box>; + type Future = Box>; fn call(&self, _req: ()) -> Self::Future { - let uri = try_future_box!(format!("{}/search/repositories?q=language:rust&sort=stars", GITHUB_API_BASE_URI) - .parse::()); + let uri = try_future_box!(format!( + "{}/search/repositories?q=language:rust&sort=stars", + GITHUB_API_BASE_URI + ) + .parse::()); let mut request = Request::new(Method::Get, uri); request.headers_mut().set(UserAgent::new("deps.rs")); @@ -60,18 +66,31 @@ impl Service for GetPopularRepos Box::new(self.0.call(request).from_err().and_then(|response| { let status = response.status(); if !status.is_success() { - try_future!(Err(format_err!("Status code {} for popular repo search", status))); + try_future!(Err(format_err!( + "Status code {} for popular repo search", + status + ))); } let body_future = response.body().concat2().from_err(); let decode_future = body_future .and_then(|body| serde_json::from_slice(body.as_ref()).map_err(|err| err.into())); - decode_future.and_then(|search_response: GithubSearchResponse| { - search_response.items.into_iter().map(|item| { - let path = RepoPath::from_parts("github", &item.owner.login, &item.name)?; - Ok(Repository { path, description: item.description }) - }).collect::, _>>() - }).into() + decode_future + .and_then(|search_response: GithubSearchResponse| { + search_response + .items + .into_iter() + .map(|item| { + let path = + RepoPath::from_parts("github", &item.owner.login, &item.name)?; + Ok(Repository { + path, + description: item.description, + }) + }) + .collect::, _>>() + }) + .into() })) } } diff --git a/src/interactors/gitlab.rs b/src/interactors/gitlab.rs index e2c0477..11514b7 100644 --- a/src/interactors/gitlab.rs +++ b/src/interactors/gitlab.rs @@ -1,6 +1,6 @@ +use failure::Error; use hyper::Uri; use relative_path::RelativePathBuf; -use failure::Error; use crate::models::repo::RepoPath; @@ -15,10 +15,12 @@ pub fn get_manifest_uri(repo_path: &RepoPath, path: &RelativePathBuf) -> Result< } else { path_str }; - Ok(format!("{}/{}/{}/raw/HEAD/{}", + Ok(format!( + "{}/{}/{}/raw/HEAD/{}", GITLAB_USER_CONTENT_BASE_URI, repo_path.qual.as_ref(), repo_path.name.as_ref(), slash_path - ).parse::()?) + ) + .parse::()?) } diff --git a/src/interactors/mod.rs b/src/interactors/mod.rs index 0c84d74..dc8b421 100644 --- a/src/interactors/mod.rs +++ b/src/interactors/mod.rs @@ -4,7 +4,7 @@ use hyper::{Error as HyperError, Method, Request, Response}; use relative_path::RelativePathBuf; use tokio_service::Service; -use crate::models::repo::{RepoSite, RepoPath}; +use crate::models::repo::{RepoPath, RepoSite}; pub mod bitbucket; pub mod crates; @@ -16,26 +16,21 @@ pub mod rustsec; pub struct RetrieveFileAtPath(pub S); impl Service for RetrieveFileAtPath - where S: Service + Clone + 'static, - S::Future: 'static +where + S: Service + Clone + 'static, + S::Future: 'static, { type Request = (RepoPath, RelativePathBuf); type Response = String; type Error = Error; - type Future = Box>; + type Future = Box>; fn call(&self, req: Self::Request) -> Self::Future { let (repo_path, path) = req; let uri = match &repo_path.site { - &RepoSite::Github => { - try_future_box!(github::get_manifest_uri(&repo_path, &path)) - }, - &RepoSite::Gitlab => { - try_future_box!(gitlab::get_manifest_uri(&repo_path, &path)) - }, - &RepoSite::Bitbucket => { - try_future_box!(bitbucket::get_manifest_uri(&repo_path, &path)) - } + &RepoSite::Github => try_future_box!(github::get_manifest_uri(&repo_path, &path)), + &RepoSite::Gitlab => try_future_box!(gitlab::get_manifest_uri(&repo_path, &path)), + &RepoSite::Bitbucket => try_future_box!(bitbucket::get_manifest_uri(&repo_path, &path)), }; let request = Request::new(Method::Get, uri.clone()); diff --git a/src/interactors/rustsec.rs b/src/interactors/rustsec.rs index 1622769..93f5c2f 100644 --- a/src/interactors/rustsec.rs +++ b/src/interactors/rustsec.rs @@ -2,23 +2,24 @@ use std::str; use std::sync::Arc; use failure::Error; -use futures::{Future, IntoFuture, Stream, future}; +use futures::{future, Future, IntoFuture, Stream}; use hyper::{Error as HyperError, Method, Request, Response}; -use rustsec::ADVISORY_DB_URL; use rustsec::db::AdvisoryDatabase; +use rustsec::ADVISORY_DB_URL; use tokio_service::Service; #[derive(Debug, Clone)] pub struct FetchAdvisoryDatabase(pub S); impl Service for FetchAdvisoryDatabase - where S: Service + Clone + 'static, - S::Future: 'static +where + S: Service + Clone + 'static, + S::Future: 'static, { type Request = (); type Response = Arc; type Error = Error; - type Future = Box>; + type Future = Box>; fn call(&self, _req: ()) -> Self::Future { let service = self.0.clone(); @@ -31,11 +32,17 @@ impl Service for FetchAdvisoryDatabase service.call(request).from_err().and_then(|response| { let status = response.status(); if !status.is_success() { - future::Either::A(future::err(format_err!("Status code {} when fetching advisory db", status))) + future::Either::A(future::err(format_err!( + "Status code {} when fetching advisory db", + status + ))) } else { let body_future = response.body().concat2().from_err(); - let decode_future = body_future - .and_then(|body| Ok(Arc::new(AdvisoryDatabase::from_toml(str::from_utf8(&body)?)?))); + let decode_future = body_future.and_then(|body| { + Ok(Arc::new(AdvisoryDatabase::from_toml(str::from_utf8( + &body, + )?)?)) + }); future::Either::B(decode_future) } }) diff --git a/src/main.rs b/src/main.rs index 0f93a0e..de77c47 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,6 @@ #[macro_use] extern crate failure; #[macro_use] -extern crate serde_derive; -#[macro_use] extern crate slog; #[macro_use] extern crate try_future; diff --git a/src/models/crates.rs b/src/models/crates.rs index 3fc60ed..9d7d294 100644 --- a/src/models/crates.rs +++ b/src/models/crates.rs @@ -9,14 +9,14 @@ use semver::{Version, VersionReq}; #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct CratePath { pub name: CrateName, - pub version: Version + pub version: Version, } impl CratePath { pub fn from_parts(name: &str, version: &str) -> Result { Ok(CratePath { name: name.parse()?, - version: version.parse()? + version: version.parse()?, }) } } @@ -46,9 +46,9 @@ impl FromStr for CrateName { type Err = Error; fn from_str(input: &str) -> Result { - let is_valid = input.chars().all(|c| { - c.is_ascii_alphanumeric() || c == '_' || c == '-' - }); + let is_valid = input + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'); if !is_valid { Err(format_err!("failed to validate crate name: {}", input)) @@ -63,13 +63,13 @@ pub struct CrateRelease { pub name: CrateName, pub version: Version, pub deps: CrateDeps, - pub yanked: bool + pub yanked: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub enum CrateDep { External(VersionReq), - Internal(RelativePathBuf) + Internal(RelativePathBuf), } impl CrateDep { @@ -86,7 +86,7 @@ impl CrateDep { pub struct CrateDeps { pub main: IndexMap, pub dev: IndexMap, - pub build: IndexMap + pub build: IndexMap, } #[derive(Debug)] @@ -94,7 +94,7 @@ pub struct AnalyzedDependency { pub required: VersionReq, pub latest_that_matches: Option, pub latest: Option, - pub insecure: bool + pub insecure: bool, } impl AnalyzedDependency { @@ -103,7 +103,7 @@ impl AnalyzedDependency { required, latest_that_matches: None, latest: None, - insecure: false + insecure: false, } } @@ -116,32 +116,44 @@ impl AnalyzedDependency { pub struct AnalyzedDependencies { pub main: IndexMap, pub dev: IndexMap, - pub build: IndexMap + pub build: IndexMap, } impl AnalyzedDependencies { pub fn new(deps: &CrateDeps) -> AnalyzedDependencies { - let main = deps.main.iter().filter_map(|(name, dep)| { - if let &CrateDep::External(ref req) = dep { - Some((name.clone(), AnalyzedDependency::new(req.clone()))) - } else { - None - } - }).collect(); - let dev = deps.dev.iter().filter_map(|(name, dep)| { - if let &CrateDep::External(ref req) = dep { - Some((name.clone(), AnalyzedDependency::new(req.clone()))) - } else { - None - } - }).collect(); - let build = deps.build.iter().filter_map(|(name, dep)| { - if let &CrateDep::External(ref req) = dep { - Some((name.clone(), AnalyzedDependency::new(req.clone()))) - } else { - None - } - }).collect(); + let main = deps + .main + .iter() + .filter_map(|(name, dep)| { + if let &CrateDep::External(ref req) = dep { + Some((name.clone(), AnalyzedDependency::new(req.clone()))) + } else { + None + } + }) + .collect(); + let dev = deps + .dev + .iter() + .filter_map(|(name, dep)| { + if let &CrateDep::External(ref req) = dep { + Some((name.clone(), AnalyzedDependency::new(req.clone()))) + } else { + None + } + }) + .collect(); + let build = deps + .build + .iter() + .filter_map(|(name, dep)| { + if let &CrateDep::External(ref req) = dep { + Some((name.clone(), AnalyzedDependency::new(req.clone()))) + } else { + None + } + }) + .collect(); AnalyzedDependencies { main, dev, build } } @@ -150,38 +162,35 @@ impl AnalyzedDependencies { } pub fn count_outdated(&self) -> usize { - let main_outdated = self.main.iter() + let main_outdated = self + .main + .iter() .filter(|&(_, dep)| dep.is_outdated()) .count(); - let dev_outdated = self.dev.iter() + let dev_outdated = self + .dev + .iter() .filter(|&(_, dep)| dep.is_outdated()) .count(); - let build_outdated = self.build.iter() + let build_outdated = self + .build + .iter() .filter(|&(_, dep)| dep.is_outdated()) .count(); main_outdated + dev_outdated + build_outdated } - pub fn count_insecure(&self) -> usize { - let main_insecure = self.main.iter() - .filter(|&(_, dep)| dep.insecure) - .count(); - let dev_insecure = self.dev.iter() - .filter(|&(_, dep)| dep.insecure) - .count(); - let build_insecure = self.build.iter() - .filter(|&(_, dep)| dep.insecure) - .count(); + pub fn count_insecure(&self) -> usize { + let main_insecure = self.main.iter().filter(|&(_, dep)| dep.insecure).count(); + let dev_insecure = self.dev.iter().filter(|&(_, dep)| dep.insecure).count(); + let build_insecure = self.build.iter().filter(|&(_, dep)| dep.insecure).count(); main_insecure + dev_insecure + build_insecure - } + } 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()); + 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 } } @@ -189,6 +198,12 @@ impl AnalyzedDependencies { #[derive(Clone, Debug)] pub enum CrateManifest { Package(CrateName, CrateDeps), - Workspace { members: Vec }, - Mixed { name: CrateName, deps: CrateDeps, members: Vec } + Workspace { + members: Vec, + }, + Mixed { + name: CrateName, + deps: CrateDeps, + members: Vec, + }, } diff --git a/src/models/mod.rs b/src/models/mod.rs index 5f3bd04..ea98907 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -3,5 +3,5 @@ pub mod repo; pub enum SubjectPath { Repo(self::repo::RepoPath), - Crate(self::crates::CratePath) + Crate(self::crates::CratePath), } diff --git a/src/models/repo.rs b/src/models/repo.rs index d6a7fd1..885c190 100644 --- a/src/models/repo.rs +++ b/src/models/repo.rs @@ -5,14 +5,14 @@ use failure::Error; #[derive(Clone, Debug)] pub struct Repository { pub path: RepoPath, - pub description: String + pub description: String, } #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct RepoPath { pub site: RepoSite, pub qual: RepoQualifier, - pub name: RepoName + pub name: RepoName, } impl RepoPath { @@ -20,7 +20,7 @@ impl RepoPath { Ok(RepoPath { site: site.parse()?, qual: qual.parse()?, - name: name.parse()? + name: name.parse()?, }) } } @@ -50,7 +50,7 @@ impl FromStr for RepoSite { "github" => Ok(RepoSite::Github), "gitlab" => Ok(RepoSite::Gitlab), "bitbucket" => Ok(RepoSite::Bitbucket), - _ => Err(format_err!("unknown repo site identifier")) + _ => Err(format_err!("unknown repo site identifier")), } } } @@ -72,9 +72,9 @@ impl FromStr for RepoQualifier { type Err = Error; fn from_str(input: &str) -> Result { - let is_valid = input.chars().all(|c| { - c.is_ascii_alphanumeric() || c == '.' || c == '-' || c == '_' - }); + let is_valid = input + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '-' || c == '_'); ensure!(is_valid, "invalid repo qualifier"); Ok(RepoQualifier(input.to_string())) @@ -94,9 +94,9 @@ impl FromStr for RepoName { type Err = Error; fn from_str(input: &str) -> Result { - let is_valid = input.chars().all(|c| { - c.is_ascii_alphanumeric() || c == '.' || c == '-' || c == '_' - }); + let is_valid = input + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '-' || c == '_'); ensure!(is_valid, "invalid repo name"); Ok(RepoName(input.to_string())) diff --git a/src/parsers/manifest.rs b/src/parsers/manifest.rs index 46dc9ad..19f900c 100644 --- a/src/parsers/manifest.rs +++ b/src/parsers/manifest.rs @@ -2,33 +2,33 @@ use failure::Error; use indexmap::IndexMap; use relative_path::RelativePathBuf; use semver::VersionReq; -use toml; +use serde::{Deserialize, Serialize}; -use crate::models::crates::{CrateName, CrateDep, CrateDeps, CrateManifest}; +use crate::models::crates::{CrateDep, CrateDeps, CrateManifest, CrateName}; #[derive(Serialize, Deserialize, Debug)] struct CargoTomlComplexDependency { git: Option, path: Option, - version: Option + version: Option, } #[derive(Serialize, Deserialize, Debug)] #[serde(untagged)] enum CargoTomlDependency { Simple(String), - Complex(CargoTomlComplexDependency) + Complex(CargoTomlComplexDependency), } #[derive(Serialize, Deserialize, Debug)] struct CargoTomlPackage { - name: String + name: String, } #[derive(Serialize, Deserialize, Debug)] struct CargoTomlWorkspace { #[serde(default)] - members: Vec + members: Vec, } #[derive(Serialize, Deserialize, Debug)] @@ -44,32 +44,42 @@ struct CargoToml { dev_dependencies: IndexMap, #[serde(rename = "build-dependencies")] #[serde(default)] - build_dependencies: IndexMap + build_dependencies: IndexMap, } -fn convert_dependency(cargo_dep: (String, CargoTomlDependency)) -> Option> { +fn convert_dependency( + cargo_dep: (String, CargoTomlDependency), +) -> Option> { match cargo_dep { - (name, CargoTomlDependency::Simple(string)) => { - Some(name.parse::().map_err(|err| err.into()).and_then(|parsed_name| { - string.parse::().map_err(|err| err.into()) - .map(|version| (parsed_name, CrateDep::External(version))) - })) - } + (name, CargoTomlDependency::Simple(string)) => Some( + name.parse::() + .map_err(|err| err.into()) + .and_then(|parsed_name| { + string + .parse::() + .map_err(|err| err.into()) + .map(|version| (parsed_name, CrateDep::External(version))) + }), + ), (name, CargoTomlDependency::Complex(cplx)) => { if cplx.git.is_some() { None } else if cplx.path.is_some() { cplx.path.map(|path| { - name.parse::().map_err(|err| err.into()).map(|parsed_name| { - (parsed_name, CrateDep::Internal(path)) - }) + name.parse::() + .map_err(|err| err.into()) + .map(|parsed_name| (parsed_name, CrateDep::Internal(path))) }) } else { cplx.version.map(|string| { - name.parse::().map_err(|err| err.into()).and_then(|parsed_name| { - string.parse::().map_err(|err| err.into()) - .map(|version| (parsed_name, CrateDep::External(version))) - }) + name.parse::() + .map_err(|err| err.into()) + .and_then(|parsed_name| { + string + .parse::() + .map_err(|err| err.into()) + .map(|version| (parsed_name, CrateDep::External(version))) + }) }) } } @@ -82,20 +92,29 @@ pub fn parse_manifest_toml(input: &str) -> Result { let mut package_part = None; let mut workspace_part = None; - if let Some(package) = cargo_toml.package { + if let Some(package) = cargo_toml.package { let crate_name = package.name.parse::()?; - let dependencies = cargo_toml.dependencies - .into_iter().filter_map(convert_dependency).collect::, _>>()?; - let dev_dependencies = cargo_toml.dev_dependencies - .into_iter().filter_map(convert_dependency).collect::, _>>()?; - let build_dependencies = cargo_toml.build_dependencies - .into_iter().filter_map(convert_dependency).collect::, _>>()?; + let dependencies = cargo_toml + .dependencies + .into_iter() + .filter_map(convert_dependency) + .collect::, _>>()?; + let dev_dependencies = cargo_toml + .dev_dependencies + .into_iter() + .filter_map(convert_dependency) + .collect::, _>>()?; + let build_dependencies = cargo_toml + .build_dependencies + .into_iter() + .filter_map(convert_dependency) + .collect::, _>>()?; let deps = CrateDeps { main: dependencies, dev: dev_dependencies, - build: build_dependencies + build: build_dependencies, }; package_part = Some((crate_name, deps)); @@ -106,21 +125,23 @@ pub fn parse_manifest_toml(input: &str) -> Result { } match (package_part, workspace_part) { - (Some((name, deps)), None) => - Ok(CrateManifest::Package(name, deps)), - (None, Some(members)) => - Ok(CrateManifest::Workspace { members }), - (Some((name, deps)), Some(members)) => - Ok(CrateManifest::Mixed { name, deps, members }), - (None, None) => - Err(format_err!("neither workspace nor package found in manifest")) + (Some((name, deps)), None) => Ok(CrateManifest::Package(name, deps)), + (None, Some(members)) => Ok(CrateManifest::Workspace { members }), + (Some((name, deps)), Some(members)) => Ok(CrateManifest::Mixed { + name, + deps, + members, + }), + (None, None) => Err(format_err!( + "neither workspace nor package found in manifest" + )), } } #[cfg(test)] mod tests { - use models::crates::CrateManifest; use super::parse_manifest_toml; + use models::crates::CrateManifest; #[test] fn parse_workspace_without_members_declaration() { @@ -136,14 +157,18 @@ symbolic-common = { version = "2.0.6", path = "common" } let manifest = parse_manifest_toml(toml).unwrap(); match manifest { - CrateManifest::Mixed { name, deps, members } => { + CrateManifest::Mixed { + name, + deps, + members, + } => { assert_eq!(name.as_ref(), "symbolic"); assert_eq!(deps.main.len(), 1); assert_eq!(deps.dev.len(), 0); assert_eq!(deps.build.len(), 0); assert_eq!(members.len(), 0); - }, - _ => panic!("expected mixed manifest") + } + _ => panic!("expected mixed manifest"), } } } diff --git a/src/server/assets.rs b/src/server/assets.rs index 2aad748..1f2666c 100644 --- a/src/server/assets.rs +++ b/src/server/assets.rs @@ -1,4 +1,2 @@ -pub static STATIC_STYLE_CSS: &'static str = - include_str!(concat!(env!("OUT_DIR"), "/style.css")); -pub static STATIC_FAVICON_PNG: &'static [u8; 1338] = - include_bytes!("../../assets/favicon.png"); +pub static STATIC_STYLE_CSS: &'static str = include_str!(concat!(env!("OUT_DIR"), "/style.css")); +pub static STATIC_FAVICON_PNG: &'static [u8; 1338] = include_bytes!("../../assets/favicon.png"); diff --git a/src/server/views/badge.rs b/src/server/views/badge.rs index 3f6f68a..2c03a17 100644 --- a/src/server/views/badge.rs +++ b/src/server/views/badge.rs @@ -1,6 +1,6 @@ use badge::{Badge, BadgeOptions}; -use hyper::Response; use hyper::header::ContentType; +use hyper::Response; use crate::engine::AnalyzeDependenciesOutcome; @@ -11,7 +11,7 @@ pub fn badge(analysis_outcome: Option<&AnalyzeDependenciesOutcome>) -> Badge { BadgeOptions { subject: "dependencies".into(), status: "insecure".into(), - color: "#e05d44".into() + color: "#e05d44".into(), } } else { let (outdated, total) = outcome.outdated_ratio(); @@ -20,30 +20,28 @@ pub fn badge(analysis_outcome: Option<&AnalyzeDependenciesOutcome>) -> Badge { BadgeOptions { subject: "dependencies".into(), status: format!("{} of {} outdated", outdated, total), - color: "#dfb317".into() + color: "#dfb317".into(), } } else if total > 0 { BadgeOptions { subject: "dependencies".into(), status: "up to date".into(), - color: "#4c1".into() + color: "#4c1".into(), } } else { BadgeOptions { subject: "dependencies".into(), status: "none".into(), - color: "#4c1".into() + color: "#4c1".into(), } } } - }, - None => { - BadgeOptions { - subject: "dependencies".into(), - status: "unknown".into(), - color: "#9f9f9f".into() - } } + None => BadgeOptions { + subject: "dependencies".into(), + status: "unknown".into(), + color: "#9f9f9f".into(), + }, }; Badge::new(opts) diff --git a/src/server/views/html/error.rs b/src/server/views/html/error.rs index 7b0875f..4a668a4 100644 --- a/src/server/views/html/error.rs +++ b/src/server/views/html/error.rs @@ -1,19 +1,22 @@ use hyper::Response; use maud::html; -pub fn render(title: &str, descr: &str) -> Response { - super::render_html(title, html! { - section class="hero is-light" { - div class="hero-head" { (super::render_navbar()) } - } - section class="section" { - div class="container" { - div class="notification is-danger" { - p class="title is-3" { (title) } - p { (descr) } +pub fn render(title: &str, descr: &str) -> Response { + super::render_html( + title, + html! { + section class="hero is-light" { + div class="hero-head" { (super::render_navbar()) } + } + section class="section" { + div class="container" { + div class="notification is-danger" { + p class="title is-3" { (title) } + p { (descr) } + } } } - } - (super::render_footer(None)) - }) + (super::render_footer(None)) + }, + ) } diff --git a/src/server/views/html/index.rs b/src/server/views/html/index.rs index 8e2aba4..bc413b3 100644 --- a/src/server/views/html/index.rs +++ b/src/server/views/html/index.rs @@ -1,8 +1,8 @@ use hyper::Response; -use maud::{Markup, html}; +use maud::{html, Markup}; -use crate::models::repo::Repository; use crate::models::crates::CratePath; +use crate::models::repo::Repository; fn popular_table(popular_repos: Vec, popular_crates: Vec) -> Markup { html! { @@ -64,23 +64,26 @@ fn popular_table(popular_repos: Vec, popular_crates: Vec) } pub fn render(popular_repos: Vec, popular_crates: Vec) -> Response { - super::render_html("Keep your dependencies up-to-date", html! { - section class="hero is-light" { - div class="hero-head" { (super::render_navbar()) } - div class="hero-body" { - div class="container" { - p class="title is-1" { "Keep your dependencies up-to-date" } - p { - "Deps.rs uses semantic versioning to detect outdated or insecure dependencies in your project's" - code { "Cargo.toml" } - "." + super::render_html( + "Keep your dependencies up-to-date", + html! { + section class="hero is-light" { + div class="hero-head" { (super::render_navbar()) } + div class="hero-body" { + div class="container" { + p class="title is-1" { "Keep your dependencies up-to-date" } + p { + "Deps.rs uses semantic versioning to detect outdated or insecure dependencies in your project's" + code { "Cargo.toml" } + "." + } } } } - } - section class="section" { - div class="container" { (popular_table(popular_repos, popular_crates)) } - } - (super::render_footer(None)) - }) + section class="section" { + div class="container" { (popular_table(popular_repos, popular_crates)) } + } + (super::render_footer(None)) + }, + ) } diff --git a/src/server/views/html/mod.rs b/src/server/views/html/mod.rs index f8245b1..be800ac 100644 --- a/src/server/views/html/mod.rs +++ b/src/server/views/html/mod.rs @@ -1,11 +1,11 @@ use std::time::Duration; -use hyper::Response; use hyper::header::ContentType; -use maud::{Markup, Render, html}; +use hyper::Response; +use maud::{html, Markup, Render}; -pub mod index; pub mod error; +pub mod index; pub mod status; use super::super::SELF_BASE_URL; @@ -47,7 +47,8 @@ fn render_navbar() -> Markup { } fn render_footer(duration: Option) -> Markup { - let duration_millis = duration.map(|d| d.as_secs() * 1000 + (d.subsec_nanos() / 1000 / 1000) as u64); + let duration_millis = + duration.map(|d| d.as_secs() * 1000 + (d.subsec_nanos() / 1000 / 1000) as u64); html! { footer class="footer" { diff --git a/src/server/views/html/status.rs b/src/server/views/html/status.rs index c64a87b..7b7971d 100644 --- a/src/server/views/html/status.rs +++ b/src/server/views/html/status.rs @@ -1,11 +1,11 @@ use hyper::Response; -use maud::{Markup, html}; use indexmap::IndexMap; +use maud::{html, Markup}; use crate::engine::AnalyzeDependenciesOutcome; -use crate::models::crates::{CrateName, AnalyzedDependency, AnalyzedDependencies}; -use crate::models::SubjectPath; +use crate::models::crates::{AnalyzedDependencies, AnalyzedDependency, CrateName}; use crate::models::repo::RepoSite; +use crate::models::SubjectPath; use super::super::badge; @@ -94,7 +94,7 @@ fn get_site_icon(site: &RepoSite) -> &'static str { match *site { RepoSite::Github => "fa-github", RepoSite::Gitlab => "fa-gitlab", - RepoSite::Bitbucket => "fa-bitbucket" + RepoSite::Bitbucket => "fa-bitbucket", } } @@ -108,7 +108,7 @@ fn render_title(subject_path: &SubjectPath) -> Markup { (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)) { @@ -144,18 +144,26 @@ fn render_failure(subject_path: SubjectPath) -> Markup { } } -fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, subject_path: SubjectPath) -> Markup { +fn render_success( + analysis_outcome: AnalyzeDependenciesOutcome, + subject_path: SubjectPath, +) -> Markup { 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) => + 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_data_uri = badge::badge(Some(&analysis_outcome)).to_svg_data_uri(); - let hero_class = if analysis_outcome.any_insecure() { + let hero_class = if analysis_outcome.any_insecure() { "is-danger" } else if analysis_outcome.any_outdated() { "is-warning" @@ -194,12 +202,17 @@ fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, subject_path: Su } } -pub fn render(analysis_outcome: Option, subject_path: SubjectPath) -> Response { +pub fn render( + analysis_outcome: Option, + subject_path: SubjectPath, +) -> Response { 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) => + 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 { diff --git a/src/server/views/mod.rs b/src/server/views/mod.rs index 387fe62..efbdb0f 100644 --- a/src/server/views/mod.rs +++ b/src/server/views/mod.rs @@ -1,2 +1,2 @@ -pub mod html; pub mod badge; +pub mod html; diff --git a/src/utils/cache.rs b/src/utils/cache.rs index 80303fe..a96663c 100644 --- a/src/utils/cache.rs +++ b/src/utils/cache.rs @@ -1,28 +1,30 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; use std::hash::Hash; -use std::time::{Duration, Instant}; use std::ops::Deref; use std::sync::Mutex; +use std::time::{Duration, Instant}; use failure::Error; -use futures::{Future, Poll}; use futures::future::{FromErr, Shared, SharedItem}; +use futures::{Future, Poll}; use lru_cache::LruCache; use shared_failure::SharedFailure; use tokio_service::Service; pub struct Cache - where S: Service, - S::Request: Hash + Eq +where + S: Service, + S::Request: Hash + Eq, { inner: S, duration: Duration, - cache: Mutex>)>> + cache: Mutex>)>>, } impl Debug for Cache - where S: Service + Debug, - S::Request: Hash + Eq +where + S: Service + Debug, + S::Request: Hash + Eq, { fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult { fmt.debug_struct("Cache") @@ -32,22 +34,24 @@ impl Debug for Cache } } -impl Cache - where S: Service, - S::Request: Hash + Eq +impl Cache +where + S: Service, + S::Request: Hash + Eq, { pub fn new(service: S, duration: Duration, capacity: usize) -> Cache { Cache { inner: service, duration: duration, - cache: Mutex::new(LruCache::new(capacity)) + cache: Mutex::new(LruCache::new(capacity)), } } } impl Service for Cache - where S: Service, - S::Request: Clone + Hash + Eq +where + S: Service, + S::Request: Clone + Hash + Eq, { type Request = S::Request; type Response = CachedItem; @@ -70,23 +74,25 @@ impl Service for Cache } } -pub struct Cached>(Shared>); +pub struct Cached>(Shared>); impl Debug for Cached - where F: Future + Debug, - F::Item: Debug +where + F: Future + Debug, + F::Item: Debug, { fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult { self.0.fmt(fmt) } } -impl> Future for Cached { +impl> Future for Cached { type Item = CachedItem; type Error = SharedFailure; fn poll(&mut self) -> Poll { - self.0.poll() + self.0 + .poll() .map_err(|err| (*err).clone()) .map(|_async| _async.map(CachedItem)) }