From 901878ee3f2bee6605b02d321cc4c92bc32fd5b0 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 27 Jun 2026 08:44:57 +0900 Subject: 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> 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) --- crates/shirabe/src/downloader/download_manager.rs | 139 ++++++++++++++++++++-- 1 file changed, 127 insertions(+), 12 deletions(-) (limited to 'crates/shirabe/src/downloader/download_manager.rs') diff --git a/crates/shirabe/src/downloader/download_manager.rs b/crates/shirabe/src/downloader/download_manager.rs index 183813d..a5a83a6 100644 --- a/crates/shirabe/src/downloader/download_manager.rs +++ b/crates/shirabe/src/downloader/download_manager.rs @@ -60,28 +60,22 @@ impl DownloadManager { /// Makes downloader prefer source installation over the dist. /// /// @param bool $preferSource prefer downloading from source - pub fn set_prefer_source(&mut self, prefer_source: bool) -> &mut Self { + pub fn set_prefer_source(&mut self, prefer_source: bool) { self.prefer_source = prefer_source; - - self } /// Makes downloader prefer dist installation over the source. /// /// @param bool $preferDist prefer downloading from dist - pub fn set_prefer_dist(&mut self, prefer_dist: bool) -> &mut Self { + pub fn set_prefer_dist(&mut self, prefer_dist: bool) { self.prefer_dist = prefer_dist; - - self } /// Sets fine tuned preference settings for package level source/dist selection. /// /// @param array $preferences array of preferences by package patterns - pub fn set_preferences(&mut self, preferences: IndexMap) -> &mut Self { + pub fn set_preferences(&mut self, preferences: IndexMap) { self.package_preferences = preferences; - - self } /// Sets installer downloader for a specific installation type. @@ -92,11 +86,9 @@ impl DownloadManager { &mut self, r#type: &str, downloader: std::rc::Rc>, - ) -> &mut Self { + ) { let r#type = strtolower(r#type); self.downloaders.insert(r#type, downloader); - - self } /// Returns downloader for a specific installation type. @@ -551,3 +543,126 @@ impl DownloadManager { rtrim(dir, Some("\\/")) } } + +// Composer's Composer::setDownloadManager() accepts any DownloadManager subclass, so plugins may +// swap in a replacement. The interface captures the methods reached through Composer's accessor and +// through the `Rc>` references fed from it. +#[async_trait::async_trait(?Send)] +pub trait DownloadManagerInterface: std::fmt::Debug { + fn set_prefer_source(&mut self, prefer_source: bool); + fn set_prefer_dist(&mut self, prefer_dist: bool); + fn get_downloader_for_package( + &self, + package: PackageInterfaceHandle, + ) -> Result>>>; + async fn download( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option, + ) -> Result>; + async fn prepare( + &self, + r#type: &str, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option, + ) -> Result>; + async fn install( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + ) -> Result>; + async fn update( + &self, + initial: PackageInterfaceHandle, + target: PackageInterfaceHandle, + target_dir: &str, + ) -> Result>; + async fn remove( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + ) -> Result>; + async fn cleanup( + &self, + r#type: &str, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option, + ) -> Result>; +} + +#[async_trait::async_trait(?Send)] +impl DownloadManagerInterface for DownloadManager { + fn set_prefer_source(&mut self, prefer_source: bool) { + self.set_prefer_source(prefer_source); + } + + fn set_prefer_dist(&mut self, prefer_dist: bool) { + self.set_prefer_dist(prefer_dist); + } + + fn get_downloader_for_package( + &self, + package: PackageInterfaceHandle, + ) -> Result>>> { + self.get_downloader_for_package(package) + } + + async fn download( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option, + ) -> Result> { + self.download(package, target_dir, prev_package).await + } + + async fn prepare( + &self, + r#type: &str, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option, + ) -> Result> { + self.prepare(r#type, package, target_dir, prev_package) + .await + } + + async fn install( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + ) -> Result> { + self.install(package, target_dir).await + } + + async fn update( + &self, + initial: PackageInterfaceHandle, + target: PackageInterfaceHandle, + target_dir: &str, + ) -> Result> { + self.update(initial, target, target_dir).await + } + + async fn remove( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + ) -> Result> { + self.remove(package, target_dir).await + } + + async fn cleanup( + &self, + r#type: &str, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option, + ) -> Result> { + self.cleanup(r#type, package, target_dir, prev_package) + .await + } +} -- cgit v1.3.1