2024-07-28 18:19:54 +02:00
|
|
|
use crate::{
|
|
|
|
lockfile::{DependencyGraph, DownloadedDependencyGraphNode, DownloadedGraph},
|
|
|
|
source::{
|
|
|
|
traits::{PackageRef, PackageSource},
|
|
|
|
PackageSources,
|
|
|
|
},
|
|
|
|
Project, PACKAGES_CONTAINER_NAME,
|
|
|
|
};
|
2024-07-17 19:38:01 +02:00
|
|
|
use std::{
|
2024-07-23 01:20:50 +02:00
|
|
|
collections::HashSet,
|
2024-07-17 19:38:01 +02:00
|
|
|
fs::create_dir_all,
|
2024-07-23 01:20:50 +02:00
|
|
|
sync::{mpsc::Receiver, Arc, Mutex},
|
2024-07-17 19:38:01 +02:00
|
|
|
};
|
|
|
|
|
2024-07-23 01:20:50 +02:00
|
|
|
type MultithreadedGraph = Arc<Mutex<DownloadedGraph>>;
|
|
|
|
|
|
|
|
type MultithreadDownloadJob = (
|
|
|
|
Receiver<Result<(), errors::DownloadGraphError>>,
|
|
|
|
MultithreadedGraph,
|
|
|
|
);
|
|
|
|
|
2024-07-17 19:38:01 +02:00
|
|
|
impl Project {
|
2024-08-03 22:18:38 +02:00
|
|
|
/// Downloads a graph of dependencies
|
2024-07-17 19:38:01 +02:00
|
|
|
pub fn download_graph(
|
|
|
|
&self,
|
|
|
|
graph: &DependencyGraph,
|
|
|
|
refreshed_sources: &mut HashSet<PackageSources>,
|
2024-07-23 01:20:50 +02:00
|
|
|
reqwest: &reqwest::blocking::Client,
|
|
|
|
threads: usize,
|
|
|
|
) -> Result<MultithreadDownloadJob, errors::DownloadGraphError> {
|
2024-07-17 19:38:01 +02:00
|
|
|
let manifest = self.deser_manifest()?;
|
2024-07-23 01:20:50 +02:00
|
|
|
let downloaded_graph: MultithreadedGraph = Arc::new(Mutex::new(Default::default()));
|
2024-07-17 19:38:01 +02:00
|
|
|
|
2024-07-23 01:20:50 +02:00
|
|
|
let threadpool = threadpool::ThreadPool::new(threads);
|
|
|
|
let (tx, rx) = std::sync::mpsc::channel();
|
2024-07-17 19:38:01 +02:00
|
|
|
|
|
|
|
for (name, versions) in graph {
|
2024-07-22 23:16:04 +02:00
|
|
|
for (version_id, node) in versions {
|
2024-07-23 16:37:47 +02:00
|
|
|
let source = node.pkg_ref.source();
|
2024-07-17 19:38:01 +02:00
|
|
|
|
|
|
|
if refreshed_sources.insert(source.clone()) {
|
|
|
|
source.refresh(self).map_err(Box::new)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
let container_folder = node.container_folder(
|
|
|
|
&self
|
|
|
|
.path()
|
|
|
|
.join(node.base_folder(manifest.target.kind(), true))
|
|
|
|
.join(PACKAGES_CONTAINER_NAME),
|
|
|
|
name,
|
2024-07-22 23:16:04 +02:00
|
|
|
version_id.version(),
|
2024-07-17 19:38:01 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
create_dir_all(&container_folder)?;
|
|
|
|
|
2024-07-23 01:20:50 +02:00
|
|
|
let tx = tx.clone();
|
2024-07-17 19:38:01 +02:00
|
|
|
|
2024-07-23 01:20:50 +02:00
|
|
|
let name = name.clone();
|
|
|
|
let version_id = version_id.clone();
|
|
|
|
let node = node.clone();
|
|
|
|
|
|
|
|
let project = Arc::new(self.clone());
|
|
|
|
let reqwest = reqwest.clone();
|
|
|
|
let downloaded_graph = downloaded_graph.clone();
|
|
|
|
|
|
|
|
threadpool.execute(move || {
|
|
|
|
let project = project.clone();
|
|
|
|
|
2024-07-24 00:53:34 +02:00
|
|
|
log::debug!("downloading {name}@{version_id}");
|
|
|
|
|
2024-07-28 18:19:54 +02:00
|
|
|
let (fs, target) = match source.download(&node.pkg_ref, &project, &reqwest) {
|
|
|
|
Ok(target) => target,
|
|
|
|
Err(e) => {
|
|
|
|
tx.send(Err(e.into())).unwrap();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
2024-07-23 01:20:50 +02:00
|
|
|
|
2024-07-24 00:53:34 +02:00
|
|
|
log::debug!("downloaded {name}@{version_id}");
|
|
|
|
|
2024-07-28 18:19:54 +02:00
|
|
|
match fs.write_to(container_folder, project.cas_dir(), true) {
|
|
|
|
Ok(_) => {}
|
|
|
|
Err(e) => {
|
|
|
|
tx.send(Err(errors::DownloadGraphError::WriteFailed(e)))
|
|
|
|
.unwrap();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-07-23 01:20:50 +02:00
|
|
|
let mut downloaded_graph = downloaded_graph.lock().unwrap();
|
|
|
|
downloaded_graph
|
|
|
|
.entry(name)
|
|
|
|
.or_default()
|
|
|
|
.insert(version_id, DownloadedDependencyGraphNode { node, target });
|
|
|
|
|
|
|
|
tx.send(Ok(())).unwrap();
|
|
|
|
});
|
2024-07-17 19:38:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-23 01:20:50 +02:00
|
|
|
Ok((rx, downloaded_graph))
|
2024-07-17 19:38:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-03 22:18:38 +02:00
|
|
|
/// Errors that can occur when downloading a graph
|
2024-07-17 19:38:01 +02:00
|
|
|
pub mod errors {
|
|
|
|
use thiserror::Error;
|
|
|
|
|
2024-08-03 22:18:38 +02:00
|
|
|
/// Errors that can occur when downloading a graph
|
2024-07-17 19:38:01 +02:00
|
|
|
#[derive(Debug, Error)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum DownloadGraphError {
|
2024-08-03 22:18:38 +02:00
|
|
|
/// Error occurred deserializing the project manifest
|
2024-07-17 19:38:01 +02:00
|
|
|
#[error("error deserializing project manifest")]
|
|
|
|
ManifestDeserializationFailed(#[from] crate::errors::ManifestReadError),
|
|
|
|
|
2024-08-03 22:18:38 +02:00
|
|
|
/// Error occurred refreshing a package source
|
2024-07-17 19:38:01 +02:00
|
|
|
#[error("failed to refresh package source")]
|
|
|
|
RefreshFailed(#[from] Box<crate::source::errors::RefreshError>),
|
|
|
|
|
2024-08-03 22:18:38 +02:00
|
|
|
/// Error interacting with the filesystem
|
2024-07-17 19:38:01 +02:00
|
|
|
#[error("error interacting with filesystem")]
|
|
|
|
Io(#[from] std::io::Error),
|
|
|
|
|
2024-08-03 22:18:38 +02:00
|
|
|
/// Error downloading a package
|
2024-07-17 19:38:01 +02:00
|
|
|
#[error("failed to download package")]
|
|
|
|
DownloadFailed(#[from] crate::source::errors::DownloadError),
|
2024-07-28 18:19:54 +02:00
|
|
|
|
2024-08-03 22:18:38 +02:00
|
|
|
/// Error writing package contents
|
2024-07-28 18:19:54 +02:00
|
|
|
#[error("failed to write package contents")]
|
|
|
|
WriteFailed(std::io::Error),
|
2024-07-17 19:38:01 +02:00
|
|
|
}
|
|
|
|
}
|