diff options
Diffstat (limited to 'crates/shirabe/src/dependency_resolver/pool_builder.rs')
| -rw-r--r-- | crates/shirabe/src/dependency_resolver/pool_builder.rs | 298 |
1 files changed, 230 insertions, 68 deletions
diff --git a/crates/shirabe/src/dependency_resolver/pool_builder.rs b/crates/shirabe/src/dependency_resolver/pool_builder.rs index 0d99587..f518545 100644 --- a/crates/shirabe/src/dependency_resolver/pool_builder.rs +++ b/crates/shirabe/src/dependency_resolver/pool_builder.rs @@ -6,8 +6,8 @@ use shirabe_external_packages::composer::pcre::preg::Preg; use shirabe_external_packages::composer::semver::compiling_matcher::CompilingMatcher; use shirabe_external_packages::composer::semver::intervals::Intervals; use shirabe_php_shim::{ - array_chunk, array_flip, array_map, array_merge, array_search, count, in_array, microtime, - number_format, round, spl_object_hash, sprintf, strpos, LogicException, PhpMixed, + LogicException, PhpMixed, array_chunk, array_flip, array_map, array_merge, array_search, count, + in_array, microtime, number_format, round, spl_object_hash, sprintf, strpos, }; use shirabe_semver::constraint::constraint::Constraint; use shirabe_semver::constraint::constraint_interface::ConstraintInterface; @@ -126,7 +126,11 @@ impl PoolBuilder { self.allowed_types = types; } - pub fn build_pool(&mut self, repositories: Vec<Box<dyn RepositoryInterface>>, request: &mut Request) -> anyhow::Result<Pool> { + pub fn build_pool( + &mut self, + repositories: Vec<Box<dyn RepositoryInterface>>, + request: &mut Request, + ) -> anyhow::Result<Pool> { self.restricted_packages_list = if request.get_restricted_packages().is_some() { Some(array_flip(&request.get_restricted_packages().unwrap())) } else { @@ -139,7 +143,8 @@ impl PoolBuilder { if request.get_locked_repository().is_none() { return Err(LogicException { - message: "No lock repo present and yet a partial update was requested.".to_string(), + message: "No lock repo present and yet a partial update was requested." + .to_string(), code: 0, } .into()); @@ -165,9 +170,13 @@ impl PoolBuilder { // if they do get unlocked, but by default they are unlocked without update propagation. if locked_package.get_dist_type().as_deref() == Some("path") { let transport_options = locked_package.get_transport_options(); - let symlink_disabled = transport_options.get("symlink").map(|v| v.as_bool() == Some(false)).unwrap_or(false); + let symlink_disabled = transport_options + .get("symlink") + .map(|v| v.as_bool() == Some(false)) + .unwrap_or(false); if !transport_options.contains_key("symlink") || !symlink_disabled { - self.path_repo_unlocked.insert(locked_package.get_name().to_string(), true); + self.path_repo_unlocked + .insert(locked_package.get_name().to_string(), true); continue; } } @@ -180,11 +189,17 @@ impl PoolBuilder { for package in request.get_fixed_or_locked_packages() { // using MatchAllConstraint here because fixed packages do not need to retrigger // loading any packages - self.loaded_packages.insert(package.get_name().to_string(), Box::new(MatchAllConstraint::new())); + self.loaded_packages.insert( + package.get_name().to_string(), + Box::new(MatchAllConstraint::new()), + ); // replace means conflict, so if a fixed package replaces a name, no need to load that one, packages would conflict anyways for (_k, link) in &package.get_replaces() { - self.loaded_packages.insert(link.get_target().to_string(), Box::new(MatchAllConstraint::new())); + self.loaded_packages.insert( + link.get_target().to_string(), + Box::new(MatchAllConstraint::new()), + ); } // TODO in how far can we do the above for conflicts? It's more tricky cause conflicts can be limited to @@ -193,7 +208,8 @@ impl PoolBuilder { let in_root_or_platform = package .get_repository() .map(|r| { - r.as_any().is::<RootPackageRepository>() || r.as_any().is::<PlatformRepository>() + r.as_any().is::<RootPackageRepository>() + || r.as_any().is::<PlatformRepository>() }) .unwrap_or(false); if in_root_or_platform @@ -206,7 +222,8 @@ impl PoolBuilder { { self.load_package(request, &repositories, &*package, false)?; } else { - self.unacceptable_fixed_or_locked_packages.push(package.clone_box()); + self.unacceptable_fixed_or_locked_packages + .push(package.clone_box()); } } @@ -216,7 +233,8 @@ impl PoolBuilder { continue; } - self.packages_to_load.insert(package_name.clone(), constraint.clone_box()); + self.packages_to_load + .insert(package_name.clone(), constraint.clone_box()); self.max_extended_reqs.insert(package_name.clone(), true); } @@ -253,7 +271,8 @@ impl PoolBuilder { None => continue, }; - let mut package_and_aliases: IndexMap<i64, Box<dyn BasePackage>> = IndexMap::new(); + let mut package_and_aliases: IndexMap<i64, Box<dyn BasePackage>> = + IndexMap::new(); package_and_aliases.insert(i, package.clone_box()); if let Some(aliases) = self.alias_map.get(&spl_object_hash(&*package)) { for (idx, alias) in aliases { @@ -263,7 +282,11 @@ impl PoolBuilder { let mut found = false; for (_idx, package_or_alias) in &package_and_aliases { - if CompilingMatcher::matches(&*constraint, Constraint::OP_EQ, package_or_alias.get_version()) { + if CompilingMatcher::matches( + &*constraint, + Constraint::OP_EQ, + package_or_alias.get_version(), + ) { found = true; } } @@ -287,7 +310,10 @@ impl PoolBuilder { self.root_aliases.clone(), self.root_references.clone(), self.packages.values().map(|p| p.clone_box()).collect(), - self.unacceptable_fixed_or_locked_packages.iter().map(|p| p.clone_box()).collect(), + self.unacceptable_fixed_or_locked_packages + .iter() + .map(|p| p.clone_box()) + .collect(), ); self.event_dispatcher .as_mut() @@ -300,12 +326,16 @@ impl PoolBuilder { .enumerate() .map(|(i, p)| (i as i64, p)) .collect(); - self.unacceptable_fixed_or_locked_packages = pre_pool_create_event.get_unacceptable_fixed_packages(); + self.unacceptable_fixed_or_locked_packages = + pre_pool_create_event.get_unacceptable_fixed_packages(); } let mut pool = Pool::new( self.packages.values().map(|p| p.clone_box()).collect(), - self.unacceptable_fixed_or_locked_packages.iter().map(|p| p.clone_box()).collect(), + self.unacceptable_fixed_or_locked_packages + .iter() + .map(|p| p.clone_box()) + .collect(), ); self.alias_map = IndexMap::new(); @@ -330,7 +360,12 @@ impl PoolBuilder { Ok(pool) } - fn mark_package_name_for_loading(&mut self, request: &Request, name: &str, constraint: Box<dyn ConstraintInterface>) { + fn mark_package_name_for_loading( + &mut self, + request: &Request, + name: &str, + constraint: Box<dyn ConstraintInterface>, + ) { // Skip platform requires at this stage if PlatformRepository::is_platform_package(name) { return; @@ -399,7 +434,11 @@ impl PoolBuilder { self.loaded_packages.shift_remove(name); } - fn load_packages_marked_for_loading(&mut self, request: &mut Request, repositories: &Vec<Box<dyn RepositoryInterface>>) -> anyhow::Result<()> { + fn load_packages_marked_for_loading( + &mut self, + request: &mut Request, + repositories: &Vec<Box<dyn RepositoryInterface>>, + ) -> anyhow::Result<()> { let to_remove: Vec<String> = self .packages_to_load .keys() @@ -420,7 +459,8 @@ impl PoolBuilder { .map(|(k, v)| (k.clone(), v.clone_box())) .collect(); for (name, constraint) in &snapshot { - self.loaded_packages.insert(name.clone(), constraint.clone_box()); + self.loaded_packages + .insert(name.clone(), constraint.clone_box()); } // Load packages in chunks of 50 to prevent memory usage build-up due to caches of all sorts @@ -432,7 +472,12 @@ impl PoolBuilder { // never need to load anything else from them let is_locked_repo = request .get_locked_repository() - .map(|lr| std::ptr::eq(lr as *const _ as *const u8, repository.as_ref() as *const _ as *const u8)) + .map(|lr| { + std::ptr::eq( + lr as *const _ as *const u8, + repository.as_ref() as *const _ as *const u8, + ) + }) .unwrap_or(false); if repository.as_any().is::<PlatformRepository>() || is_locked_repo { continue; @@ -447,17 +492,28 @@ impl PoolBuilder { package_batch, &self.acceptable_stabilities, &self.stability_flags, - self.loaded_per_repo.get(&(repo_index as i64)).cloned().unwrap_or_default(), + self.loaded_per_repo + .get(&(repo_index as i64)) + .cloned() + .unwrap_or_default(), ); - let names_found = result.get("namesFound").and_then(|v| v.as_list()).cloned().unwrap_or_default(); + let names_found = result + .get("namesFound") + .and_then(|v| v.as_list()) + .cloned() + .unwrap_or_default(); for name in &names_found { // avoid loading the same package again from other repositories once it has been found if let Some(b) = package_batches.get_mut(batch_index) { b.shift_remove(name.as_string().unwrap_or("")); } } - let packages_in_result = result.get("packages").and_then(|v| v.as_list()).cloned().unwrap_or_default(); + let packages_in_result = result + .get("packages") + .and_then(|v| v.as_list()) + .cloned() + .unwrap_or_default(); for package in &packages_in_result { let pkg = match package.as_package_interface() { Some(p) => p, @@ -472,7 +528,11 @@ impl PoolBuilder { if in_array(pkg.get_type(), &self.ignored_types, true) || (self.allowed_types.is_some() - && !in_array(pkg.get_type(), self.allowed_types.as_ref().unwrap(), true)) + && !in_array( + pkg.get_type(), + self.allowed_types.as_ref().unwrap(), + true, + )) { continue; } @@ -495,7 +555,13 @@ impl PoolBuilder { Ok(()) } - fn load_package(&mut self, request: &mut Request, repositories: &Vec<Box<dyn RepositoryInterface>>, package: &dyn BasePackage, propagate_update: bool) -> anyhow::Result<()> { + fn load_package( + &mut self, + request: &mut Request, + repositories: &Vec<Box<dyn RepositoryInterface>>, + package: &dyn BasePackage, + propagate_update: bool, + ) -> anyhow::Result<()> { let index = self.index_counter; self.index_counter += 1; self.packages.insert(index, package.clone_box()); @@ -537,19 +603,20 @@ impl PoolBuilder { } else { package.clone_box() }; - let alias_package: Box<dyn BasePackage> = if base_package.as_any().is::<CompletePackage>() { - Box::new(CompleteAliasPackage::new( - base_package.clone_box(), - alias.get("alias_normalized").cloned().unwrap_or_default(), - alias.get("alias").cloned().unwrap_or_default(), - )) - } else { - Box::new(AliasPackage::new( - base_package.clone_box(), - alias.get("alias_normalized").cloned().unwrap_or_default(), - alias.get("alias").cloned().unwrap_or_default(), - )) - }; + let alias_package: Box<dyn BasePackage> = + if base_package.as_any().is::<CompletePackage>() { + Box::new(CompleteAliasPackage::new( + base_package.clone_box(), + alias.get("alias_normalized").cloned().unwrap_or_default(), + alias.get("alias").cloned().unwrap_or_default(), + )) + } else { + Box::new(AliasPackage::new( + base_package.clone_box(), + alias.get("alias_normalized").cloned().unwrap_or_default(), + alias.get("alias").cloned().unwrap_or_default(), + )) + }; // PHP: $aliasPackage->setRootPackageAlias(true); // BasePackage doesn't expose this directly; the AliasPackage trait method handles it. @@ -577,7 +644,9 @@ impl PoolBuilder { if propagate_update && request.get_update_allow_transitive_dependencies() { let skipped_root_requires = self.get_skipped_root_requires(request, &require); - if request.get_update_allow_transitive_root_dependencies() || 0 == count(&skipped_root_requires) { + if request.get_update_allow_transitive_root_dependencies() + || 0 == count(&skipped_root_requires) + { self.unlock_package(request, repositories, &require)?; self.mark_package_name_for_loading(request, &require, link_constraint); } else { @@ -588,7 +657,9 @@ impl PoolBuilder { } } } - } else if self.path_repo_unlocked.contains_key(&require) && !self.loaded_packages.contains_key(&require) { + } else if self.path_repo_unlocked.contains_key(&require) + && !self.loaded_packages.contains_key(&require) + { // if doing a partial update and a package depends on a path-repo-unlocked package which is not referenced by the root, we need to ensure it gets loaded as it was not loaded by the request's root requirements // and would not be loaded above if update propagation is not allowed (which happens if the requirer is itself a path-repo-unlocked package) or if transitive deps are not allowed to be unlocked self.mark_package_name_for_loading(request, &require, link_constraint); @@ -603,10 +674,14 @@ impl PoolBuilder { if propagate_update && request.get_update_allow_transitive_dependencies() { for (_k, link) in &package.get_replaces() { let replace = link.get_target().to_string(); - if self.loaded_packages.contains_key(&replace) && self.skipped_load.contains_key(&replace) { + if self.loaded_packages.contains_key(&replace) + && self.skipped_load.contains_key(&replace) + { let skipped_root_requires = self.get_skipped_root_requires(request, &replace); - if request.get_update_allow_transitive_root_dependencies() || 0 == count(&skipped_root_requires) { + if request.get_update_allow_transitive_root_dependencies() + || 0 == count(&skipped_root_requires) + { self.unlock_package(request, repositories, &replace)?; // the replaced package only needs to be loaded if something else requires it self.mark_package_name_for_loading_if_required(request, &replace); @@ -660,7 +735,11 @@ impl PoolBuilder { for (_k, link) in &package_or_replacer.get_replaces() { if root_requires.contains_key(link.get_target()) { if name != package_or_replacer.get_name() { - matches.push(format!("{} (via replace of {})", package_or_replacer.get_name(), name)); + matches.push(format!( + "{} (via replace of {})", + package_or_replacer.get_name(), + name + )); } else { matches.push(package_or_replacer.get_name().to_string()); } @@ -735,7 +814,12 @@ impl PoolBuilder { /// Reverts the decision to use a locked package if a partial update with transitive dependencies /// found that this package actually needs to be updated - fn unlock_package(&mut self, request: &mut Request, repositories: &Vec<Box<dyn RepositoryInterface>>, name: &str) -> anyhow::Result<()> { + fn unlock_package( + &mut self, + request: &mut Request, + repositories: &Vec<Box<dyn RepositoryInterface>>, + name: &str, + ) -> anyhow::Result<()> { let skipped: Vec<Box<dyn PackageInterface>> = self .skipped_load .get(name) @@ -744,21 +828,35 @@ impl PoolBuilder { for package_or_replacer in &skipped { // if we unfixed a replaced package name, we also need to unfix the replacer itself // as long as it was not unfixed yet - if package_or_replacer.get_name() != name && self.skipped_load.contains_key(package_or_replacer.get_name()) { + if package_or_replacer.get_name() != name + && self + .skipped_load + .contains_key(package_or_replacer.get_name()) + { let replacer_name = package_or_replacer.get_name().to_string(); if request.get_update_allow_transitive_root_dependencies() - || (!self.is_root_require(request, name) && !self.is_root_require(request, &replacer_name)) + || (!self.is_root_require(request, name) + && !self.is_root_require(request, &replacer_name)) { self.unlock_package(request, repositories, &replacer_name)?; if self.is_root_require(request, &replacer_name) { - self.mark_package_name_for_loading(request, &replacer_name, Box::new(MatchAllConstraint::new())); + self.mark_package_name_for_loading( + request, + &replacer_name, + Box::new(MatchAllConstraint::new()), + ); } else { - let pkgs: Vec<Box<dyn BasePackage>> = self.packages.values().map(|p| p.clone_box()).collect(); + let pkgs: Vec<Box<dyn BasePackage>> = + self.packages.values().map(|p| p.clone_box()).collect(); for loaded_package in &pkgs { let requires = loaded_package.get_requires(); if let Some(req_link) = requires.get(&replacer_name) { - self.mark_package_name_for_loading(request, &replacer_name, req_link.get_constraint()); + self.mark_package_name_for_loading( + request, + &replacer_name, + req_link.get_constraint(), + ); } } } @@ -784,10 +882,15 @@ impl PoolBuilder { self.path_repo_unlocked.shift_remove(name); // remove locked package by this name which was already initialized - let locked_packages: Vec<Box<dyn BasePackage>> = request.get_locked_packages().iter().map(|p| p.clone_box()).collect(); + let locked_packages: Vec<Box<dyn BasePackage>> = request + .get_locked_packages() + .iter() + .map(|p| p.clone_box()) + .collect(); for locked_package in &locked_packages { if locked_package.as_alias_package().is_none() && locked_package.get_name() == name { - let pkgs: Vec<Box<dyn BasePackage>> = self.packages.values().map(|p| p.clone_box()).collect(); + let pkgs: Vec<Box<dyn BasePackage>> = + self.packages.values().map(|p| p.clone_box()).collect(); let index_opt = array_search(&**locked_package, &pkgs, true); if let Some(index) = index_opt { request.unlock_package(&**locked_package); @@ -798,23 +901,47 @@ impl PoolBuilder { // satisfied their requirements // and if this package is replacing another that is required by a locked or fixed package, ensure // that we load that replaced package in case an update to this package removes the replacement - let fixed_or_locked: Vec<Box<dyn BasePackage>> = request.get_fixed_or_locked_packages().iter().map(|p| p.clone_box()).collect(); + let fixed_or_locked: Vec<Box<dyn BasePackage>> = request + .get_fixed_or_locked_packages() + .iter() + .map(|p| p.clone_box()) + .collect(); for fixed_or_locked_package in &fixed_or_locked { - if std::ptr::eq(fixed_or_locked_package.as_ref() as *const _, locked_package.as_ref() as *const _) { + if std::ptr::eq( + fixed_or_locked_package.as_ref() as *const _, + locked_package.as_ref() as *const _, + ) { continue; } - if self.skipped_load.contains_key(fixed_or_locked_package.get_name()) { + if self + .skipped_load + .contains_key(fixed_or_locked_package.get_name()) + { let requires = fixed_or_locked_package.get_requires(); if let Some(req_link) = requires.get(locked_package.get_name()) { - self.mark_package_name_for_loading(request, locked_package.get_name(), req_link.get_constraint()); + self.mark_package_name_for_loading( + request, + locked_package.get_name(), + req_link.get_constraint(), + ); } for (_k, replace) in &locked_package.get_replaces() { - if requires.contains_key(replace.get_target()) && self.skipped_load.contains_key(replace.get_target()) { - self.unlock_package(request, repositories, replace.get_target())?; + if requires.contains_key(replace.get_target()) + && self.skipped_load.contains_key(replace.get_target()) + { + self.unlock_package( + request, + repositories, + replace.get_target(), + )?; // this package is in $requires so no need to call markPackageNameForLoadingIfRequired - self.mark_package_name_for_loading(request, replace.get_target(), replace.get_constraint()); + self.mark_package_name_for_loading( + request, + replace.get_target(), + replace.get_constraint(), + ); } } } @@ -827,21 +954,37 @@ impl PoolBuilder { fn mark_package_name_for_loading_if_required(&mut self, request: &Request, name: &str) { if self.is_root_require(request, name) { - self.mark_package_name_for_loading(request, name, request.get_requires()[name].clone_box()); + self.mark_package_name_for_loading( + request, + name, + request.get_requires()[name].clone_box(), + ); } - let pkgs: Vec<Box<dyn BasePackage>> = self.packages.values().map(|p| p.clone_box()).collect(); + let pkgs: Vec<Box<dyn BasePackage>> = + self.packages.values().map(|p| p.clone_box()).collect(); for package in &pkgs { for (_k, link) in &package.get_requires() { if name == link.get_target() { - self.mark_package_name_for_loading(request, link.get_target(), link.get_constraint()); + self.mark_package_name_for_loading( + request, + link.get_target(), + link.get_constraint(), + ); } } } } - fn remove_loaded_package(&mut self, _request: &Request, repositories: &Vec<Box<dyn RepositoryInterface>>, package: &dyn BasePackage, index: i64) { - let repos_box: Vec<Box<dyn RepositoryInterface>> = repositories.iter().map(|r| r.clone_box()).collect(); + fn remove_loaded_package( + &mut self, + _request: &Request, + repositories: &Vec<Box<dyn RepositoryInterface>>, + package: &dyn BasePackage, + index: i64, + ) { + let repos_box: Vec<Box<dyn RepositoryInterface>> = + repositories.iter().map(|r| r.clone_box()).collect(); let repo_index = match package.get_repository() { Some(repo) => array_search(&*repo, &repos_box, true).unwrap_or(-1), None => -1, @@ -881,7 +1024,11 @@ impl PoolBuilder { let before = microtime(true); let total = count(&pool.get_packages()) as f64; - let pool = self.pool_optimizer.as_mut().unwrap().optimize(request, pool); + let pool = self + .pool_optimizer + .as_mut() + .unwrap() + .optimize(request, pool); let filtered = total - (count(&pool.get_packages()) as f64); @@ -890,7 +1037,10 @@ impl PoolBuilder { } self.io.write_with_verbosity( - &sprintf("Pool optimizer completed in %.3f seconds", &[(microtime(true) - before).into()]), + &sprintf( + "Pool optimizer completed in %.3f seconds", + &[(microtime(true) - before).into()], + ), true, IOInterface::VERY_VERBOSE, ); @@ -910,7 +1060,12 @@ impl PoolBuilder { pool } - fn run_security_advisory_filter(&mut self, pool: Pool, repositories: &Vec<Box<dyn RepositoryInterface>>, request: &Request) -> Pool { + fn run_security_advisory_filter( + &mut self, + pool: Pool, + repositories: &Vec<Box<dyn RepositoryInterface>>, + request: &Request, + ) -> Pool { if self.security_advisory_pool_filter.is_none() { return pool; } @@ -920,7 +1075,11 @@ impl PoolBuilder { let before = microtime(true); let total = count(&pool.get_packages()) as f64; - let pool = self.security_advisory_pool_filter.as_mut().unwrap().filter(pool, repositories, request); + let pool = self.security_advisory_pool_filter.as_mut().unwrap().filter( + pool, + repositories, + request, + ); let filtered = total - (count(&pool.get_packages()) as f64); @@ -929,7 +1088,10 @@ impl PoolBuilder { } self.io.write_with_verbosity( - &sprintf("Security advisory pool filter completed in %.3f seconds", &[(microtime(true) - before).into()]), + &sprintf( + "Security advisory pool filter completed in %.3f seconds", + &[(microtime(true) - before).into()], + ), true, IOInterface::VERY_VERBOSE, ); |
