From 59bab6efee41a196b0d9d392167c536abbe068ba Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 10 May 2026 20:31:00 +0900 Subject: refactor(downloader): introduce top-level downloader module Move VCS downloaders and DownloadManager out of vcs/repository into a new top-level downloader module mirroring Composer\Downloader, and add stub types for the remaining Composer downloader hierarchy (file, archive variants, path, perforce, fossil, exceptions, interfaces) so future ports have a home. --- .../mozart-core/src/repository/download_manager.rs | 143 --------------------- .../repository/installer_executor/filesystem.rs | 18 +-- 2 files changed, 9 insertions(+), 152 deletions(-) delete mode 100644 crates/mozart-core/src/repository/download_manager.rs (limited to 'crates/mozart-core/src/repository') diff --git a/crates/mozart-core/src/repository/download_manager.rs b/crates/mozart-core/src/repository/download_manager.rs deleted file mode 100644 index d422899..0000000 --- a/crates/mozart-core/src/repository/download_manager.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! `DownloadManager` — pick the right [`VcsDownloader`] for a given -//! [`LocalPackage`]. Mirrors `Composer\Downloader\DownloadManager`. - -use std::path::PathBuf; - -use crate::composer::{InstallationSource, LocalPackage}; -use crate::vcs::downloader::VcsDownloader; -use crate::vcs::downloader::git::GitDownloader; -use crate::vcs::downloader::hg::HgDownloader; -use crate::vcs::downloader::svn::SvnDownloader; -use crate::vcs::process::ProcessExecutor; -use crate::vcs::util::git::GitUtil; -use crate::vcs::util::hg::HgUtil; -use crate::vcs::util::svn::SvnUtil; - -/// Selects a `VcsDownloader` for a package based on its installation source -/// and source type. Mirrors `DownloadManager::getDownloaderForPackage`: -/// -/// - `metapackage` → `None`. -/// - `installation-source: dist` → `None` (Composer would return a -/// `FileDownloader`-family object that does not implement -/// `ChangeReportInterface` / `DvcsDownloaderInterface`, so the status -/// command's `instanceof` checks all become no-ops; returning `None` -/// directly is the equivalent in our trait-object world). -/// - `installation-source: source` → the matching VCS downloader by -/// `source.type` (`git` / `hg` / `svn`). -pub struct DownloadManager { - git_cache_dir: PathBuf, -} - -impl DownloadManager { - /// `git_cache_dir`: where `GitUtil` should keep mirror clones (e.g. - /// `/.cache/git`). - pub fn new(git_cache_dir: PathBuf) -> Self { - Self { git_cache_dir } - } - - pub fn get_downloader_for_package( - &self, - package: &LocalPackage, - ) -> Option> { - if package.package_type() == Some("metapackage") { - return None; - } - match package.installation_source()? { - InstallationSource::Dist => None, - InstallationSource::Source => { - let kind = package.source()?.kind.as_str(); - match kind { - "git" => { - let git_util = - GitUtil::new(ProcessExecutor::new(), self.git_cache_dir.clone()); - Some(Box::new(GitDownloader::new(git_util))) - } - "hg" => { - let hg_util = HgUtil::new(ProcessExecutor::new()); - Some(Box::new(HgDownloader::new(hg_util))) - } - "svn" => { - let svn_util = SvnUtil::new(ProcessExecutor::new()); - Some(Box::new(SvnDownloader::new(svn_util))) - } - _ => None, - } - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::composer::PackageReference; - use serde_json::Value; - - fn pkg( - installation_source: Option, - source_kind: Option<&str>, - ) -> LocalPackage { - let source = source_kind.map(|kind| PackageReference { - kind: kind.to_string(), - url: "https://example/repo".into(), - reference: Some("abc123".into()), - shasum: None, - }); - LocalPackage::new( - "vendor/pkg".into(), - "1.0.0".into(), - None, - Some("library".into()), - installation_source, - source, - None, - Value::Null, - ) - } - - #[test] - fn metapackage_returns_none() { - let dm = DownloadManager::new(PathBuf::from("/tmp/mz-test-cache")); - let mut p = pkg(Some(InstallationSource::Source), Some("git")); - // override type - p = LocalPackage::new( - "vendor/pkg".into(), - "1.0.0".into(), - None, - Some("metapackage".into()), - p.installation_source(), - p.source().cloned(), - None, - Value::Null, - ); - assert!(dm.get_downloader_for_package(&p).is_none()); - } - - #[test] - fn dist_install_returns_none() { - let dm = DownloadManager::new(PathBuf::from("/tmp/mz-test-cache")); - let p = pkg(Some(InstallationSource::Dist), Some("git")); - assert!(dm.get_downloader_for_package(&p).is_none()); - } - - #[test] - fn source_install_with_git_returns_some() { - let dm = DownloadManager::new(PathBuf::from("/tmp/mz-test-cache")); - let p = pkg(Some(InstallationSource::Source), Some("git")); - assert!(dm.get_downloader_for_package(&p).is_some()); - } - - #[test] - fn unknown_source_kind_returns_none() { - let dm = DownloadManager::new(PathBuf::from("/tmp/mz-test-cache")); - let p = pkg(Some(InstallationSource::Source), Some("perforce")); - assert!(dm.get_downloader_for_package(&p).is_none()); - } - - #[test] - fn missing_installation_source_returns_none() { - let dm = DownloadManager::new(PathBuf::from("/tmp/mz-test-cache")); - let p = pkg(None, Some("git")); - assert!(dm.get_downloader_for_package(&p).is_none()); - } -} diff --git a/crates/mozart-core/src/repository/installer_executor/filesystem.rs b/crates/mozart-core/src/repository/installer_executor/filesystem.rs index 3f982e3..2b34e02 100644 --- a/crates/mozart-core/src/repository/installer_executor/filesystem.rs +++ b/crates/mozart-core/src/repository/installer_executor/filesystem.rs @@ -5,9 +5,10 @@ //! [`crate::vcs`], and removes vendor directories. Test code substitutes a //! recording-only executor instead (added in a later step). -use super::super::cache::Cache; -use super::super::downloader; -use super::{ExecuteContext, InstallerExecutor, PackageOperation}; +use crate::downloader::{GitDownloader, HgDownloader, SvnDownloader}; +use crate::repository::cache::Cache; +use crate::repository::downloader; +use crate::repository::installer_executor::{ExecuteContext, InstallerExecutor, PackageOperation}; use std::path::Path; pub struct FilesystemExecutor { @@ -135,6 +136,8 @@ fn install_from_source( vendor_dir: &Path, package_name: &str, ) -> anyhow::Result<()> { + use crate::downloader::VcsDownloader as _; + let target = vendor_dir.join(package_name); if target.exists() { std::fs::remove_dir_all(&target)?; @@ -145,23 +148,20 @@ fn install_from_source( let process = crate::vcs::process::ProcessExecutor::new(); let git_util = crate::vcs::util::git::GitUtil::new(process, vendor_dir.join(".cache").join("git")); - let downloader = crate::vcs::downloader::git::GitDownloader::new(git_util); - use crate::vcs::downloader::VcsDownloader as _; + let downloader = GitDownloader::new(git_util); downloader.download(url, reference, &target)?; downloader.install(url, reference, &target)?; } "svn" => { let process = crate::vcs::process::ProcessExecutor::new(); let svn_util = crate::vcs::util::svn::SvnUtil::new(process); - let downloader = crate::vcs::downloader::svn::SvnDownloader::new(svn_util); - use crate::vcs::downloader::VcsDownloader as _; + let downloader = SvnDownloader::new(svn_util); downloader.install(url, reference, &target)?; } "hg" => { let process = crate::vcs::process::ProcessExecutor::new(); let hg_util = crate::vcs::util::hg::HgUtil::new(process); - let downloader = crate::vcs::downloader::hg::HgDownloader::new(hg_util); - use crate::vcs::downloader::VcsDownloader as _; + let downloader = HgDownloader::new(hg_util); downloader.install(url, reference, &target)?; } _ => { -- cgit v1.3.1