aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-02 22:59:23 +0900
committernsfisis <nsfisis@gmail.com>2026-05-02 22:59:23 +0900
commitb60cf8d9cb6776e5df85f080b5bb3fba252e154c (patch)
tree66770723795378fc65f1aeab726973b18813aef8 /crates/mozart/src
parent3c61a7e1e557e3b90128d2ec29227f166b17c05b (diff)
downloadphp-mozart-b60cf8d9cb6776e5df85f080b5bb3fba252e154c.tar.gz
php-mozart-b60cf8d9cb6776e5df85f080b5bb3fba252e154c.tar.zst
php-mozart-b60cf8d9cb6776e5df85f080b5bb3fba252e154c.zip
fix(resolver): honor root self-provide/replace as require fulfilment
Port Composer's RuleSetGenerator::createRequireRule self-fulfilling branch: when the root composer.json's `provide` or `replace` covers a name it also requires (with intersecting constraints), skip emitting an install-one-of rule for that root require. Composer relies on the root package being a fixed entry in the pool so whatProvides() includes it; Mozart does not yet add the root to the pool, so the same decision is made via explicit `root_provide` / `root_replace` tables threaded through ResolveRequest. Without this, an inline repo package whose name matches the root's provide was being force-installed. Fixes installer fixtures `provider_satisfies_its_own_requirement` and `replacer_satisfies_its_own_requirement`.
Diffstat (limited to 'crates/mozart/src')
-rw-r--r--crates/mozart/src/commands/create_project.rs10
-rw-r--r--crates/mozart/src/commands/remove.rs24
-rw-r--r--crates/mozart/src/commands/require.rs14
-rw-r--r--crates/mozart/src/commands/update.rs12
4 files changed, 60 insertions, 0 deletions
diff --git a/crates/mozart/src/commands/create_project.rs b/crates/mozart/src/commands/create_project.rs
index 92081d0..af77ba6 100644
--- a/crates/mozart/src/commands/create_project.rs
+++ b/crates/mozart/src/commands/create_project.rs
@@ -424,6 +424,16 @@ pub async fn execute(
),
temporary_constraints: HashMap::new(),
raw_repositories: raw.repositories.clone(),
+ root_provide: raw
+ .provide
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
+ root_replace: raw
+ .replace
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
};
console.info("Resolving dependencies...");
diff --git a/crates/mozart/src/commands/remove.rs b/crates/mozart/src/commands/remove.rs
index 58917e9..20cb6a2 100644
--- a/crates/mozart/src/commands/remove.rs
+++ b/crates/mozart/src/commands/remove.rs
@@ -258,6 +258,16 @@ pub async fn execute(
),
temporary_constraints: HashMap::new(),
raw_repositories: raw.repositories.clone(),
+ root_provide: raw
+ .provide
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
+ root_replace: raw
+ .replace
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
};
// Print header messages
@@ -518,6 +528,16 @@ async fn remove_unused(
),
temporary_constraints: HashMap::new(),
raw_repositories: raw.repositories.clone(),
+ root_provide: raw
+ .provide
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
+ root_replace: raw
+ .replace
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
};
console.info("Resolving dependencies to detect unused packages...");
@@ -866,6 +886,8 @@ mod tests {
),
temporary_constraints: HashMap::new(),
raw_repositories: vec![],
+ root_provide: HashMap::new(),
+ root_replace: HashMap::new(),
};
let resolved = resolve(&request)
.await
@@ -917,6 +939,8 @@ mod tests {
),
temporary_constraints: HashMap::new(),
raw_repositories: vec![],
+ root_provide: HashMap::new(),
+ root_replace: HashMap::new(),
};
let resolved2 = resolve(&request2)
.await
diff --git a/crates/mozart/src/commands/require.rs b/crates/mozart/src/commands/require.rs
index 630d960..95b26ea 100644
--- a/crates/mozart/src/commands/require.rs
+++ b/crates/mozart/src/commands/require.rs
@@ -647,6 +647,16 @@ pub async fn execute(
),
temporary_constraints: HashMap::new(),
raw_repositories: raw.repositories.clone(),
+ root_provide: raw
+ .provide
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
+ root_replace: raw
+ .replace
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
};
// Print header messages
@@ -1042,6 +1052,8 @@ mod tests {
),
temporary_constraints: HashMap::new(),
raw_repositories: vec![],
+ root_provide: HashMap::new(),
+ root_replace: HashMap::new(),
};
let resolved = resolver::resolve(&request)
@@ -1110,6 +1122,8 @@ mod tests {
),
temporary_constraints: HashMap::new(),
raw_repositories: vec![],
+ root_provide: HashMap::new(),
+ root_replace: HashMap::new(),
};
let resolved = resolver::resolve(&request)
diff --git a/crates/mozart/src/commands/update.rs b/crates/mozart/src/commands/update.rs
index 847ccf7..33b305a 100644
--- a/crates/mozart/src/commands/update.rs
+++ b/crates/mozart/src/commands/update.rs
@@ -887,6 +887,16 @@ pub async fn run(
repositories: repositories.clone(),
temporary_constraints,
raw_repositories: composer_json.repositories.clone(),
+ root_provide: composer_json
+ .provide
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
+ root_replace: composer_json
+ .replace
+ .iter()
+ .map(|(k, v)| (k.clone(), v.clone()))
+ .collect(),
};
// Step 6: Print header and run resolver
@@ -1994,6 +2004,8 @@ mod tests {
),
temporary_constraints: HashMap::new(),
raw_repositories: vec![],
+ root_provide: HashMap::new(),
+ root_replace: HashMap::new(),
};
let resolved = resolve(&request).await.expect("Resolution should succeed");