From 60bfd667e4a98f5463a5bd5f2d0259bd0eeb0a5e Mon Sep 17 00:00:00 2001 From: nsfisis Date: Wed, 3 Jun 2026 23:06:16 +0900 Subject: feat(downloader): wire as_* downcasts for file/archive/path/git downloaders Override DownloaderInterface's as_change_report_interface / as_vcs_capable_downloader_interface / as_dvcs_downloader_interface so PHP-style instanceof checks resolve to the concrete sub-interface: FileDownloader and the six archive downloaders (Zip/Tar/Gzip/Xz/Rar/Phar) plus PathDownloader gain ChangeReportInterface (archives/path delegate to the inner FileDownloader), PathDownloader exposes VcsCapableDownloaderInterface, and GitDownloader exposes DvcsDownloaderInterface. The default None impls remain correct for downloaders that do not implement a given sub-interface, so their stale TODO markers are dropped. VCS downloaders' ChangeReport/VcsCapable conformance follows separately. Co-Authored-By: Claude Opus 4.8 --- .../shirabe/src/downloader/downloader_interface.rs | 3 --- crates/shirabe/src/downloader/file_downloader.rs | 4 ++++ crates/shirabe/src/downloader/git_downloader.rs | 6 ++++++ crates/shirabe/src/downloader/gzip_downloader.rs | 15 +++++++++++++++ crates/shirabe/src/downloader/path_downloader.rs | 21 +++++++++++++++++++++ crates/shirabe/src/downloader/phar_downloader.rs | 15 +++++++++++++++ crates/shirabe/src/downloader/rar_downloader.rs | 15 +++++++++++++++ crates/shirabe/src/downloader/tar_downloader.rs | 15 +++++++++++++++ crates/shirabe/src/downloader/xz_downloader.rs | 15 +++++++++++++++ crates/shirabe/src/downloader/zip_downloader.rs | 15 +++++++++++++++ 10 files changed, 121 insertions(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/shirabe/src/downloader/downloader_interface.rs b/crates/shirabe/src/downloader/downloader_interface.rs index 986db28..873438e 100644 --- a/crates/shirabe/src/downloader/downloader_interface.rs +++ b/crates/shirabe/src/downloader/downloader_interface.rs @@ -80,19 +80,16 @@ pub trait DownloaderInterface: std::fmt::Debug { prev_package: Option, ) -> anyhow::Result>; - /// TODO(phase-b): runtime downcast helpers for PHP `instanceof` checks. fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { None } - /// TODO(phase-b): runtime downcast helpers for PHP `instanceof` checks. fn as_vcs_capable_downloader_interface( &self, ) -> Option<&dyn crate::downloader::VcsCapableDownloaderInterface> { None } - /// TODO(phase-b): runtime downcast helpers for PHP `instanceof` checks. fn as_dvcs_downloader_interface( &self, ) -> Option<&dyn crate::downloader::DvcsDownloaderInterface> { diff --git a/crates/shirabe/src/downloader/file_downloader.rs b/crates/shirabe/src/downloader/file_downloader.rs index dadf8fb..5b66a9f 100644 --- a/crates/shirabe/src/downloader/file_downloader.rs +++ b/crates/shirabe/src/downloader/file_downloader.rs @@ -153,6 +153,10 @@ impl DownloaderInterface for FileDownloader { "dist".to_owned() } + fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { + Some(self) + } + /// @inheritDoc async fn download( &self, diff --git a/crates/shirabe/src/downloader/git_downloader.rs b/crates/shirabe/src/downloader/git_downloader.rs index ed6f913..6d545ce 100644 --- a/crates/shirabe/src/downloader/git_downloader.rs +++ b/crates/shirabe/src/downloader/git_downloader.rs @@ -1380,6 +1380,12 @@ impl crate::downloader::DownloaderInterface for GitDownloader { todo!() } + fn as_dvcs_downloader_interface( + &self, + ) -> Option<&dyn crate::downloader::DvcsDownloaderInterface> { + Some(self) + } + async fn download( &self, _package: PackageInterfaceHandle, diff --git a/crates/shirabe/src/downloader/gzip_downloader.rs b/crates/shirabe/src/downloader/gzip_downloader.rs index 00adca9..337e298 100644 --- a/crates/shirabe/src/downloader/gzip_downloader.rs +++ b/crates/shirabe/src/downloader/gzip_downloader.rs @@ -3,6 +3,7 @@ use crate::cache::Cache; use crate::config::Config; use crate::downloader::ArchiveDownloader; +use crate::downloader::ChangeReportInterface; use crate::downloader::FileDownloader; use crate::event_dispatcher::EventDispatcher; use crate::io::IOInterface; @@ -129,12 +130,26 @@ impl GzipDownloader { } } +impl ChangeReportInterface for GzipDownloader { + fn get_local_changes( + &self, + package: PackageInterfaceHandle, + path: &str, + ) -> Result> { + self.inner.get_local_changes(package, path) + } +} + #[async_trait::async_trait(?Send)] impl crate::downloader::DownloaderInterface for GzipDownloader { fn get_installation_source(&self) -> String { self.inner.get_installation_source() } + fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { + Some(self) + } + async fn download( &self, package: PackageInterfaceHandle, diff --git a/crates/shirabe/src/downloader/path_downloader.rs b/crates/shirabe/src/downloader/path_downloader.rs index c50856e..3eb2a48 100644 --- a/crates/shirabe/src/downloader/path_downloader.rs +++ b/crates/shirabe/src/downloader/path_downloader.rs @@ -14,6 +14,7 @@ use crate::cache::Cache; use crate::config::Config; use crate::dependency_resolver::operation::InstallOperation; use crate::dependency_resolver::operation::UninstallOperation; +use crate::downloader::ChangeReportInterface; use crate::downloader::DownloaderInterface; use crate::downloader::FileDownloader; use crate::downloader::VcsCapableDownloaderInterface; @@ -534,6 +535,16 @@ impl VcsCapableDownloaderInterface for PathDownloader { } } +impl crate::downloader::ChangeReportInterface for PathDownloader { + fn get_local_changes( + &self, + package: PackageInterfaceHandle, + path: &str, + ) -> anyhow::Result> { + self.inner.get_local_changes(package, path) + } +} + // TODO(phase-b): wire up PathDownloader trait properly. PathDownloader extends FileDownloader and // overrides download/install/remove with &mut self signatures that diverge from the trait. The // trait methods here delegate to the inner FileDownloader; the bespoke overrides on the struct @@ -544,6 +555,16 @@ impl DownloaderInterface for PathDownloader { self.inner.get_installation_source() } + fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { + Some(self) + } + + fn as_vcs_capable_downloader_interface( + &self, + ) -> Option<&dyn crate::downloader::VcsCapableDownloaderInterface> { + Some(self) + } + async fn download( &self, package: PackageInterfaceHandle, diff --git a/crates/shirabe/src/downloader/phar_downloader.rs b/crates/shirabe/src/downloader/phar_downloader.rs index 6a4ac97..46fdd84 100644 --- a/crates/shirabe/src/downloader/phar_downloader.rs +++ b/crates/shirabe/src/downloader/phar_downloader.rs @@ -3,6 +3,7 @@ use crate::cache::Cache; use crate::config::Config; use crate::downloader::ArchiveDownloader; +use crate::downloader::ChangeReportInterface; use crate::downloader::DownloaderInterface; use crate::downloader::FileDownloader; use crate::event_dispatcher::EventDispatcher; @@ -63,12 +64,26 @@ impl PharDownloader { } } +impl ChangeReportInterface for PharDownloader { + fn get_local_changes( + &self, + package: PackageInterfaceHandle, + path: &str, + ) -> Result> { + self.inner.get_local_changes(package, path) + } +} + #[async_trait::async_trait(?Send)] impl DownloaderInterface for PharDownloader { fn get_installation_source(&self) -> String { self.inner.get_installation_source() } + fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { + Some(self) + } + async fn download( &self, package: PackageInterfaceHandle, diff --git a/crates/shirabe/src/downloader/rar_downloader.rs b/crates/shirabe/src/downloader/rar_downloader.rs index 9ce6c51..4385bc3 100644 --- a/crates/shirabe/src/downloader/rar_downloader.rs +++ b/crates/shirabe/src/downloader/rar_downloader.rs @@ -3,6 +3,7 @@ use crate::cache::Cache; use crate::config::Config; use crate::downloader::ArchiveDownloader; +use crate::downloader::ChangeReportInterface; use crate::downloader::FileDownloader; use crate::event_dispatcher::EventDispatcher; use crate::io::IOInterface; @@ -143,12 +144,26 @@ impl RarDownloader { } } +impl ChangeReportInterface for RarDownloader { + fn get_local_changes( + &self, + package: PackageInterfaceHandle, + path: &str, + ) -> Result> { + self.inner.get_local_changes(package, path) + } +} + #[async_trait::async_trait(?Send)] impl crate::downloader::DownloaderInterface for RarDownloader { fn get_installation_source(&self) -> String { self.inner.get_installation_source() } + fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { + Some(self) + } + async fn download( &self, package: PackageInterfaceHandle, diff --git a/crates/shirabe/src/downloader/tar_downloader.rs b/crates/shirabe/src/downloader/tar_downloader.rs index 07d8a5f..6cf1176 100644 --- a/crates/shirabe/src/downloader/tar_downloader.rs +++ b/crates/shirabe/src/downloader/tar_downloader.rs @@ -3,6 +3,7 @@ use crate::cache::Cache; use crate::config::Config; use crate::downloader::ArchiveDownloader; +use crate::downloader::ChangeReportInterface; use crate::downloader::DownloaderInterface; use crate::downloader::FileDownloader; use crate::event_dispatcher::EventDispatcher; @@ -58,12 +59,26 @@ impl TarDownloader { } } +impl ChangeReportInterface for TarDownloader { + fn get_local_changes( + &self, + package: PackageInterfaceHandle, + path: &str, + ) -> Result> { + self.inner.get_local_changes(package, path) + } +} + #[async_trait::async_trait(?Send)] impl DownloaderInterface for TarDownloader { fn get_installation_source(&self) -> String { self.inner.get_installation_source() } + fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { + Some(self) + } + async fn download( &self, package: PackageInterfaceHandle, diff --git a/crates/shirabe/src/downloader/xz_downloader.rs b/crates/shirabe/src/downloader/xz_downloader.rs index ac8b6ba..976497a 100644 --- a/crates/shirabe/src/downloader/xz_downloader.rs +++ b/crates/shirabe/src/downloader/xz_downloader.rs @@ -3,6 +3,7 @@ use crate::cache::Cache; use crate::config::Config; use crate::downloader::ArchiveDownloader; +use crate::downloader::ChangeReportInterface; use crate::downloader::FileDownloader; use crate::event_dispatcher::EventDispatcher; use crate::io::IOInterface; @@ -77,12 +78,26 @@ impl XzDownloader { } } +impl ChangeReportInterface for XzDownloader { + fn get_local_changes( + &self, + package: PackageInterfaceHandle, + path: &str, + ) -> Result> { + self.inner.get_local_changes(package, path) + } +} + #[async_trait::async_trait(?Send)] impl crate::downloader::DownloaderInterface for XzDownloader { fn get_installation_source(&self) -> String { self.inner.get_installation_source() } + fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { + Some(self) + } + async fn download( &self, package: PackageInterfaceHandle, diff --git a/crates/shirabe/src/downloader/zip_downloader.rs b/crates/shirabe/src/downloader/zip_downloader.rs index 17eeae5..3fda248 100644 --- a/crates/shirabe/src/downloader/zip_downloader.rs +++ b/crates/shirabe/src/downloader/zip_downloader.rs @@ -1,6 +1,7 @@ //! ref: composer/src/Composer/Downloader/ZipDownloader.php use crate::downloader::ArchiveDownloader; +use crate::downloader::ChangeReportInterface; use crate::downloader::DownloaderInterface; use crate::downloader::FileDownloader; use crate::io::IOInterface; @@ -553,6 +554,16 @@ impl ZipDownloader { } } +impl ChangeReportInterface for ZipDownloader { + fn get_local_changes( + &self, + package: PackageInterfaceHandle, + path: &str, + ) -> Result> { + self.inner.get_local_changes(package, path) + } +} + // TODO(phase-b): ZipDownloader::download is overridden with extra setup (UNZIP_COMMANDS init, // etc.). The trait method here delegates straight to the inner FileDownloader; the bespoke // override on the struct itself takes &mut self and is not yet routed through the trait. @@ -562,6 +573,10 @@ impl crate::downloader::DownloaderInterface for ZipDownloader { self.inner.get_installation_source() } + fn as_change_report_interface(&self) -> Option<&dyn crate::downloader::ChangeReportInterface> { + Some(self) + } + async fn download( &self, package: PackageInterfaceHandle, -- cgit v1.3.1