diff options
Diffstat (limited to 'cli/npm/resolution')
-rw-r--r-- | cli/npm/resolution/graph.rs | 30 | ||||
-rw-r--r-- | cli/npm/resolution/mod.rs | 50 |
2 files changed, 48 insertions, 32 deletions
diff --git a/cli/npm/resolution/graph.rs b/cli/npm/resolution/graph.rs index 497067925..b56df35ae 100644 --- a/cli/npm/resolution/graph.rs +++ b/cli/npm/resolution/graph.rs @@ -415,7 +415,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi> &self, name: &str, version_matcher: &impl NpmVersionMatcher, - package_info: NpmPackageInfo, + package_info: &NpmPackageInfo, ) -> Result<VersionAndInfo, AnyError> { if let Some(version) = self.resolve_best_package_version(name, version_matcher) @@ -462,10 +462,14 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi> maybe_best_version.cloned() } + pub fn has_package_req(&self, req: &NpmPackageReq) -> bool { + self.graph.has_package_req(req) + } + pub fn add_package_req( &mut self, package_req: &NpmPackageReq, - package_info: NpmPackageInfo, + package_info: &NpmPackageInfo, ) -> Result<(), AnyError> { let node = self.resolve_node_from_info( &package_req.name, @@ -484,7 +488,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi> fn analyze_dependency( &mut self, entry: &NpmDependencyEntry, - package_info: NpmPackageInfo, + package_info: &NpmPackageInfo, parent_id: &NpmPackageId, visited_versions: &Arc<VisitedVersionsPath>, ) -> Result<(), AnyError> { @@ -536,7 +540,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi> &mut self, name: &str, version_matcher: &impl NpmVersionMatcher, - package_info: NpmPackageInfo, + package_info: &NpmPackageInfo, ) -> Result<Arc<Mutex<Node>>, AnyError> { let version_and_info = self.resolve_best_package_version_and_info( name, @@ -613,7 +617,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi> NpmDependencyEntryKind::Dep => { self.analyze_dependency( dep, - package_info, + &package_info, &parent_id, &visited_versions, )?; @@ -624,7 +628,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi> &dep.bare_specifier, &parent_id, dep, - package_info, + &package_info, &visited_versions, )?; if let Some(new_parent_id) = maybe_new_parent_id { @@ -647,7 +651,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi> specifier: &str, parent_id: &NpmPackageId, peer_dep: &NpmDependencyEntry, - peer_package_info: NpmPackageInfo, + peer_package_info: &NpmPackageInfo, visited_ancestor_versions: &Arc<VisitedVersionsPath>, ) -> Result<Option<NpmPackageId>, AnyError> { fn find_matching_child<'a>( @@ -881,7 +885,7 @@ struct VersionAndInfo { fn get_resolved_package_version_and_info( pkg_name: &str, version_matcher: &impl NpmVersionMatcher, - info: NpmPackageInfo, + info: &NpmPackageInfo, parent: Option<&NpmPackageId>, ) -> Result<VersionAndInfo, AnyError> { let mut maybe_best_version: Option<VersionAndInfo> = None; @@ -922,7 +926,7 @@ fn get_resolved_package_version_and_info( bail!("Could not find dist-tag '{}'.", tag) } } else { - for (_, version_info) in info.versions.into_iter() { + for version_info in info.versions.values() { let version = NpmVersion::parse(&version_info.version)?; if version_matcher.matches(&version) { let is_best_version = maybe_best_version @@ -932,7 +936,7 @@ fn get_resolved_package_version_and_info( if is_best_version { maybe_best_version = Some(VersionAndInfo { version, - info: version_info, + info: version_info.clone(), }); } } @@ -981,7 +985,7 @@ mod test { let result = get_resolved_package_version_and_info( "test", &package_ref.req, - NpmPackageInfo { + &NpmPackageInfo { name: "test".to_string(), versions: HashMap::new(), dist_tags: HashMap::from([( @@ -1001,7 +1005,7 @@ mod test { let result = get_resolved_package_version_and_info( "test", &package_ref.req, - NpmPackageInfo { + &NpmPackageInfo { name: "test".to_string(), versions: HashMap::from([ ("0.1.0".to_string(), NpmPackageVersionInfo::default()), @@ -2014,7 +2018,7 @@ mod test { for req in reqs { let req = NpmPackageReference::from_str(req).unwrap().req; resolver - .add_package_req(&req, api.package_info(&req.name).await.unwrap()) + .add_package_req(&req, &api.package_info(&req.name).await.unwrap()) .unwrap(); } diff --git a/cli/npm/resolution/mod.rs b/cli/npm/resolution/mod.rs index 934cfb59b..381e350c9 100644 --- a/cli/npm/resolution/mod.rs +++ b/cli/npm/resolution/mod.rs @@ -422,42 +422,54 @@ impl NpmResolution { // multiple packages are resolved in alphabetical order package_reqs.sort_by(|a, b| a.name.cmp(&b.name)); - // go over the top level packages first, then down the + // go over the top level package names first, then down the // tree one level at a time through all the branches let mut unresolved_tasks = Vec::with_capacity(package_reqs.len()); - for package_req in package_reqs { - if graph.has_package_req(&package_req) { + let mut resolving_package_names = + HashSet::with_capacity(package_reqs.len()); + for package_req in &package_reqs { + if graph.has_package_req(package_req) { // skip analyzing this package, as there's already a matching top level package continue; } + if !resolving_package_names.insert(package_req.name.clone()) { + continue; // already resolving + } - // no existing best version, so resolve the current packages - let api = self.api.clone(); - let maybe_info = if should_sync_download() { + // cache the package info up front in parallel + if should_sync_download() { // for deterministic test output - Some(api.package_info(&package_req.name).await) + self.api.package_info(&package_req.name).await?; } else { - None + let api = self.api.clone(); + let package_name = package_req.name.clone(); + unresolved_tasks.push(tokio::task::spawn(async move { + // This is ok to call because api will internally cache + // the package information in memory. + api.package_info(&package_name).await + })); }; - unresolved_tasks.push(tokio::task::spawn(async move { - let info = match maybe_info { - Some(info) => info?, - None => api.package_info(&package_req.name).await?, - }; - Result::<_, AnyError>::Ok((package_req, info)) - })); + } + + for result in futures::future::join_all(unresolved_tasks).await { + result??; // surface the first error } let mut resolver = GraphDependencyResolver::new(&mut graph, &self.api); - for result in futures::future::join_all(unresolved_tasks).await { - let (package_req, info) = result??; - resolver.add_package_req(&package_req, info)?; + for package_req in package_reqs { + // avoid loading the info if this is already in the graph + if !resolver.has_package_req(&package_req) { + let info = self.api.package_info(&package_req.name).await?; + resolver.add_package_req(&package_req, &info)?; + } } resolver.resolve_pending().await?; - graph.into_snapshot(&self.api).await + let result = graph.into_snapshot(&self.api).await; + self.api.clear_memory_cache(); + result } pub fn resolve_package_from_id( |