pesde/src/download.rs

151 lines
5.2 KiB
Rust
Raw Normal View History

2024-07-28 18:19:54 +02:00
use crate::{
lockfile::{DependencyGraph, DownloadedDependencyGraphNode, DownloadedGraph},
2024-09-04 19:48:37 +02:00
manifest::DependencyType,
2024-07-28 18:19:54 +02:00
source::{
traits::{PackageRef, PackageSource},
PackageSources,
},
Project, PACKAGES_CONTAINER_NAME,
};
2024-11-05 20:44:24 +01:00
use fs_err::tokio as fs;
2024-07-17 19:38:01 +02:00
use std::{
collections::HashSet,
2024-11-05 20:44:24 +01:00
sync::{Arc, Mutex},
2024-07-17 19:38:01 +02:00
};
type MultithreadedGraph = Arc<Mutex<DownloadedGraph>>;
type MultithreadDownloadJob = (
2024-11-05 20:44:24 +01:00
tokio::sync::mpsc::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-11-05 20:44:24 +01:00
pub async fn download_graph(
2024-07-17 19:38:01 +02:00
&self,
graph: &DependencyGraph,
refreshed_sources: &mut HashSet<PackageSources>,
2024-11-05 20:44:24 +01:00
reqwest: &reqwest::Client,
2024-09-04 19:48:37 +02:00
prod: bool,
write: bool,
) -> Result<MultithreadDownloadJob, errors::DownloadGraphError> {
2024-11-05 20:44:24 +01:00
let manifest = self.deser_manifest().await?;
let downloaded_graph: MultithreadedGraph = Arc::new(Mutex::new(Default::default()));
2024-07-17 19:38:01 +02:00
2024-11-05 20:44:24 +01:00
let (tx, rx) =
tokio::sync::mpsc::channel(graph.iter().map(|(_, versions)| versions.len()).sum());
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()) {
2024-11-05 20:44:24 +01:00
source.refresh(self).await.map_err(Box::new)?;
2024-07-17 19:38:01 +02:00
}
let container_folder = node.container_folder(
&self
.package_dir()
.join(
manifest
.target
.kind()
.packages_folder(&node.pkg_ref.target_kind()),
)
2024-07-17 19:38:01 +02:00
.join(PACKAGES_CONTAINER_NAME),
name,
2024-07-22 23:16:04 +02:00
version_id.version(),
2024-07-17 19:38:01 +02:00
);
2024-11-05 20:44:24 +01:00
fs::create_dir_all(&container_folder).await?;
2024-07-17 19:38:01 +02:00
let tx = tx.clone();
2024-07-17 19:38:01 +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();
2024-11-05 20:44:24 +01:00
tokio::spawn(async move {
let project = project.clone();
2024-07-24 00:53:34 +02:00
log::debug!("downloading {name}@{version_id}");
2024-11-05 20:44:24 +01:00
let (fs, target) =
match source.download(&node.pkg_ref, &project, &reqwest).await {
Ok(target) => target,
Err(e) => {
tx.send(Err(Box::new(e).into())).await.unwrap();
return;
}
};
2024-07-24 00:53:34 +02:00
log::debug!("downloaded {name}@{version_id}");
2024-09-04 19:48:37 +02:00
if write {
if !prod || node.ty != DependencyType::Dev {
2024-11-05 20:44:24 +01:00
match fs.write_to(container_folder, project.cas_dir(), true).await {
2024-09-04 19:48:37 +02:00
Ok(_) => {}
Err(e) => {
tx.send(Err(errors::DownloadGraphError::WriteFailed(e)))
2024-11-05 20:44:24 +01:00
.await
2024-09-04 19:48:37 +02:00
.unwrap();
return;
}
};
} else {
log::debug!("skipping writing {name}@{version_id} to disk, dev dependency in prod mode");
2024-07-28 18:19:54 +02:00
}
2024-09-04 19:48:37 +02:00
}
2024-07-28 18:19:54 +02:00
2024-11-05 20:44:24 +01:00
{
let mut downloaded_graph = downloaded_graph.lock().unwrap();
downloaded_graph
.entry(name)
.or_default()
.insert(version_id, DownloadedDependencyGraphNode { node, target });
}
2024-11-05 20:44:24 +01:00
tx.send(Ok(())).await.unwrap();
});
2024-07-17 19:38:01 +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-08 17:59:59 +02:00
/// An 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-08 17:59:59 +02:00
/// An 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-11-01 20:57:32 +01:00
#[error("error interacting with the filesystem")]
2024-07-17 19:38:01 +02:00
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")]
2024-08-11 16:16:25 +02:00
DownloadFailed(#[from] Box<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
}
}