diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-27 08:44:57 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-27 08:44:57 +0900 |
| commit | 901878ee3f2bee6605b02d321cc4c92bc32fd5b0 (patch) | |
| tree | 83d8c8c9a24cb95c0656866d328b87c2d4c5127f /crates/shirabe/src/autoload | |
| parent | 5c2c72223cb6b4d77a332eeeeff7ee4e82e3f239 (diff) | |
| download | php-shirabe-901878ee3f2bee6605b02d321cc4c92bc32fd5b0.tar.gz php-shirabe-901878ee3f2bee6605b02d321cc4c92bc32fd5b0.tar.zst php-shirabe-901878ee3f2bee6605b02d321cc4c92bc32fd5b0.zip | |
refactor(composer): hold managers behind *Interface traits
Composer/PartialComposer exposed its RepositoryManager, InstallationManager,
EventDispatcher, Locker, DownloadManager, AutoloadGenerator and ArchiveManager
as concrete types, but Composer's public setters (setDownloadManager() etc.)
let plugins swap in subclasses. Introduce a *Interface trait per manager and
store each as Rc<RefCell<dyn ...Interface>> so a replacement is honored.
Only Composer's slots and the sinks fed from its accessors become trait
objects; managers injected concretely at construction keep their concrete
references, matching PHP semantics. Fluent setters on the affected classes now
return () and Locker::update_hash is de-generified to a boxed FnOnce so the
traits stay object-safe.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/autoload')
| -rw-r--r-- | crates/shirabe/src/autoload/autoload_generator.rs | 136 |
1 files changed, 131 insertions, 5 deletions
diff --git a/crates/shirabe/src/autoload/autoload_generator.rs b/crates/shirabe/src/autoload/autoload_generator.rs index 1bdea07..1d0960d 100644 --- a/crates/shirabe/src/autoload/autoload_generator.rs +++ b/crates/shirabe/src/autoload/autoload_generator.rs @@ -21,12 +21,12 @@ use crate::event_dispatcher::EventDispatcher; use crate::filter::platform_requirement_filter::IgnoreAllPlatformRequirementFilter; use crate::filter::platform_requirement_filter::PlatformRequirementFilterFactory; use crate::filter::platform_requirement_filter::PlatformRequirementFilterInterface; -use crate::installer::InstallationManager; +use crate::installer::InstallationManagerInterface; use crate::io::IOInterface; use crate::io::IOInterfaceImmutable; use crate::io::NullIO; use crate::json::JsonFile; -use crate::package::Locker; +use crate::package::LockerInterface; use crate::package::PackageInterfaceHandle; use crate::package::RootPackageInterfaceHandle; use crate::repository::InstalledRepositoryInterface; @@ -107,11 +107,11 @@ impl AutoloadGenerator { config: &Config, local_repo: &mut dyn InstalledRepositoryInterface, root_package: RootPackageInterfaceHandle, - installation_manager: &mut InstallationManager, + installation_manager: &mut dyn InstallationManagerInterface, target_dir: &str, scan_psr_packages: bool, suffix: Option<String>, - locker: Option<&mut Locker>, + locker: Option<&mut dyn LockerInterface>, strict_ambiguous: bool, ) -> anyhow::Result<ClassMap> { let mut scan_psr_packages = scan_psr_packages; @@ -732,7 +732,7 @@ impl AutoloadGenerator { pub fn build_package_map( &self, - installation_manager: &mut InstallationManager, + installation_manager: &mut dyn InstallationManagerInterface, root_package: RootPackageInterfaceHandle, packages: Vec<PackageInterfaceHandle>, ) -> anyhow::Result<Vec<(PackageInterfaceHandle, Option<String>)>> { @@ -1930,6 +1930,132 @@ impl AutoloadGenerator { } } +// Composer's Composer::setAutoloadGenerator() accepts any AutoloadGenerator subclass, so plugins +// may swap in a replacement. The interface captures the methods reached through Composer's accessor +// and through the `Rc<RefCell<dyn AutoloadGeneratorInterface>>` references fed from it. +pub trait AutoloadGeneratorInterface: std::fmt::Debug { + fn set_dev_mode(&mut self, dev_mode: bool); + fn set_class_map_authoritative(&mut self, class_map_authoritative: bool); + fn set_apcu(&mut self, apcu: bool, apcu_prefix: Option<String>); + fn set_run_scripts(&mut self, run_scripts: bool); + fn set_dry_run(&mut self, dry_run: bool); + fn set_platform_requirement_filter( + &mut self, + platform_requirement_filter: std::rc::Rc<dyn PlatformRequirementFilterInterface>, + ); + #[allow(clippy::too_many_arguments, reason = "to keep PHP signature")] + fn dump( + &mut self, + config: &Config, + local_repo: &mut dyn InstalledRepositoryInterface, + root_package: RootPackageInterfaceHandle, + installation_manager: &mut dyn InstallationManagerInterface, + target_dir: &str, + scan_psr_packages: bool, + suffix: Option<String>, + locker: Option<&mut dyn LockerInterface>, + strict_ambiguous: bool, + ) -> anyhow::Result<ClassMap>; + fn build_package_map( + &self, + installation_manager: &mut dyn InstallationManagerInterface, + root_package: RootPackageInterfaceHandle, + packages: Vec<PackageInterfaceHandle>, + ) -> anyhow::Result<Vec<(PackageInterfaceHandle, Option<String>)>>; + fn parse_autoloads( + &self, + package_map: Vec<(PackageInterfaceHandle, Option<String>)>, + root_package: RootPackageInterfaceHandle, + filtered_dev_packages: PhpMixed, + ) -> IndexMap<String, PhpMixed>; + fn create_loader( + &self, + autoloads: &IndexMap<String, PhpMixed>, + vendor_dir: Option<String>, + ) -> ClassLoader; +} + +impl AutoloadGeneratorInterface for AutoloadGenerator { + fn set_dev_mode(&mut self, dev_mode: bool) { + self.set_dev_mode(dev_mode); + } + + fn set_class_map_authoritative(&mut self, class_map_authoritative: bool) { + self.set_class_map_authoritative(class_map_authoritative); + } + + fn set_apcu(&mut self, apcu: bool, apcu_prefix: Option<String>) { + self.set_apcu(apcu, apcu_prefix); + } + + fn set_run_scripts(&mut self, run_scripts: bool) { + self.set_run_scripts(run_scripts); + } + + fn set_dry_run(&mut self, dry_run: bool) { + self.set_dry_run(dry_run); + } + + fn set_platform_requirement_filter( + &mut self, + platform_requirement_filter: std::rc::Rc<dyn PlatformRequirementFilterInterface>, + ) { + self.set_platform_requirement_filter(platform_requirement_filter); + } + + #[allow(clippy::too_many_arguments, reason = "to keep PHP signature")] + fn dump( + &mut self, + config: &Config, + local_repo: &mut dyn InstalledRepositoryInterface, + root_package: RootPackageInterfaceHandle, + installation_manager: &mut dyn InstallationManagerInterface, + target_dir: &str, + scan_psr_packages: bool, + suffix: Option<String>, + locker: Option<&mut dyn LockerInterface>, + strict_ambiguous: bool, + ) -> anyhow::Result<ClassMap> { + self.dump( + config, + local_repo, + root_package, + installation_manager, + target_dir, + scan_psr_packages, + suffix, + locker, + strict_ambiguous, + ) + } + + fn build_package_map( + &self, + installation_manager: &mut dyn InstallationManagerInterface, + root_package: RootPackageInterfaceHandle, + packages: Vec<PackageInterfaceHandle>, + ) -> anyhow::Result<Vec<(PackageInterfaceHandle, Option<String>)>> { + self.build_package_map(installation_manager, root_package, packages) + } + + fn parse_autoloads( + &self, + package_map: Vec<(PackageInterfaceHandle, Option<String>)>, + root_package: RootPackageInterfaceHandle, + filtered_dev_packages: PhpMixed, + ) -> IndexMap<String, PhpMixed> { + self.parse_autoloads(package_map, root_package, filtered_dev_packages) + } + + fn create_loader( + &self, + autoloads: &IndexMap<String, PhpMixed>, + vendor_dir: Option<String>, + ) -> ClassLoader { + self.create_loader(autoloads, vendor_dir) + } +} + /// Evaluates one of the `autoload_namespaces.php` / `autoload_psr4.php` / `autoload_classmap.php` /// files that `dump` just generated, returning the `return array(...)` payload with every path /// expression resolved to an absolute string. This stands in for PHP's `require $file` (there is no |
