Files
uv/crates/puffin-dev/src/resolve_many.rs
T
konsti 9488804024 Add docker builder (#238)
This docker container provides isolation of source distribution builds,
whether [intended to be
helpful](https://pypi.org/project/nvidia-pyindex/) or other more or less
malicious forms of host system modification.

Fixes #194

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2023-11-02 12:03:56 +01:00

101 lines
3.2 KiB
Rust

use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;
use clap::Parser;
use directories::ProjectDirs;
use fs_err as fs;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use indicatif::ProgressStyle;
use tokio::sync::Semaphore;
use tracing::{info, info_span, span, Level, Span};
use tracing_indicatif::span_ext::IndicatifSpanExt;
use pep508_rs::Requirement;
use platform_host::Platform;
use puffin_client::RegistryClientBuilder;
use puffin_dispatch::BuildDispatch;
use puffin_interpreter::Virtualenv;
use puffin_traits::BuildContext;
#[derive(Parser)]
pub(crate) struct ResolveManyArgs {
list: PathBuf,
#[clap(long)]
limit: Option<usize>,
/// Path to the cache directory.
#[arg(global = true, long, env = "PUFFIN_CACHE_DIR")]
cache_dir: Option<PathBuf>,
}
pub(crate) async fn resolve_many(args: ResolveManyArgs) -> anyhow::Result<()> {
let data = fs::read_to_string(&args.list)?;
let lines = data.lines().map(Requirement::from_str);
let requirements: Vec<Requirement> = if let Some(limit) = args.limit {
lines.take(limit).collect::<anyhow::Result<_, _>>()?
} else {
lines.collect::<anyhow::Result<_, _>>()?
};
let project_dirs = ProjectDirs::from("", "", "puffin");
let cache = args
.cache_dir
.as_deref()
.or_else(|| project_dirs.as_ref().map(ProjectDirs::cache_dir));
let platform = Platform::current()?;
let venv = Virtualenv::from_env(platform, cache)?;
let build_dispatch = BuildDispatch::new(
RegistryClientBuilder::default().cache(cache).build(),
cache.map(Path::to_path_buf),
venv.interpreter_info().clone(),
fs::canonicalize(venv.python_executable())?,
);
let build_dispatch_arc = Arc::new(build_dispatch);
let mut tasks = FuturesUnordered::new();
let semaphore = Arc::new(Semaphore::new(50));
let header_span = info_span!("resolve many");
header_span.pb_set_style(&ProgressStyle::default_bar());
header_span.pb_set_length(requirements.len() as u64);
let _header_span_enter = header_span.enter();
for requirement in requirements {
let build_dispatch_arc = build_dispatch_arc.clone();
let semaphore = semaphore.clone();
tasks.push(tokio::spawn(async move {
let span = span!(Level::TRACE, "resolving");
let _enter = span.enter();
let permit = semaphore.clone().acquire_owned().await.unwrap();
let result = build_dispatch_arc.resolve(&[requirement.clone()]).await;
drop(permit);
(requirement.to_string(), result)
}));
}
let mut success = 0usize;
let mut errors = Vec::new();
while let Some(result) = tasks.next().await {
let (package, result) = result.unwrap();
match result {
Ok(resolution) => {
info!("Success: {} ({} package(s))", package, resolution.len());
success += 1;
}
Err(err) => {
info!("Error for {}: {:?}", package, err);
errors.push(package);
}
}
Span::current().pb_inc(1);
}
info!("Errors: {}", errors.join(", "));
info!("Success: {}, Error: {}", success, errors.len());
Ok(())
}