prepare for multi-crate repos

This commit is contained in:
Sam Rijs 2018-01-27 12:17:50 +11:00
parent 28f5cf7ba2
commit eb1bd1b698
4 changed files with 43 additions and 14 deletions

View file

@ -26,7 +26,7 @@ pub struct Api {
impl Api { impl Api {
pub fn new(engine: Engine) -> Api { pub fn new(engine: Engine) -> Api {
let mut router = Router::new(); let mut router = Router::new();
router.add("/api/v1/analyze/:site/:qual/:name", Route::AnalyzeDependencies); router.add("/repo/:site/:qual/:name/dependencies.json", Route::AnalyzeDependencies);
Api { engine, router: Arc::new(router) } Api { engine, router: Arc::new(router) }
} }
@ -40,7 +40,7 @@ struct AnalyzeDependenciesResponseDetail {
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
struct AnalyzeDependenciesResponse { struct AnalyzeDependenciesResponseSingle {
dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail>, dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail>,
#[serde(rename="dev-dependencies")] #[serde(rename="dev-dependencies")]
dev_dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail>, dev_dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail>,
@ -48,6 +48,11 @@ struct AnalyzeDependenciesResponse {
build_dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail> build_dependencies: BTreeMap<String, AnalyzeDependenciesResponseDetail>
} }
#[derive(Debug, Serialize)]
struct AnalyzeDependenciesResponse {
crates: BTreeMap<String, AnalyzeDependenciesResponseSingle>
}
impl Service for Api { impl Service for Api {
type Request = Request; type Request = Request;
type Response = Response; type Response = Response;
@ -96,30 +101,33 @@ impl Api {
response.set_body(format!("{:?}", err)); response.set_body(format!("{:?}", err));
future::Either::A(future::ok(response)) future::Either::A(future::ok(response))
}, },
Ok(dependencies) => { Ok(analysis_outcome) => {
let response_struct = AnalyzeDependenciesResponse { let single = AnalyzeDependenciesResponseSingle {
dependencies: dependencies.main.into_iter() dependencies: analysis_outcome.deps.main.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail { .map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(), outdated: analyzed.is_outdated(),
required: analyzed.required, required: analyzed.required,
latest: analyzed.latest latest: analyzed.latest
})).collect(), })).collect(),
dev_dependencies: dependencies.dev.into_iter() dev_dependencies: analysis_outcome.deps.dev.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail { .map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(), outdated: analyzed.is_outdated(),
required: analyzed.required, required: analyzed.required,
latest: analyzed.latest latest: analyzed.latest
})).collect(), })).collect(),
build_dependencies: dependencies.build.into_iter() build_dependencies: analysis_outcome.deps.build.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail { .map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(), outdated: analyzed.is_outdated(),
required: analyzed.required, required: analyzed.required,
latest: analyzed.latest latest: analyzed.latest
})).collect() })).collect()
}; };
let multi = AnalyzeDependenciesResponse {
crates: vec![(analysis_outcome.name.into(), single)].into_iter().collect()
};
let mut response = Response::new() let mut response = Response::new()
.with_header(ContentType::json()) .with_header(ContentType::json())
.with_body(serde_json::to_string(&response_struct).unwrap()); .with_body(serde_json::to_string(&multi).unwrap());
future::Either::B(future::ok(response)) future::Either::B(future::ok(response))
} }
} }

View file

@ -31,15 +31,20 @@ pub enum AnalyzeDependenciesError {
const FETCH_RELEASES_CONCURRENCY: usize = 10; const FETCH_RELEASES_CONCURRENCY: usize = 10;
pub struct AnalyzeDependenciesOutcome {
pub name: CrateName,
pub deps: AnalyzedDependencies
}
impl Engine { impl Engine {
pub fn analyze_dependencies(&self, repo_path: RepoPath) -> pub fn analyze_dependencies(&self, repo_path: RepoPath) ->
impl Future<Item=AnalyzedDependencies, Error=AnalyzeDependenciesError> impl Future<Item=AnalyzeDependenciesOutcome, Error=AnalyzeDependenciesError>
{ {
let manifest_future = self.retrieve_manifest(&repo_path); let manifest_future = self.retrieve_manifest(&repo_path);
let engine = self.clone(); let engine = self.clone();
manifest_future.and_then(move |manifest| { manifest_future.and_then(move |manifest| {
let CrateManifest::Crate(deps) = manifest; let CrateManifest::Crate(crate_name, deps) = manifest;
let analyzer = DependencyAnalyzer::new(&deps); let analyzer = DependencyAnalyzer::new(&deps);
let main_deps = deps.main.into_iter().map(|(name, _)| name); let main_deps = deps.main.into_iter().map(|(name, _)| name);
@ -48,10 +53,17 @@ impl Engine {
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));
stream::iter_ok(release_futures) let analyzed_deps_future = stream::iter_ok(release_futures)
.buffer_unordered(FETCH_RELEASES_CONCURRENCY) .buffer_unordered(FETCH_RELEASES_CONCURRENCY)
.fold(analyzer, |mut analyzer, releases| { analyzer.process(releases); Ok(analyzer) }) .fold(analyzer, |mut analyzer, releases| { analyzer.process(releases); Ok(analyzer) })
.map(|analyzer| analyzer.finalize()) .map(|analyzer| analyzer.finalize());
analyzed_deps_future.map(move |analyzed_deps| {
AnalyzeDependenciesOutcome {
name: crate_name,
deps: analyzed_deps
}
})
}) })
} }

View file

@ -96,5 +96,5 @@ impl AnalyzedDependencies {
#[derive(Debug)] #[derive(Debug)]
pub enum CrateManifest { pub enum CrateManifest {
Crate(CrateDeps) Crate(CrateName, CrateDeps)
} }

View file

@ -26,8 +26,14 @@ enum CargoTomlDependency {
Complex(CargoTomlComplexDependency) Complex(CargoTomlComplexDependency)
} }
#[derive(Serialize, Deserialize, Debug)]
struct CargoTomlPackage {
name: String
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
struct CargoToml { struct CargoToml {
package: CargoTomlPackage,
#[serde(default)] #[serde(default)]
dependencies: BTreeMap<String, CargoTomlDependency>, dependencies: BTreeMap<String, CargoTomlDependency>,
#[serde(rename = "dev-dependencies")] #[serde(rename = "dev-dependencies")]
@ -65,6 +71,9 @@ pub fn parse_manifest_toml(input: &str) -> Result<CrateManifest, ManifestParseEr
let cargo_toml = toml::de::from_str::<CargoToml>(input) let cargo_toml = toml::de::from_str::<CargoToml>(input)
.map_err(ManifestParseError::Serde)?; .map_err(ManifestParseError::Serde)?;
let crate_name = cargo_toml.package.name.parse()
.map_err(ManifestParseError::Name)?;
let dependencies = cargo_toml.dependencies let dependencies = cargo_toml.dependencies
.into_iter().filter_map(convert_dependency).collect::<Result<BTreeMap<_, _>, _>>()?; .into_iter().filter_map(convert_dependency).collect::<Result<BTreeMap<_, _>, _>>()?;
let dev_dependencies = cargo_toml.dev_dependencies let dev_dependencies = cargo_toml.dev_dependencies
@ -78,5 +87,5 @@ pub fn parse_manifest_toml(input: &str) -> Result<CrateManifest, ManifestParseEr
build: build_dependencies build: build_dependencies
}; };
Ok(CrateManifest::Crate(deps)) Ok(CrateManifest::Crate(crate_name, deps))
} }