aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-registry/src/lockfile.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-04 00:49:40 +0900
committernsfisis <nsfisis@gmail.com>2026-05-04 00:49:40 +0900
commit74c188162886755c380a4696d8b684cb28687402 (patch)
tree4a33b20c6ceef51d3720f169918c077c1cb06376 /crates/mozart-registry/src/lockfile.rs
parent6449a15de90fe8252fb288bd5eacb99dc2cd699a (diff)
downloadphp-mozart-74c188162886755c380a4696d8b684cb28687402.tar.gz
php-mozart-74c188162886755c380a4696d8b684cb28687402.tar.zst
php-mozart-74c188162886755c380a4696d8b684cb28687402.zip
fix(update): preserve locked refs and aliases on partial update
Partial update of a non-allow-listed dev package now resolves and emits the locked-repo entry verbatim, mirroring Composer's `PoolBuilder`. Three coordinated changes: - resolver: `lock_filter_allows` accepts the locked package's branch- alias normalized versions, not just the base. Without this, root constraints like `~2.1` against a `dev-master` locked package whose branch alias is `2.1.x-dev` failed with "no matching package found". - lockfile: new `lock_pinned_names` field on `LockFileGenerationRequest` routes non-allow-listed packages through `previous_lock_lookup` before `inline_lookup`, so the lock's source/dist references survive even when the inline metadata has moved to a newer commit. - update: `apply_partial_update` skips alias entries — re-pinning their pretty `version` to the base would collapse the alias label and emit a self-referential entry in the new lock's `aliases[]` block. Unblocks partial_update_forces_dev_reference_from_lock_for_non_updated_packages. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/mozart-registry/src/lockfile.rs')
-rw-r--r--crates/mozart-registry/src/lockfile.rs27
1 files changed, 27 insertions, 0 deletions
diff --git a/crates/mozart-registry/src/lockfile.rs b/crates/mozart-registry/src/lockfile.rs
index 94983e3..5a293fe 100644
--- a/crates/mozart-registry/src/lockfile.rs
+++ b/crates/mozart-registry/src/lockfile.rs
@@ -467,6 +467,16 @@ pub struct LockFileGenerationRequest {
/// during partial updates: lock entries are stable across updates that
/// don't touch the package, even if the upstream metadata has drifted.
pub previous_lock: Option<LockFile>,
+ /// Lowercase package names that were held back to their locked version
+ /// on a partial update — i.e. they were NOT in the CLI's allow list and
+ /// were re-pinned by `apply_partial_update`. For these names the lock
+ /// entry's metadata (source/dist references in particular) is canonical:
+ /// inline / composer-repo metadata may have drifted to a newer commit
+ /// that the partial update is explicitly choosing not to take. Mirrors
+ /// Composer's `PoolBuilder`, which keeps non-allow-listed packages at
+ /// the locked-repo entry rather than re-loading them from the inline /
+ /// VCS sources.
+ pub lock_pinned_names: indexmap::IndexSet<String>,
}
impl LockFileGenerationRequest {
@@ -926,6 +936,21 @@ pub async fn generate_lock_file(request: &LockFileGenerationRequest) -> anyhow::
let mut package_metadata: IndexMap<String, PackagistVersion> = IndexMap::new();
let repo_set = &request.repositories;
for pkg in &real_resolved {
+ // For packages held back to the locked version on a partial update,
+ // the lock entry is the canonical metadata source. Inline / composer-
+ // repo / VCS sources may have moved to a newer commit that this
+ // partial update is explicitly choosing NOT to take, so consulting
+ // them first would silently bump the source/dist reference. Mirrors
+ // Composer's `PoolBuilder` behaviour: non-allow-listed packages keep
+ // the locked-repo entry rather than re-loading from upstream.
+ let pinned = request.lock_pinned_names.contains(&pkg.name.to_lowercase());
+ if pinned
+ && let Some(prev) = request.previous_lock_lookup(&pkg.name, &pkg.version_normalized)
+ {
+ package_metadata.insert(pkg.name.clone(), prev);
+ continue;
+ }
+
if let Some(inline) = request.inline_lookup(&pkg.name, &pkg.version_normalized) {
package_metadata.insert(pkg.name.clone(), inline);
continue;
@@ -1640,6 +1665,7 @@ mod tests {
crate::cache::Cache::new(std::env::temp_dir().join("mozart-test-cache"), false),
)),
previous_lock: None,
+ lock_pinned_names: IndexSet::new(),
};
let lock = generate_lock_file(&request).await.unwrap();
@@ -1787,6 +1813,7 @@ mod tests {
false,
))),
previous_lock: None,
+ lock_pinned_names: IndexSet::new(),
};
let lock = generate_lock_file(&gen_request)