aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-registry/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-02 17:21:29 +0900
committernsfisis <nsfisis@gmail.com>2026-05-02 17:21:29 +0900
commit43efd895d24b7ccd2853fa5bcf08ad0e621f33ce (patch)
tree6caa14192cb2c753b9699bc3c5d62fe334920718 /crates/mozart-registry/src
parent5b767cdd832d39816ee4c2dbf94274c0130dd572 (diff)
downloadphp-mozart-43efd895d24b7ccd2853fa5bcf08ad0e621f33ce.tar.gz
php-mozart-43efd895d24b7ccd2853fa5bcf08ad0e621f33ce.tar.zst
php-mozart-43efd895d24b7ccd2853fa5bcf08ad0e621f33ce.zip
refactor(registry): plumb RepositorySet and executor through callers
ResolveRequest and LockFileGenerationRequest now take Arc<RepositorySet> instead of a raw Cache. install_from_lock now accepts &mut dyn InstallerExecutor instead of constructing FilesystemExecutor internally. Both changes expose the DI injection points needed by the upcoming in-process test harness, where Packagist must be replaced with an empty RepositorySet (Composer's `'packagist' => false` test config) and filesystem install execution must be replaced with a tracing recorder (Composer's InstallationManagerMock). The eager VCS scan and inline-package preload still happen inside resolve(), so the RawRepository array is kept on ResolveRequest as raw_repositories - migrating those through RepositorySet remains a follow-up. RepositorySet gains with_packagist and empty constructors so production callers and future tests have a uniform construction shape. All 136 enabled installer fixtures + 114 mozart-registry tests + 541 mozart lib tests still green; clippy clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/mozart-registry/src')
-rw-r--r--crates/mozart-registry/src/lockfile.rs41
-rw-r--r--crates/mozart-registry/src/repository/mod.rs16
-rw-r--r--crates/mozart-registry/src/resolver.rs58
3 files changed, 62 insertions, 53 deletions
diff --git a/crates/mozart-registry/src/lockfile.rs b/crates/mozart-registry/src/lockfile.rs
index edda3e9..8022f8b 100644
--- a/crates/mozart-registry/src/lockfile.rs
+++ b/crates/mozart-registry/src/lockfile.rs
@@ -1,7 +1,5 @@
-use crate::cache::Cache;
use crate::packagist::{PackagistDist, PackagistSource, PackagistVersion};
-use crate::repository::packagist_repo::PackagistRepository;
-use crate::repository::{Repository, RepositorySet};
+use crate::repository::RepositorySet;
use crate::resolver::ResolvedPackage;
use mozart_core::package::{RawPackageData, to_json_pretty};
use serde::{Deserialize, Serialize};
@@ -9,18 +7,6 @@ use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::fs;
use std::path::Path;
-/// Build a [`RepositorySet`] containing only [`PackagistRepository`].
-///
-/// Used by `generate_lock_file` to fetch full metadata for resolved packages
-/// not already covered by inline `type: package` repositories. Step B routes
-/// only Packagist queries through the trait; VCS/inline migration is a
-/// follow-up.
-fn build_packagist_repo_set(repo_cache: &Cache) -> RepositorySet {
- let repos: Vec<Box<dyn Repository>> =
- vec![Box::new(PackagistRepository::new(repo_cache.clone()))];
- RepositorySet::new(repos)
-}
-
fn default_stability() -> String {
"stable".to_string()
}
@@ -364,8 +350,9 @@ pub struct LockFileGenerationRequest {
pub composer_json: RawPackageData,
/// Whether require-dev was included in resolution.
pub include_dev: bool,
- /// Repo cache for Packagist API calls made during generation.
- pub repo_cache: Cache,
+ /// Repository set used to fetch full metadata for resolved packages
+ /// that aren't already covered by inline `type: package` repositories.
+ pub repositories: std::sync::Arc<RepositorySet>,
}
impl LockFileGenerationRequest {
@@ -535,7 +522,7 @@ pub async fn generate_lock_file(request: &LockFileGenerationRequest) -> anyhow::
// through `RepositorySet`, which today contains only Packagist; future
// steps will move VCS / inline through the same set.
let mut package_metadata: HashMap<String, PackagistVersion> = HashMap::new();
- let repo_set = build_packagist_repo_set(&request.repo_cache);
+ let repo_set = &request.repositories;
for pkg in &request.resolved_packages {
if let Some(inline) = request.inline_lookup(&pkg.name, &pkg.version_normalized) {
package_metadata.insert(pkg.name.clone(), inline);
@@ -1092,7 +1079,9 @@ mod tests {
composer_json_content: composer_json_content.clone(),
composer_json,
include_dev: true,
- repo_cache: Cache::new(std::env::temp_dir().join("mozart-test-cache"), false),
+ repositories: std::sync::Arc::new(RepositorySet::with_packagist(
+ crate::cache::Cache::new(std::env::temp_dir().join("mozart-test-cache"), false),
+ )),
};
let lock = generate_lock_file(&request).await.unwrap();
@@ -1180,9 +1169,11 @@ mod tests {
#[tokio::test]
#[ignore]
async fn test_generate_lock_file_monolog() {
+ use crate::cache::Cache;
use crate::resolver::PlatformConfig;
use crate::resolver::{ResolveRequest, resolve};
use mozart_core::package::Stability;
+ use std::sync::Arc;
// Resolve monolog/monolog ^3.0
let resolve_request = ResolveRequest {
@@ -1197,9 +1188,12 @@ mod tests {
platform: PlatformConfig::new(),
ignore_platform_reqs: false,
ignore_platform_req_list: vec![],
- repo_cache: Cache::new(std::env::temp_dir().join("mozart-test-cache"), false),
+ repositories: Arc::new(RepositorySet::with_packagist(Cache::new(
+ std::env::temp_dir().join("mozart-test-cache"),
+ false,
+ ))),
temporary_constraints: HashMap::new(),
- repositories: vec![],
+ raw_repositories: vec![],
};
let resolved = resolve(&resolve_request)
@@ -1216,7 +1210,10 @@ mod tests {
composer_json_content: composer_json_content.clone(),
composer_json,
include_dev: false,
- repo_cache: Cache::new(std::env::temp_dir().join("mozart-test-cache"), false),
+ repositories: Arc::new(RepositorySet::with_packagist(Cache::new(
+ std::env::temp_dir().join("mozart-test-cache"),
+ false,
+ ))),
};
let lock = generate_lock_file(&gen_request)
diff --git a/crates/mozart-registry/src/repository/mod.rs b/crates/mozart-registry/src/repository/mod.rs
index 1ab8797..0f742a3 100644
--- a/crates/mozart-registry/src/repository/mod.rs
+++ b/crates/mozart-registry/src/repository/mod.rs
@@ -81,6 +81,22 @@ impl RepositorySet {
Self { repos }
}
+ /// Production default: a single [`packagist_repo::PackagistRepository`]
+ /// backed by the given on-disk cache. Mirrors what Composer does when
+ /// no `'packagist' => false` entry appears in the merged config.
+ pub fn with_packagist(repo_cache: crate::cache::Cache) -> Self {
+ Self::new(vec![Box::new(packagist_repo::PackagistRepository::new(
+ repo_cache,
+ ))])
+ }
+
+ /// An empty set. Mirrors Composer's `'packagist' => false` test config:
+ /// resolution proceeds entirely from packages already in the pool
+ /// (eager VCS scan, inline `type: package` repos, the locked repository).
+ pub fn empty() -> Self {
+ Self::new(Vec::new())
+ }
+
pub fn is_empty(&self) -> bool {
self.repos.is_empty()
}
diff --git a/crates/mozart-registry/src/resolver.rs b/crates/mozart-registry/src/resolver.rs
index 878dc02..336d6d7 100644
--- a/crates/mozart-registry/src/resolver.rs
+++ b/crates/mozart-registry/src/resolver.rs
@@ -6,11 +6,10 @@
use std::collections::{HashMap, HashSet};
use std::fmt;
+use std::sync::Arc;
-use crate::cache::Cache;
use crate::packagist;
-use crate::repository::packagist_repo::PackagistRepository;
-use crate::repository::{PackageQuery, Repository, RepositorySet};
+use crate::repository::{PackageQuery, RepositorySet};
use crate::vcs_bridge;
use mozart_core::package::{RawRepository, Stability};
use mozart_sat_resolver::{
@@ -348,14 +347,20 @@ pub struct ResolveRequest {
pub ignore_platform_reqs: bool,
/// Specific platform requirements to ignore.
pub ignore_platform_req_list: Vec<String>,
- /// On-disk repo cache for Packagist API responses.
- pub repo_cache: Cache,
+ /// Repository set used to fetch package metadata. Mirrors Composer's
+ /// `RepositoryManager`. Production builders construct this with a single
+ /// `PackagistRepository`; in-process test harnesses can construct one
+ /// without any HTTP-backed repos to mimic Composer's
+ /// `'packagist' => false` test config.
+ pub repositories: Arc<RepositorySet>,
/// Temporary version constraint overrides (from --with flag).
/// Maps package name (lowercase) to constraint string.
pub temporary_constraints: HashMap<String, String>,
- /// VCS repositories from composer.json "repositories" section.
- /// Used to fetch packages from VCS before falling back to Packagist.
- pub repositories: Vec<RawRepository>,
+ /// VCS / inline-package repository entries from composer.json's
+ /// `repositories` section, used by the eager VCS scan and inline-package
+ /// preload that still live in `resolve()` (Step B follow-up will move
+ /// these through `RepositorySet` too).
+ pub raw_repositories: Vec<RawRepository>,
}
/// A single package in the resolution output.
@@ -369,19 +374,6 @@ pub struct ResolvedPackage {
pub is_dev: bool,
}
-/// Build a [`RepositorySet`] containing only [`PackagistRepository`].
-///
-/// The resolver still preloads VCS and inline packages directly into the
-/// pool builder (and tracks their names in skip-lists) — Step B routes
-/// only Packagist queries through the trait. Migrating VCS/inline through
-/// `RepositorySet` is a follow-up. The function returns a single-repo set
-/// purely so the seed and transitive loops have a uniform call shape.
-fn build_packagist_repo_set(repo_cache: &Cache) -> RepositorySet {
- let repos: Vec<Box<dyn Repository>> =
- vec![Box::new(PackagistRepository::new(repo_cache.clone()))];
- RepositorySet::new(repos)
-}
-
// ─────────────────────────────────────────────────────────────────────────────
// Public resolve() function
// ─────────────────────────────────────────────────────────────────────────────
@@ -460,7 +452,7 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
}
// Scan VCS repositories and collect packages from them
- let vcs_packages = vcs_bridge::scan_vcs_repositories(&request.repositories).await;
+ let vcs_packages = vcs_bridge::scan_vcs_repositories(&request.raw_repositories).await;
let mut vcs_package_names: HashSet<String> = HashSet::new();
for vpkg in &vcs_packages {
vcs_package_names.insert(vpkg.name.clone());
@@ -481,7 +473,7 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
// Collect inline `type: package` repositories. These don't require any
// network fetch; they go straight into the pool and are also tracked by
// name so the Packagist seed/transitive loops below skip them.
- let inline_packages = crate::inline_package::collect_inline_packages(&request.repositories);
+ let inline_packages = crate::inline_package::collect_inline_packages(&request.raw_repositories);
let mut inline_package_names: HashSet<String> = HashSet::new();
for ipkg in &inline_packages {
inline_package_names.insert(ipkg.name.clone());
@@ -496,12 +488,12 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
}
}
- // Build the repository set used for Packagist queries (and, in future
- // steps, inline + VCS too). Today only Packagist flows through the
- // trait — VCS and inline packages above are still preloaded directly,
- // and their names go into the skip lists so we don't double-load them
- // through this set.
- let repo_set: RepositorySet = build_packagist_repo_set(&request.repo_cache);
+ // The repository set is supplied by the caller. Today production
+ // builders pass a single-Packagist set; in-process tests can pass a
+ // set with no HTTP-backed repos. VCS and inline packages above are
+ // still preloaded directly, and their names go into the skip lists so
+ // we don't double-load them through this set.
+ let repo_set: &RepositorySet = &request.repositories;
// Seed the builder with packages for root requirements.
let seed_names: Vec<String> = root_requires
@@ -993,6 +985,7 @@ mod tests {
#[tokio::test]
#[ignore]
async fn test_resolve_monolog_e2e() {
+ use crate::cache::Cache;
let request = ResolveRequest {
root_name: String::new(),
require: vec![("monolog/monolog".to_string(), "^3.0".to_string())],
@@ -1005,9 +998,12 @@ mod tests {
platform: PlatformConfig::new(),
ignore_platform_reqs: false,
ignore_platform_req_list: vec![],
- repo_cache: Cache::new(std::env::temp_dir().join("mozart-test-cache"), false),
+ repositories: Arc::new(RepositorySet::with_packagist(Cache::new(
+ std::env::temp_dir().join("mozart-test-cache"),
+ false,
+ ))),
temporary_constraints: HashMap::new(),
- repositories: vec![],
+ raw_repositories: vec![],
};
let result = resolve(&request).await;