2025-08-07 15:31:48 +01:00
|
|
|
use std::ops::Deref;
|
|
|
|
|
|
|
|
|
|
use anyhow::{Result, bail};
|
|
|
|
|
use clap::Parser;
|
|
|
|
|
use futures::TryStreamExt;
|
|
|
|
|
use tokio_util::compat::FuturesAsyncReadCompatExt;
|
|
|
|
|
|
|
|
|
|
use uv_cache::{Cache, CacheArgs};
|
2025-08-29 20:30:51 +02:00
|
|
|
use uv_client::{BaseClientBuilder, RegistryClientBuilder};
|
2025-08-07 15:31:48 +01:00
|
|
|
use uv_pep508::VerbatimUrl;
|
|
|
|
|
use uv_pypi_types::ParsedUrl;
|
2025-10-09 21:28:30 +04:00
|
|
|
use uv_settings::EnvironmentOptions;
|
2025-08-07 15:31:48 +01:00
|
|
|
|
|
|
|
|
#[derive(Parser)]
|
|
|
|
|
pub(crate) struct ValidateZipArgs {
|
|
|
|
|
url: VerbatimUrl,
|
|
|
|
|
#[command(flatten)]
|
|
|
|
|
cache_args: CacheArgs,
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-09 21:28:30 +04:00
|
|
|
pub(crate) async fn validate_zip(
|
|
|
|
|
args: ValidateZipArgs,
|
|
|
|
|
environment: EnvironmentOptions,
|
|
|
|
|
) -> Result<()> {
|
2025-08-07 15:31:48 +01:00
|
|
|
let cache = Cache::try_from(args.cache_args)?.init()?;
|
2025-10-09 21:28:30 +04:00
|
|
|
let client = RegistryClientBuilder::new(
|
|
|
|
|
BaseClientBuilder::default().timeout(environment.http_timeout),
|
|
|
|
|
cache,
|
|
|
|
|
)
|
|
|
|
|
.build();
|
2025-08-07 15:31:48 +01:00
|
|
|
|
|
|
|
|
let ParsedUrl::Archive(archive) = ParsedUrl::try_from(args.url.to_url())? else {
|
|
|
|
|
bail!("Only archive URLs are supported");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let response = client
|
|
|
|
|
.uncached_client(&archive.url)
|
|
|
|
|
.get(archive.url.deref().clone())
|
|
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
let reader = response
|
|
|
|
|
.bytes_stream()
|
|
|
|
|
.map_err(std::io::Error::other)
|
|
|
|
|
.into_async_read();
|
|
|
|
|
|
|
|
|
|
let target = tempfile::TempDir::new()?;
|
|
|
|
|
|
|
|
|
|
uv_extract::stream::unzip(reader.compat(), target.path()).await?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|