From c1733d88510b7afb88f7a17849de514365e42c84 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 2 May 2026 16:53:41 +0900 Subject: refactor(registry): introduce Repository and InstallerExecutor traits Sets up DI scaffolding for in-process installer E2E tests, mirroring how Composer's PHPUnit suite swaps Packagist (FactoryMock) and the install manager (InstallationManagerMock) without touching the network or filesystem. Additions: - Repository trait + RepositorySet (Composer's RepositoryInterface analog), with PackagistRepository, InlinePackageRepository, VcsRepository impls. - InstallerExecutor trait (Composer's InstallationManager analog) with FilesystemExecutor extracted from install_from_lock. install_from_lock now delegates per-package install/uninstall verbs to FilesystemExecutor; console output orchestration stays in the caller so existing --EXPECT-OUTPUT-shape assertions remain comparable. No behavior change - all 136 enabled installer fixtures still pass. Also tightens the installer_fixture\! ignore form to a single token (installer_fixture\!(name, ignore)) for readability. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/repository/inline_package_repo.rs | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 crates/mozart-registry/src/repository/inline_package_repo.rs (limited to 'crates/mozart-registry/src/repository/inline_package_repo.rs') diff --git a/crates/mozart-registry/src/repository/inline_package_repo.rs b/crates/mozart-registry/src/repository/inline_package_repo.rs new file mode 100644 index 0000000..1043559 --- /dev/null +++ b/crates/mozart-registry/src/repository/inline_package_repo.rs @@ -0,0 +1,63 @@ +//! [`Repository`] for inline `type: package` repositories. +//! +//! Wraps [`crate::inline_package::collect_inline_packages`]. The data is +//! embedded in `composer.json` so there's no I/O — the repo just filters +//! its in-memory list by queried name. +//! +//! Mirrors `Composer\Repository\PackageRepository` (which extends +//! `ArrayRepository`). Only the package's own `name` is matched against +//! queries — `replace`/`provide` targets are NOT advertised here, exactly +//! like Composer's `ArrayRepository::loadPackages` checks `getName()` only. +//! Replacement satisfaction happens later in the solver once the replacing +//! package is loaded transitively. + +use super::{LoadResult, NamedPackagistVersion, PackageQuery, Repository}; +use crate::inline_package::{InlinePackage, collect_inline_packages}; +use mozart_core::package::RawRepository; + +pub struct InlinePackageRepository { + id: String, + packages: Vec, +} + +impl InlinePackageRepository { + /// Build from the raw `repositories` array of a `composer.json`. Non- + /// `package` entries are ignored. + pub fn from_repositories(repositories: &[RawRepository]) -> Self { + Self { + id: "package".to_string(), + packages: collect_inline_packages(repositories), + } + } + + pub fn package_count(&self) -> usize { + self.packages.len() + } +} + +#[async_trait::async_trait] +impl Repository for InlinePackageRepository { + fn id(&self) -> &str { + &self.id + } + + async fn load_packages(&self, queries: &[PackageQuery<'_>]) -> anyhow::Result { + let mut result = LoadResult::default(); + for query in queries { + let mut found_any = false; + for ipkg in &self.packages { + if ipkg.name == query.name { + found_any = true; + result.packages.push(NamedPackagistVersion { + name: ipkg.name.clone(), + version: ipkg.version.clone(), + }); + } + } + if found_any { + result.names_found.push(query.name.to_string()); + } + } + Ok(result) + } +} -- cgit v1.3.1