diff options
Diffstat (limited to 'crates/mozart-core/src/downloader')
5 files changed, 129 insertions, 66 deletions
diff --git a/crates/mozart-core/src/downloader/download_manager.rs b/crates/mozart-core/src/downloader/download_manager.rs index c83bc64..68ae20e 100644 --- a/crates/mozart-core/src/downloader/download_manager.rs +++ b/crates/mozart-core/src/downloader/download_manager.rs @@ -1,40 +1,49 @@ -//! `DownloadManager` — pick the right [`VcsDownloader`] for a given -//! [`LocalPackage`]. Mirrors `Composer\Downloader\DownloadManager`. - use crate::composer::{InstallationSource, LocalPackage}; -use crate::downloader::{GitDownloader, HgDownloader, SvnDownloader, VcsDownloader}; -use crate::vcs::process::ProcessExecutor; -use crate::vcs::util::git::GitUtil; -use crate::vcs::util::hg::HgUtil; -use crate::vcs::util::svn::SvnUtil; -use std::path::PathBuf; +use crate::console::IoInterface; +use crate::downloader::{DownloaderInterface, VcsDownloader}; +use crate::repository::cache::Cache; +use crate::repository::downloader::{DownloadProgress, download_dist}; +use crate::util::Filesystem; -/// 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`). +/// ref: \Composer\Downloader\DownloadManager pub struct DownloadManager { - git_cache_dir: PathBuf, + #[allow(unused)] + io: std::sync::Arc<std::sync::Mutex<Box<dyn IoInterface>>>, + prefer_dist: bool, + prefer_source: bool, + #[allow(unused)] + package_preferences: Vec<(String, InstallationSource)>, + #[allow(unused)] + filesystem: Filesystem, + downloaders: indexmap::IndexMap<String, Box<dyn DownloaderInterface>>, + files_cache: Cache, // TODO: remove } impl DownloadManager { - /// `git_cache_dir`: where `GitUtil` should keep mirror clones (e.g. - /// `<vendor>/.cache/git`). - pub fn new(git_cache_dir: PathBuf) -> Self { - Self { git_cache_dir } + pub fn new( + io: std::sync::Arc<std::sync::Mutex<Box<dyn IoInterface>>>, + prefer_source: bool, + filesystem: Filesystem, + files_cache: Cache, + ) -> Self { + Self { + io, + prefer_dist: false, + prefer_source, + package_preferences: Vec::new(), + filesystem, + downloaders: indexmap::IndexMap::new(), + files_cache, + } } - pub fn get_downloader_for_package( - &self, - package: &LocalPackage, - ) -> Option<Box<dyn VcsDownloader>> { + pub fn set_downloader(&mut self, r#type: String, downloader: Box<dyn DownloaderInterface>) { + assert!(r#type.chars().all(|c| c.is_ascii_lowercase())); + + self.downloaders.insert(r#type, downloader); + } + + pub fn get_downloader_for_package(&self, package: &LocalPackage) -> Option<&dyn VcsDownloader> { if package.package_type() == Some("metapackage") { return None; } @@ -42,32 +51,58 @@ impl DownloadManager { 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, - } + self.downloaders + .get(kind) + .and_then(|d| d.as_vcs_downloader()) } } } + + /// Makes downloader prefer source installation over the dist. + pub fn set_prefer_source(&mut self, prefer_source: bool) { + self.prefer_source = prefer_source; + } + + /// Makes downloader prefer dist installation over the source. + pub fn set_prefer_dist(&mut self, prefer_dist: bool) { + self.prefer_dist = prefer_dist; + } + + pub async fn download_legacy( + &self, + url: &str, + expected_shasum: Option<&str>, + progress: Option<&mut DownloadProgress>, + ) -> anyhow::Result<Vec<u8>> { + download_dist(url, expected_shasum, progress, &self.files_cache).await + } } #[cfg(test)] mod tests { use super::*; use crate::composer::PackageReference; + use crate::console::Console; + use crate::downloader::GitDownloader; + use crate::vcs::process::ProcessExecutor; use serde_json::Value; + use std::path::PathBuf; + use std::sync::{Arc, Mutex}; + + fn make_dm() -> DownloadManager { + let io: Arc<Mutex<Box<dyn IoInterface>>> = Arc::new(Mutex::new(Box::new(Console::new( + 0, true, false, true, true, + )) + as Box<dyn IoInterface>)); + let cache_dir = PathBuf::from("/tmp/mz-test-cache"); + let cache = Cache::new(cache_dir.clone(), false); + let mut dm = DownloadManager::new(io, false, Filesystem::new(), cache); + dm.set_downloader( + "git".to_owned(), + Box::new(GitDownloader::new(ProcessExecutor::new(), cache_dir)), + ); + dm + } fn pkg( installation_source: Option<InstallationSource>, @@ -93,7 +128,7 @@ mod tests { #[test] fn metapackage_returns_none() { - let dm = DownloadManager::new(PathBuf::from("/tmp/mz-test-cache")); + let dm = make_dm(); let mut p = pkg(Some(InstallationSource::Source), Some("git")); // override type p = LocalPackage::new( @@ -111,28 +146,28 @@ mod tests { #[test] fn dist_install_returns_none() { - let dm = DownloadManager::new(PathBuf::from("/tmp/mz-test-cache")); + let dm = make_dm(); 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 dm = make_dm(); 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 dm = make_dm(); 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 dm = make_dm(); let p = pkg(None, Some("git")); assert!(dm.get_downloader_for_package(&p).is_none()); } diff --git a/crates/mozart-core/src/downloader/downloader_interface.rs b/crates/mozart-core/src/downloader/downloader_interface.rs index 9c1b585..6184a0d 100644 --- a/crates/mozart-core/src/downloader/downloader_interface.rs +++ b/crates/mozart-core/src/downloader/downloader_interface.rs @@ -1 +1,5 @@ -pub trait DownloaderInterface {} +use crate::downloader::VcsDownloader; + +pub trait DownloaderInterface: Send + Sync { + fn as_vcs_downloader(&self) -> Option<&dyn VcsDownloader>; +} diff --git a/crates/mozart-core/src/downloader/git_downloader.rs b/crates/mozart-core/src/downloader/git_downloader.rs index d4d8c44..6e1351c 100644 --- a/crates/mozart-core/src/downloader/git_downloader.rs +++ b/crates/mozart-core/src/downloader/git_downloader.rs @@ -1,12 +1,11 @@ +use crate::downloader::{DownloaderInterface, VcsDownloader}; +use crate::vcs::process::ProcessExecutor; +use crate::vcs::util::git::GitUtil; use anyhow::Result; use regex::Regex; use std::path::Path; use std::sync::LazyLock; -use crate::downloader::VcsDownloader; -use crate::vcs::process::ProcessExecutor; -use crate::vcs::util::git::GitUtil; - /// Match `<hex> HEAD` lines in `git show-ref --head -d` output. static HEAD_REF_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?im)^([a-f0-9]+) HEAD$").unwrap()); @@ -19,8 +18,10 @@ pub struct GitDownloader { } impl GitDownloader { - pub fn new(git_util: GitUtil) -> Self { - Self { git_util } + pub fn new(process: ProcessExecutor, cache_dir: std::path::PathBuf) -> Self { + Self { + git_util: GitUtil::new(process, cache_dir), + } } } @@ -235,6 +236,12 @@ impl VcsDownloader for GitDownloader { } } +impl DownloaderInterface for GitDownloader { + fn as_vcs_downloader(&self) -> Option<&dyn VcsDownloader> { + Some(self) + } +} + fn collect_show_ref(process: &ProcessExecutor, target: &Path) -> Result<Option<String>> { let output = process.execute(&["git", "show-ref", "--head", "-d"], Some(target))?; if output.status != 0 { diff --git a/crates/mozart-core/src/downloader/hg_downloader.rs b/crates/mozart-core/src/downloader/hg_downloader.rs index 9fb918e..dfe3546 100644 --- a/crates/mozart-core/src/downloader/hg_downloader.rs +++ b/crates/mozart-core/src/downloader/hg_downloader.rs @@ -1,16 +1,19 @@ +use crate::downloader::{DownloaderInterface, VcsDownloader}; +use crate::vcs::process::ProcessExecutor; +use crate::vcs::util::hg::HgUtil; use anyhow::Result; use std::path::Path; -use crate::{downloader::VcsDownloader, vcs::util::hg::HgUtil}; - /// Mercurial downloader using clone/pull/update. pub struct HgDownloader { hg_util: HgUtil, } impl HgDownloader { - pub fn new(hg_util: HgUtil) -> Self { - Self { hg_util } + pub fn new(process: ProcessExecutor) -> Self { + Self { + hg_util: HgUtil::new(process), + } } } @@ -82,3 +85,9 @@ impl VcsDownloader for HgDownloader { false } } + +impl DownloaderInterface for HgDownloader { + fn as_vcs_downloader(&self) -> Option<&dyn VcsDownloader> { + Some(self) + } +} diff --git a/crates/mozart-core/src/downloader/svn_downloader.rs b/crates/mozart-core/src/downloader/svn_downloader.rs index c78f9b7..690a090 100644 --- a/crates/mozart-core/src/downloader/svn_downloader.rs +++ b/crates/mozart-core/src/downloader/svn_downloader.rs @@ -1,11 +1,11 @@ +use crate::downloader::{DownloaderInterface, VcsDownloader}; +use crate::vcs::process::ProcessExecutor; +use crate::vcs::util::svn::SvnUtil; use anyhow::Result; use regex::Regex; use std::path::Path; use std::sync::LazyLock; -use crate::downloader::VcsDownloader; -use crate::vcs::util::svn::SvnUtil; - /// Match any non-`X` status line (mirror of Composer's /// `{^ *[^X ] +}m`). Ignores externals (`X` prefix). static SVN_STATUS_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?m)^ *[^X ] +").unwrap()); @@ -16,8 +16,10 @@ pub struct SvnDownloader { } impl SvnDownloader { - pub fn new(svn_util: SvnUtil) -> Self { - Self { svn_util } + pub fn new(process: ProcessExecutor) -> Self { + Self { + svn_util: SvnUtil::new(process), + } } } @@ -83,3 +85,9 @@ impl VcsDownloader for SvnDownloader { false } } + +impl DownloaderInterface for SvnDownloader { + fn as_vcs_downloader(&self) -> Option<&dyn VcsDownloader> { + Some(self) + } +} |
