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/downloader | |
| 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/downloader')
| -rw-r--r-- | crates/shirabe/src/downloader/download_manager.rs | 139 |
1 files changed, 127 insertions, 12 deletions
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<string, string> $preferences array of preferences by package patterns - pub fn set_preferences(&mut self, preferences: IndexMap<String, String>) -> &mut Self { + pub fn set_preferences(&mut self, preferences: IndexMap<String, String>) { 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<std::cell::RefCell<dyn DownloaderInterface>>, - ) -> &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<RefCell<dyn DownloadManagerInterface>>` 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<Option<std::rc::Rc<std::cell::RefCell<dyn DownloaderInterface>>>>; + async fn download( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option<PackageInterfaceHandle>, + ) -> Result<Option<PhpMixed>>; + async fn prepare( + &self, + r#type: &str, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option<PackageInterfaceHandle>, + ) -> Result<Option<PhpMixed>>; + async fn install( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + ) -> Result<Option<PhpMixed>>; + async fn update( + &self, + initial: PackageInterfaceHandle, + target: PackageInterfaceHandle, + target_dir: &str, + ) -> Result<Option<PhpMixed>>; + async fn remove( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + ) -> Result<Option<PhpMixed>>; + async fn cleanup( + &self, + r#type: &str, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option<PackageInterfaceHandle>, + ) -> Result<Option<PhpMixed>>; +} + +#[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<Option<std::rc::Rc<std::cell::RefCell<dyn DownloaderInterface>>>> { + self.get_downloader_for_package(package) + } + + async fn download( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option<PackageInterfaceHandle>, + ) -> Result<Option<PhpMixed>> { + self.download(package, target_dir, prev_package).await + } + + async fn prepare( + &self, + r#type: &str, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option<PackageInterfaceHandle>, + ) -> Result<Option<PhpMixed>> { + self.prepare(r#type, package, target_dir, prev_package) + .await + } + + async fn install( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + ) -> Result<Option<PhpMixed>> { + self.install(package, target_dir).await + } + + async fn update( + &self, + initial: PackageInterfaceHandle, + target: PackageInterfaceHandle, + target_dir: &str, + ) -> Result<Option<PhpMixed>> { + self.update(initial, target, target_dir).await + } + + async fn remove( + &self, + package: PackageInterfaceHandle, + target_dir: &str, + ) -> Result<Option<PhpMixed>> { + self.remove(package, target_dir).await + } + + async fn cleanup( + &self, + r#type: &str, + package: PackageInterfaceHandle, + target_dir: &str, + prev_package: Option<PackageInterfaceHandle>, + ) -> Result<Option<PhpMixed>> { + self.cleanup(r#type, package, target_dir, prev_package) + .await + } +} |
