aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-core/src/downloader
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mozart-core/src/downloader')
-rw-r--r--crates/mozart-core/src/downloader/download_manager.rs135
-rw-r--r--crates/mozart-core/src/downloader/downloader_interface.rs6
-rw-r--r--crates/mozart-core/src/downloader/git_downloader.rs19
-rw-r--r--crates/mozart-core/src/downloader/hg_downloader.rs17
-rw-r--r--crates/mozart-core/src/downloader/svn_downloader.rs18
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)
+ }
+}