Move source distribution unpacking out of build (#2294)

## Summary

If a user provides a source distribution via a direct path, it can
either be an archive (like a `.tar.gz` or `.zip` file) or a directory.
If the former, we need to extract (e.g., unzip) the contents at some
point. Previously, this extraction was in `uv-build`; this PR lifts it
up to the distribution database.

The first benefit here is that various methods that take the
distribution are now simpler, as they can assume a directory.

The second benefit is that we no longer extract _multiple times_ when
working with a source distribution. (Previously, if we tried to get the
metadata, then fell back and built the wheel, we'd extract the wheel
_twice_.)
This commit is contained in:
Charlie Marsh 2024-03-07 19:40:11 -08:00 committed by GitHub
parent e321a2767d
commit 26f6919465
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 107 additions and 47 deletions

View file

@ -18,7 +18,6 @@ distribution-types = { path = "../distribution-types" }
pep508_rs = { path = "../pep508-rs" }
platform-host = { path = "../platform-host" }
pypi-types = { path = "../pypi-types" }
uv-extract = { path = "../uv-extract" }
uv-fs = { path = "../uv-fs" }
uv-interpreter = { path = "../uv-interpreter" }
uv-traits = { path = "../uv-traits", features = ["serde"] }

View file

@ -62,10 +62,6 @@ static DEFAULT_BACKEND: Lazy<Pep517Backend> = Lazy::new(|| Pep517Backend {
pub enum Error {
#[error(transparent)]
IO(#[from] io::Error),
#[error("Failed to extract archive: {0}")]
Extraction(PathBuf, #[source] uv_extract::Error),
#[error("Unsupported archive format (extension not recognized): {0}")]
UnsupportedArchiveType(String),
#[error("Invalid source distribution: {0}")]
InvalidSourceDist(String),
#[error("Invalid pyproject.toml")]
@ -74,8 +70,6 @@ pub enum Error {
EditableSetupPy,
#[error("Failed to install requirements from {0}")]
RequirementsInstall(&'static str, #[source] anyhow::Error),
#[error("Source distribution not found at: {0}")]
NotFound(PathBuf),
#[error("Failed to create temporary virtualenv")]
Virtualenv(#[from] uv_virtualenv::Error),
#[error("Failed to run {0}")]
@ -365,38 +359,10 @@ impl SourceBuild {
) -> Result<Self, Error> {
let temp_dir = tempdir_in(build_context.cache().root())?;
let metadata = match fs::metadata(source) {
Ok(metadata) => metadata,
Err(err) if err.kind() == io::ErrorKind::NotFound => {
return Err(Error::NotFound(source.to_path_buf()));
}
Err(err) => return Err(err.into()),
};
let source_root = if metadata.is_dir() {
source.to_path_buf()
} else {
debug!("Unpacking for build: {}", source.display());
let extracted = temp_dir.path().join("extracted");
// Unzip the archive into the temporary directory.
let reader = fs_err::tokio::File::open(source).await?;
uv_extract::stream::archive(tokio::io::BufReader::new(reader), source, &extracted)
.await
.map_err(|err| Error::Extraction(extracted.clone(), err))?;
// Extract the top-level directory from the archive.
match uv_extract::strip_component(&extracted) {
Ok(top_level) => top_level,
Err(uv_extract::Error::NonSingularArchive(_)) => extracted,
Err(err) => return Err(Error::Extraction(extracted.clone(), err)),
}
};
let source_tree = if let Some(subdir) = subdirectory {
source_root.join(subdir)
source.join(subdir)
} else {
source_root
source.to_path_buf()
};
let default_backend: Pep517Backend = DEFAULT_BACKEND.clone();