diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-04 09:51:44 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-04 09:51:44 +0900 |
| commit | f7b87d6934ea05d35e3ee0576e7d82d3b67b001e (patch) | |
| tree | 7081e89512fd657da4f674002733246b187737c6 | |
| parent | 74c188162886755c380a4696d8b684cb28687402 (diff) | |
| download | php-mozart-f7b87d6934ea05d35e3ee0576e7d82d3b67b001e.tar.gz php-mozart-f7b87d6934ea05d35e3ee0576e7d82d3b67b001e.tar.zst php-mozart-f7b87d6934ea05d35e3ee0576e7d82d3b67b001e.zip | |
fix(resolver): normalize bare branch atoms to dev-NAME in root aliases
Composer's VersionParser::normalize maps `master`/`trunk`/`default`
(with or without `dev-` prefix) to `dev-NAME`, not `9999999-dev`. Mozart
was emitting the four-segment 9999999 form for these atoms in
normalize_root_alias_atom, so a root require like `dev-master as 1.1.0`
recorded its target as `9999999.9999999.9999999.9999999-dev` and never
matched the pool's `dev-master` entry — the alias was silently dropped
and transitive `^1.1` requires couldn't see the materialized 1.1.0 alias.
| -rw-r--r-- | crates/mozart-registry/src/resolver.rs | 31 | ||||
| -rw-r--r-- | crates/mozart/tests/installer.rs | 2 |
2 files changed, 19 insertions, 14 deletions
diff --git a/crates/mozart-registry/src/resolver.rs b/crates/mozart-registry/src/resolver.rs index 35856c3..87a92e9 100644 --- a/crates/mozart-registry/src/resolver.rs +++ b/crates/mozart-registry/src/resolver.rs @@ -243,11 +243,11 @@ pub fn normalize_branch_alias_target(alias_target: &str) -> Option<String> { /// either side of an `as` clause (`require: "1.0.x-dev as dev-master"`). /// /// Composer sends both sides through `normalize`, which: -/// - Maps `master` / `trunk` / `default` (with optional `dev-` prefix) to -/// `9999999-dev`. Mozart's pool uses the four-segment expansion -/// `9999999.9999999.9999999.9999999-dev`, which is what -/// `make_default_branch_alias` emits — keep the same form here so a root -/// `as dev-master` lines up with synthetic default-branch aliases. +/// - Maps bare `master` / `trunk` / `default` to the `dev-` prefixed form +/// (`master` → `dev-master`) for BC with Composer 1, then returns +/// `dev-NAME` unchanged. Inline `type: package` entries for these branches +/// land in the pool under the same literal `dev-NAME` form, so root aliases +/// declared with the matching atom must point at that same string. /// - Strips a leading `v` and treats numeric `*.x-dev` branches via /// `normalizeBranch` (= `normalize_branch_alias_target`). /// - Leaves other `dev-NAME` strings as `dev-NAME`. @@ -257,22 +257,27 @@ fn normalize_root_alias_atom(atom: &str) -> Option<String> { return None; } let lower = trimmed.to_lowercase(); - let stripped = lower.strip_prefix("dev-").unwrap_or(&lower); - if matches!(stripped, "master" | "trunk" | "default") { - return Some("9999999.9999999.9999999.9999999-dev".to_string()); + // Composer's normalize: bare `master` / `trunk` / `default` get the + // `dev-` prefix prepended for BC, then fall through to the `dev-` + // branch below. + let with_prefix = if matches!(lower.as_str(), "master" | "trunk" | "default") { + format!("dev-{lower}") + } else { + trimmed.to_string() + }; + let lower_pref = with_prefix.to_lowercase(); + if let Some(rest) = lower_pref.strip_prefix("dev-") { + return Some(format!("dev-{rest}")); } - if let Some(numeric) = normalize_branch_alias_target(trimmed) { + if let Some(numeric) = normalize_branch_alias_target(&with_prefix) { return Some(numeric); } - if let Some(rest) = lower.strip_prefix("dev-") { - return Some(format!("dev-{rest}")); - } // Stable numeric atoms (e.g. `1.1.1`) need to come back in the // four-segment form `Version::Display` produces, so the alias // matcher's `input.version != alias.version_normalized` check lines // up with pool inputs (which carry the 4-segment normalized form). // Returning the raw input here would silently never match. - parse_normalized(trimmed).map(|v| v.to_string()) + parse_normalized(&with_prefix).map(|v| v.to_string()) } /// A root-level alias declared via the `require: "X as Y"` shorthand on the diff --git a/crates/mozart/tests/installer.rs b/crates/mozart/tests/installer.rs index 955a1ad..729e9db 100644 --- a/crates/mozart/tests/installer.rs +++ b/crates/mozart/tests/installer.rs @@ -388,7 +388,7 @@ installer_fixture!(update_allow_list_removes_unused); 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_alias); 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); |
