aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-registry/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mozart-registry/src')
-rw-r--r--crates/mozart-registry/src/lockfile.rs3
-rw-r--r--crates/mozart-registry/src/packagist.rs7
-rw-r--r--crates/mozart-registry/src/resolver.rs33
-rw-r--r--crates/mozart-registry/src/vcs_bridge.rs1
-rw-r--r--crates/mozart-registry/src/version.rs1
5 files changed, 45 insertions, 0 deletions
diff --git a/crates/mozart-registry/src/lockfile.rs b/crates/mozart-registry/src/lockfile.rs
index 3fc8fad..5e07e9d 100644
--- a/crates/mozart-registry/src/lockfile.rs
+++ b/crates/mozart-registry/src/lockfile.rs
@@ -1092,6 +1092,7 @@ mod tests {
extra: Some(serde_json::json!({"branch-alias": {"dev-main": "1.0.x-dev"}})),
notification_url: Some("https://packagist.org/downloads/".to_string()),
default_branch: false,
+ abandoned: None,
}
}
@@ -1167,6 +1168,7 @@ mod tests {
extra: None,
notification_url: None,
default_branch: false,
+ abandoned: None,
};
let locked = packagist_version_to_locked_package("vendor/pkg", &pv);
@@ -1506,6 +1508,7 @@ mod tests {
root_conflict: IndexMap::new(),
locked_package_names: IndexSet::new(),
locked_packages: Vec::new(),
+ block_abandoned: false,
};
let resolved = resolve(&resolve_request)
diff --git a/crates/mozart-registry/src/packagist.rs b/crates/mozart-registry/src/packagist.rs
index 1d9356d..6b24589 100644
--- a/crates/mozart-registry/src/packagist.rs
+++ b/crates/mozart-registry/src/packagist.rs
@@ -135,6 +135,13 @@ pub struct PackagistVersion {
/// `crate::resolver::packagist_to_pool_inputs`.
#[serde(rename = "default-branch", default)]
pub default_branch: bool,
+
+ /// Abandonment marker. Composer accepts `abandoned: true` (no replacement
+ /// suggested) or `abandoned: "<replacement-package>"`. Anything else
+ /// (absent, `false`, empty string) means the package is active. Mirrors
+ /// `Composer\Package\CompletePackage::isAbandoned`.
+ #[serde(default, deserialize_with = "deserialize_unset_as_none")]
+ pub abandoned: Option<serde_json::Value>,
}
impl PackagistVersion {
diff --git a/crates/mozart-registry/src/resolver.rs b/crates/mozart-registry/src/resolver.rs
index e6f3c86..0716246 100644
--- a/crates/mozart-registry/src/resolver.rs
+++ b/crates/mozart-registry/src/resolver.rs
@@ -483,6 +483,19 @@ fn should_skip_platform_dep(
// Packagist → PoolPackageInput conversion
// ─────────────────────────────────────────────────────────────────────────────
+/// Mirrors `Composer\Package\CompletePackage::isAbandoned`: any
+/// `abandoned: true` or `abandoned: "<replacement>"` value is truthy.
+/// `abandoned: false` and an empty string both register as not-abandoned.
+fn is_abandoned(pv: &packagist::PackagistVersion) -> bool {
+ match &pv.abandoned {
+ None => false,
+ Some(serde_json::Value::Null) => false,
+ Some(serde_json::Value::Bool(b)) => *b,
+ Some(serde_json::Value::String(s)) => !s.is_empty(),
+ Some(_) => true,
+ }
+}
+
/// Convert a Packagist version entry to PoolPackageInput(s).
/// May return multiple entries if branch aliases are present.
fn packagist_to_pool_inputs(
@@ -705,6 +718,13 @@ pub struct ResolveRequest {
/// version (whether directly or via another package's `replace`). Empty
/// for installs and full updates.
pub locked_packages: Vec<LockedPackageInfo>,
+ /// When true, drop abandoned packages (`abandoned: true|<replacement>`)
+ /// from the pool before solving. Mirrors Composer's
+ /// `audit.block-abandoned` config feeding into
+ /// `SecurityAdvisoryPoolFilter`: the resolver simply never sees these
+ /// versions, so a root requirement that only matches abandoned candidates
+ /// fails with the standard "could not be resolved" error.
+ pub block_abandoned: bool,
}
/// Full data for a lock-pinned package, used in partial updates. Carried on
@@ -1026,6 +1046,9 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
return false;
};
for ipkg in packages {
+ if request.block_abandoned && is_abandoned(&ipkg.version) {
+ continue;
+ }
let inputs = packagist_to_pool_inputs(
&ipkg.name,
&ipkg.version,
@@ -1052,6 +1075,9 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
let mut composer_repo_names: IndexSet<String> = IndexSet::new();
for cpkg in &composer_repo_packages {
composer_repo_names.insert(cpkg.name.clone());
+ if request.block_abandoned && is_abandoned(&cpkg.version) {
+ continue;
+ }
let inputs = packagist_to_pool_inputs(
&cpkg.name,
&cpkg.version,
@@ -1098,6 +1124,9 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
.await
.map_err(|e| ResolveError::DependencyFetchError(e.to_string()))?;
for r in &seed_results {
+ if request.block_abandoned && is_abandoned(&r.version) {
+ continue;
+ }
let inputs = packagist_to_pool_inputs(
&r.name,
&r.version,
@@ -1143,6 +1172,9 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
}
};
for r in &results {
+ if request.block_abandoned && is_abandoned(&r.version) {
+ continue;
+ }
let inputs = packagist_to_pool_inputs(
&r.name,
&r.version,
@@ -1705,6 +1737,7 @@ mod tests {
root_conflict: IndexMap::new(),
locked_package_names: IndexSet::new(),
locked_packages: Vec::new(),
+ block_abandoned: false,
};
let result = resolve(&request).await;
diff --git a/crates/mozart-registry/src/vcs_bridge.rs b/crates/mozart-registry/src/vcs_bridge.rs
index e9a2f37..aae3d87 100644
--- a/crates/mozart-registry/src/vcs_bridge.rs
+++ b/crates/mozart-registry/src/vcs_bridge.rs
@@ -188,6 +188,7 @@ pub fn vcs_to_packagist_version(vpkg: &VcsPackageVersion) -> PackagistVersion {
extra: vpkg.composer_json.get("extra").cloned(),
notification_url: None,
default_branch: vpkg.is_default_branch,
+ abandoned: vpkg.composer_json.get("abandoned").cloned(),
}
}
diff --git a/crates/mozart-registry/src/version.rs b/crates/mozart-registry/src/version.rs
index ba120fa..9a7c6e6 100644
--- a/crates/mozart-registry/src/version.rs
+++ b/crates/mozart-registry/src/version.rs
@@ -199,6 +199,7 @@ mod tests {
extra: None,
notification_url: None,
default_branch: false,
+ abandoned: None,
}
}