From e37b12d6e2d95b4d3924859732513e125fc552e0 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 3 May 2026 23:31:31 +0900 Subject: feat(registry): support type: path repositories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a `mozart-php-serialize` crate (a byte-compatible port of PHP's `serialize()`) and a `mozart-registry::path_repository` module that expands `type: path` entries into synthetic `type: package` repositories. Each synthesized package carries the same SHA-1 dist reference Composer computes (`sha1(\$json . serialize(\$options))`) so the lockfile and trace lines match Composer byte-for-byte. Two latent bugs surfaced once the path-repo flow exercised real resolutions: - `apply_partial_update` swapped path-repo packages back to their locked version, defeating Composer's "path repos always reload" rule (`PoolBuilder` treats them as canonical, not lock-bound). Mirror the path-repo skip already used when constructing `locked_packages`. - `normalize_root_alias_atom` returned the raw input string for stable numeric atoms (e.g. `1.1.1`), so the alias matcher's `input.version \!= alias.version_normalized` check — comparing against pool inputs that carry the 4-segment normalized form — silently never matched. Run the parsed Version through Display so both sides are in the same shape. `install/update::run` gain a `path_repo_base_override: Option<&Path>` parameter for the in-process test harness: Composer's PHPUnit `InstallerTest::setUp` does `chdir(__DIR__)` so relative path-repo URLs resolve against `composer/tests/Composer/Test/`, but the Rust harness writes `composer.json` into a per-test tempdir and can't chdir safely under parallel tests. Production callers pass `None` and resolve against `working_dir`. Greens 3 ignored installer fixtures: partial_update_loads_root_aliases_for_path_repos alias_in_lock alias_in_lock2 --- crates/mozart/tests/installer.rs | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'crates/mozart/tests') diff --git a/crates/mozart/tests/installer.rs b/crates/mozart/tests/installer.rs index 197b00f..d22f2a0 100644 --- a/crates/mozart/tests/installer.rs +++ b/crates/mozart/tests/installer.rs @@ -25,6 +25,17 @@ fn fixtures_dir() -> PathBuf { .join("../../composer/tests/Composer/Test/Fixtures/installer") } +/// Composer's PHPUnit `InstallerTest::setUp()` runs `chdir(__DIR__)` so that +/// relative `type: path` repo URLs (`Fixtures/functional/.../pkg`) resolve +/// against `composer/tests/Composer/Test/`. The Rust harness can't chdir +/// safely (cargo test runs cases in parallel), so it threads the same +/// directory through `install/update::run` as the path-repo resolution base +/// instead. Production callers of `run()` pass `None` and resolve against +/// `working_dir`, matching Composer's "use cwd" behaviour. +fn path_repo_base_for_fixtures() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../composer/tests/Composer/Test") +} + /// Rewrite `file://foobar` URLs in COMPOSER content to absolute fixture /// paths. Mirrors `composer/tests/Composer/Test/InstallerTest.php:540-542`: /// when a fixture's repository entry uses a relative `file://` URL, anchor @@ -101,12 +112,29 @@ async fn run_fixture_in_process(test: &ParsedTest) -> anyhow::Result = match &cli.command { Some(Commands::Install(args)) => { - install::run(root, args, &console, repositories, &mut executor).await + install::run( + root, + Some(&path_repo_base), + args, + &console, + repositories, + &mut executor, + ) + .await } Some(Commands::Update(args)) => { - update::run(root, args, &console, repositories, &mut executor).await + update::run( + root, + Some(&path_repo_base), + args, + &console, + repositories, + &mut executor, + ) + .await } other => anyhow::bail!("unsupported run command in fixture: {:?}", other.is_some()), }; @@ -217,8 +245,8 @@ macro_rules! installer_fixture { installer_fixture!(abandoned_listed); installer_fixture!(alias_in_complex_constraints, ignore); -installer_fixture!(alias_in_lock, ignore); -installer_fixture!(alias_in_lock2, ignore); +installer_fixture!(alias_in_lock); +installer_fixture!(alias_in_lock2); installer_fixture!(alias_on_unloadable_package); installer_fixture!(alias_solver_problems); installer_fixture!(alias_solver_problems2); @@ -292,7 +320,7 @@ installer_fixture!(partial_update_from_lock_with_root_alias, ignore); installer_fixture!(partial_update_installs_from_lock_even_missing, ignore); installer_fixture!(partial_update_keeps_older_dep_if_still_required); installer_fixture!(partial_update_keeps_older_dep_if_still_required_with_provide); -installer_fixture!(partial_update_loads_root_aliases_for_path_repos, ignore); +installer_fixture!(partial_update_loads_root_aliases_for_path_repos); installer_fixture!(partial_update_security_advisory_matching_locked_dep); installer_fixture!(partial_update_security_advisory_matching_locked_dep_with_dependencies); installer_fixture!(partial_update_with_dependencies_provide); -- cgit v1.3.1