aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/downloader/download_manager.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-27 08:44:57 +0900
committernsfisis <nsfisis@gmail.com>2026-06-27 08:44:57 +0900
commit901878ee3f2bee6605b02d321cc4c92bc32fd5b0 (patch)
tree83d8c8c9a24cb95c0656866d328b87c2d4c5127f /crates/shirabe/src/downloader/download_manager.rs
parent5c2c72223cb6b4d77a332eeeeff7ee4e82e3f239 (diff)
downloadphp-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/download_manager.rs')
-rw-r--r--crates/shirabe/src/downloader/download_manager.rs139
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
+ }
+}