aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--crates/mozart/src/commands/update.rs36
-rw-r--r--crates/mozart/tests/installer.rs2
2 files changed, 30 insertions, 8 deletions
diff --git a/crates/mozart/src/commands/update.rs b/crates/mozart/src/commands/update.rs
index 5e83104..5cf05c4 100644
--- a/crates/mozart/src/commands/update.rs
+++ b/crates/mozart/src/commands/update.rs
@@ -506,20 +506,42 @@ fn is_platform_dep(dep_name: &str) -> bool {
|| dep_name == "php-debug"
}
-/// Look up the require-list for `name`: prefer the lock entry (the version
-/// that will stay if not unlocked) and fall back to the union of repo
-/// requires for not-yet-locked packages. Lowercase names returned.
+/// Look up the require-list for `name`, unioning the lock entry's
+/// requires with every available version's requires from inline /
+/// composer-repo entries. Lowercase names returned, deduped.
+///
+/// Composer's `PoolBuilder::loadPackage` dynamically unlocks any locked
+/// dependency referenced by an allow-listed package's *new* (about-to-be-
+/// resolved) version. Mozart pre-computes the unlock set, so it has to
+/// consider not only the lock-pinned version's requires but also every
+/// candidate version the resolver might pick — otherwise upgrading a
+/// locked package whose new version added a requirement on another
+/// locked package leaves that other package pinned, and the resolver
+/// silently keeps the old version.
fn requires_for_name(
name: &str,
lock_map: &IndexMap<String, &lockfile::LockedPackage>,
repo_requires: &IndexMap<String, IndexSet<String>>,
) -> Option<Vec<String>> {
+ let mut deps: IndexSet<String> = IndexSet::new();
+ let mut seen = false;
if let Some(pkg) = lock_map.get(name) {
- return Some(pkg.require.keys().map(|k| k.to_lowercase()).collect());
+ seen = true;
+ for k in pkg.require.keys() {
+ deps.insert(k.to_lowercase());
+ }
+ }
+ if let Some(set) = repo_requires.get(name) {
+ seen = true;
+ for k in set {
+ deps.insert(k.clone());
+ }
+ }
+ if seen {
+ Some(deps.into_iter().collect())
+ } else {
+ None
}
- repo_requires
- .get(name)
- .map(|set| set.iter().cloned().collect())
}
/// Expand the allow-list with transitive `require` dependencies, stopping at
diff --git a/crates/mozart/tests/installer.rs b/crates/mozart/tests/installer.rs
index cd00f88..ec89e39 100644
--- a/crates/mozart/tests/installer.rs
+++ b/crates/mozart/tests/installer.rs
@@ -370,7 +370,7 @@ installer_fixture!(update_allow_list_require_new_replace);
installer_fixture!(update_allow_list_warns_non_existing_patterns);
installer_fixture!(update_allow_list_with_dependencies);
installer_fixture!(update_allow_list_with_dependencies_alias, ignore);
-installer_fixture!(update_allow_list_with_dependencies_new_requirement, ignore);
+installer_fixture!(update_allow_list_with_dependencies_new_requirement);
installer_fixture!(update_allow_list_with_dependencies_require_new);
installer_fixture!(update_allow_list_with_dependencies_require_new_replace);
installer_fixture!(