diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-10 00:32:08 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-10 00:32:08 +0900 |
| commit | 8cc1ba8a02c0318b65658f1634de378c780392b9 (patch) | |
| tree | fdd5cb61e488018891a486b25991b87c84220bb8 /crates/mozart-sat-resolver/src/pool_builder.rs | |
| parent | 72b2e877c01e67ba7edd37e34ac2eadb7a1c62c4 (diff) | |
| download | php-mozart-8cc1ba8a02c0318b65658f1634de378c780392b9.tar.gz php-mozart-8cc1ba8a02c0318b65658f1634de378c780392b9.tar.zst php-mozart-8cc1ba8a02c0318b65658f1634de378c780392b9.zip | |
refactor(workspace): consolidate crates into mozart-core
Merged mozart-archiver, mozart-autoload, mozart-registry,
mozart-sat-resolver, and mozart-vcs into mozart-core to align
the source layout with Composer's structure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'crates/mozart-sat-resolver/src/pool_builder.rs')
| -rw-r--r-- | crates/mozart-sat-resolver/src/pool_builder.rs | 222 |
1 files changed, 0 insertions, 222 deletions
diff --git a/crates/mozart-sat-resolver/src/pool_builder.rs b/crates/mozart-sat-resolver/src/pool_builder.rs deleted file mode 100644 index 6088e7d..0000000 --- a/crates/mozart-sat-resolver/src/pool_builder.rs +++ /dev/null @@ -1,222 +0,0 @@ -use crate::pool::{Pool, PoolLink, PoolPackageInput}; -use indexmap::IndexSet; -use std::collections::VecDeque; - -/// Builder for constructing a Pool from package metadata. -/// -/// The builder accepts package inputs and recursively discovers -/// transitive dependencies. This is done by the registry layer -/// before solving. -pub struct PoolBuilder { - /// Packages to add to the pool. - inputs: Vec<PoolPackageInput>, - /// Names already added (to avoid duplicates). - added: IndexSet<String>, - /// Queue of package names that need to be explored. - pending_names: VecDeque<String>, - /// Package names that have already been explored (returned by next_pending). - explored_names: IndexSet<String>, - /// Specific platform packages to ignore (from `--ignore-platform-req=name`). - ignore_platform_reqs: IndexSet<String>, - /// When true, ignore every platform package (php, ext-*, lib-*, composer-*). - /// Mirrors `--ignore-platform-reqs` (no value). - ignore_all_platform_reqs: bool, -} - -impl PoolBuilder { - pub fn new() -> Self { - PoolBuilder { - inputs: Vec::new(), - added: IndexSet::new(), - pending_names: VecDeque::new(), - explored_names: IndexSet::new(), - ignore_platform_reqs: IndexSet::new(), - ignore_all_platform_reqs: false, - } - } - - /// Set platform requirements to ignore during exploration. - pub fn set_ignore_platform_reqs(&mut self, names: IndexSet<String>) { - self.ignore_platform_reqs = names; - } - - /// When set, every platform package is skipped during exploration. - pub fn set_ignore_all_platform_reqs(&mut self, ignore_all: bool) { - self.ignore_all_platform_reqs = ignore_all; - } - - fn is_ignored_platform_dep(&self, name: &str) -> bool { - if self - .ignore_platform_reqs - .iter() - .any(|p| mozart_core::matches_wildcard(name, p)) - { - return true; - } - self.ignore_all_platform_reqs && mozart_core::platform::is_platform_package(name) - } - - /// Add a package version to the builder. Returns true if it's new. - pub fn add_package(&mut self, input: PoolPackageInput) -> bool { - let key = format!("{}@{}", input.name, input.version); - if self.added.contains(&key) { - return false; - } - self.added.insert(key); - - // Queue dependency names for exploration - for link in &input.requires { - if !self.is_ignored_platform_dep(&link.target) { - self.pending_names.push_back(link.target.clone()); - } - } - - self.inputs.push(input); - true - } - - /// Get the next package name that needs to be explored. - /// The caller should fetch available versions for this package - /// and add them via `add_package`. - pub fn next_pending(&mut self) -> Option<String> { - while let Some(name) = self.pending_names.pop_front() { - // Skip if already explored or already has versions in inputs - if self.explored_names.contains(&name) { - continue; - } - if self.inputs.iter().any(|p| p.name == name) { - continue; - } - self.explored_names.insert(name.clone()); - return Some(name); - } - None - } - - /// Check if there are more names to explore. - pub fn has_pending(&self) -> bool { - !self.pending_names.is_empty() - } - - /// Build the final Pool. - pub fn build(self) -> Pool { - Pool::new(self.inputs, vec![]) - } - - /// Get the number of packages added so far. - pub fn len(&self) -> usize { - self.inputs.len() - } - - /// Read-only access to package inputs collected so far. Used by the - /// registry layer to materialize root aliases (`require: "X as Y"`) once - /// every base + branch-alias entry is in place: a second pass scans for - /// matching `(name, version)` and pushes the alias entry on top. - pub fn inputs(&self) -> &[PoolPackageInput] { - &self.inputs - } - - /// Whether the builder has no packages. - pub fn is_empty(&self) -> bool { - self.inputs.is_empty() - } -} - -impl Default for PoolBuilder { - fn default() -> Self { - Self::new() - } -} - -/// Helper to convert (name, constraint) pairs from Packagist into PoolLinks. -/// -/// `source_version` is the normalized version of the package declaring these -/// links; it replaces any `"self.version"` constraint, mirroring Composer's -/// `ArrayLoader::createLink` (and `AliasPackage::replaceSelfVersionDependencies`, -/// which feeds the alias's own version in for the same purpose). -pub fn make_pool_links( - source: &str, - source_version: &str, - deps: &[(String, String)], -) -> Vec<PoolLink> { - deps.iter() - .map(|(target, constraint)| PoolLink { - target: target.clone(), - constraint: if constraint.trim() == "self.version" { - source_version.to_string() - } else { - constraint.clone() - }, - source: source.to_string(), - }) - .collect() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_pool_builder_basic() { - let mut builder = PoolBuilder::new(); - - builder.add_package(PoolPackageInput { - name: "a/a".to_string(), - version: "1.0.0.0".to_string(), - pretty_version: "1.0.0".to_string(), - requires: vec![PoolLink { - target: "b/b".to_string(), - constraint: "^1.0".to_string(), - source: "a/a".to_string(), - }], - replaces: vec![], - provides: vec![], - conflicts: vec![], - is_fixed: false, - is_alias_of: None, - }); - - // Should have b/b pending - let pending = builder.next_pending(); - assert_eq!(pending, Some("b/b".to_string())); - - builder.add_package(PoolPackageInput { - name: "b/b".to_string(), - version: "1.0.0.0".to_string(), - pretty_version: "1.0.0".to_string(), - requires: vec![], - replaces: vec![], - provides: vec![], - conflicts: vec![], - is_fixed: false, - is_alias_of: None, - }); - - // No more pending - assert!(builder.next_pending().is_none()); - - let pool = builder.build(); - assert_eq!(pool.len(), 2); - } - - #[test] - fn test_deduplication() { - let mut builder = PoolBuilder::new(); - - let input = PoolPackageInput { - name: "a/a".to_string(), - version: "1.0.0.0".to_string(), - pretty_version: "1.0.0".to_string(), - requires: vec![], - replaces: vec![], - provides: vec![], - conflicts: vec![], - is_fixed: false, - is_alias_of: None, - }; - - assert!(builder.add_package(input.clone())); - assert!(!builder.add_package(input)); - assert_eq!(builder.len(), 1); - } -} |
