From 4d587407cc9471dc8bfc0544eac0f8c7041fba0d Mon Sep 17 00:00:00 2001 From: nsfisis Date: Fri, 1 May 2026 22:26:16 +0900 Subject: feat(registry): support inline 'type: package' repositories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Composer's PackageRepository lets composer.json embed full package metadata under repositories[].package, mirroring the on-disk Packagist response shape. The vast majority of installer fixtures under composer/tests/Composer/Test/Fixtures/installer (179 of 189) rely on this — they declare every package they need inline rather than hitting the network. Three pieces wire this into Mozart: 1. mozart-core::package::RawRepository: relax `url` to Option (Composer enforces presence per repo type, not at JSON parse) and add `package: Option` to receive the inline definition, which can be a single object or an array. 2. mozart-registry::inline_package: a new module that walks `&[RawRepository]`, picks out type=package entries, and reshapes each `package` payload into a PackagistVersion (auto-computing version_normalized when omitted, matching Packagist's output). 3. resolver::resolve and lockfile::generate_lock_file: feed inline packages into the SAT pool builder and short-circuit the Packagist fetch when generating the lock entry for a resolved inline package. The package-name set is shared with the existing VCS-skip logic so the seed and transitive loops don't double-fetch. One additional install-time change: in install_from_lock, packages that have neither dist nor source are now skipped silently instead of bailing with "no dist or source information". This mirrors Composer's MetapackageInstaller (no installer for type=metapackage) and is also what Composer's own AllFunctionalTest exercises via InstallationManagerMock — most inline-package fixtures define synthetic packages with no download metadata, expecting the install operation to be recorded but not actually run. Net effect: installer fixture scoreboard jumps from 7/187 to 103/187. The 84 fixtures still ignored hit issues unrelated to inline-package plumbing — aliases, replace/provide chains, dev-reference handling, allow-list updates, etc. — and are tracked separately. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/mozart-core/src/package.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'crates/mozart-core/src/package.rs') diff --git a/crates/mozart-core/src/package.rs b/crates/mozart-core/src/package.rs index a45a480..02ec935 100644 --- a/crates/mozart-core/src/package.rs +++ b/crates/mozart-core/src/package.rs @@ -529,7 +529,19 @@ pub struct RawAutoload { pub struct RawRepository { #[serde(rename = "type")] pub repo_type: String, - pub url: String, + + /// Required for VCS / composer / artifact / path types; absent for inline + /// `package` repositories. Modeled as Option to mirror Composer's + /// per-type schema (Composer enforces presence in `RepositoryFactory`, + /// not at the JSON-parse step). + #[serde(default, skip_serializing_if = "Option::is_none")] + pub url: Option, + + /// Inline package definition(s) for `type: package` repositories. Either + /// a single object or an array of objects, mirroring + /// `Composer\Repository\PackageRepository`'s schema. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub package: Option, } /// Default root-package name when `composer.json` omits the `name` field. @@ -635,7 +647,8 @@ mod tests { .insert("phpunit/phpunit".to_string(), "^10.0".to_string()); raw.repositories = vec![RawRepository { repo_type: "vcs".to_string(), - url: "https://github.com/acme/repo".to_string(), + url: Some("https://github.com/acme/repo".to_string()), + package: None, }]; let mut psr4 = BTreeMap::new(); -- cgit v1.3.1