diff --git a/Cargo.lock b/Cargo.lock index c155e144f3..1fe9682f98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -364,7 +364,7 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06575e6a9673580f52661c92107baabffbf41e2141373441cbcdc47cb733003c" dependencies = [ - "bzip2 0.5.2", + "bzip2", "flate2", "futures-core", "futures-io", @@ -650,15 +650,6 @@ dependencies = [ "bzip2-sys", ] -[[package]] -name = "bzip2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" -dependencies = [ - "libbz2-rs-sys", -] - [[package]] name = "bzip2-sys" version = "0.1.13+1.0.8" @@ -2572,12 +2563,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" -[[package]] -name = "libbz2-rs-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" - [[package]] name = "libc" version = "0.2.183" @@ -2644,15 +2629,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" -[[package]] -name = "lzma-rust2" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47bb1e988e6fb779cf720ad431242d3f03167c1b3f2b1aae7f1a94b2495b36ae" -dependencies = [ - "sha2", -] - [[package]] name = "lzma-sys" version = "0.1.20" @@ -5527,12 +5503,6 @@ dependencies = [ "core_maths", ] -[[package]] -name = "typed-path" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" - [[package]] name = "typeid" version = "1.0.3" @@ -5864,7 +5834,6 @@ dependencies = [ "walkdir", "which", "wiremock", - "zip", ] [[package]] @@ -6050,7 +6019,6 @@ dependencies = [ "uv-version", "uv-warnings", "walkdir", - "zip", ] [[package]] @@ -8455,23 +8423,6 @@ dependencies = [ "syn", ] -[[package]] -name = "zip" -version = "8.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e499faf5c6b97a0d086f4a8733de6d47aee2252b8127962439d8d4311a73f72" -dependencies = [ - "bzip2 0.6.1", - "crc32fast", - "flate2", - "indexmap", - "lzma-rust2", - "memchr", - "typed-path", - "zopfli", - "zstd", -] - [[package]] name = "zlib-rs" version = "0.6.3" @@ -8484,18 +8435,6 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" -[[package]] -name = "zopfli" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] - [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index 689050149a..3dbcfb3b21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -308,13 +308,6 @@ wiremock = { version = "0.6.4" } wmi = { version = "0.18.3", default-features = false } xz2 = { version = "0.1.7", features = ["static"] } zeroize = { version = "1.8.1" } -zip = { version = "8.1.0", default-features = false, features = [ - "deflate", - "zstd", - "bzip2", - "lzma", - "xz", -] } # dev-dependencies assert_cmd = { version = "2.0.16" } diff --git a/crates/uv-build-backend/Cargo.toml b/crates/uv-build-backend/Cargo.toml index f596c69c46..da898e5971 100644 --- a/crates/uv-build-backend/Cargo.toml +++ b/crates/uv-build-backend/Cargo.toml @@ -66,4 +66,3 @@ uv-preview = { workspace = true, features = ["testing"] } indoc = { workspace = true } insta = { workspace = true } regex = { workspace = true } -zip = { workspace = true } diff --git a/crates/uv-build-backend/src/lib.rs b/crates/uv-build-backend/src/lib.rs index 02991f9e53..47a7c34bfa 100644 --- a/crates/uv-build-backend/src/lib.rs +++ b/crates/uv-build-backend/src/lib.rs @@ -439,14 +439,16 @@ pub(crate) fn error_on_venv(file_name: &OsStr, path: &Path) -> Result<(), Error> #[cfg(test)] mod tests { use super::*; + use async_zip::base::read::mem::ZipFileReader; use flate2::bufread::GzDecoder; use fs_err::File; + use futures_lite::future::block_on; use indoc::indoc; use insta::assert_snapshot; use itertools::Itertools; use regex::Regex; use sha2::Digest; - use std::io::{BufReader, Read}; + use std::io::BufReader; use std::iter; use tempfile::TempDir; use uv_distribution_filename::{SourceDistFilename, WheelFilename}; @@ -582,15 +584,57 @@ mod tests { } fn wheel_contents(direct_output_dir: &Path) -> Vec { - let wheel = zip::ZipArchive::new(File::open(direct_output_dir).unwrap()).unwrap(); + let wheel = block_on(read_wheel(direct_output_dir)); let mut wheel_contents: Vec<_> = wheel - .file_names() - .map(|path| path.replace('\\', "/")) + .file() + .entries() + .iter() + .map(|entry| { + entry + .filename() + .as_str() + .expect("wheel filenames should be UTF-8") + .replace('\\', "/") + }) .collect(); wheel_contents.sort_unstable(); wheel_contents } + fn wheel_entry(wheel_path: &Path, filename: &str) -> String { + block_on(async { + let wheel = read_wheel(wheel_path).await; + let index = wheel + .file() + .entries() + .iter() + .position(|entry| { + entry + .filename() + .as_str() + .is_ok_and(|entry_filename| entry_filename == filename) + }) + .expect("wheel entry should exist"); + + let mut reader = wheel + .reader_with_entry(index) + .await + .expect("wheel entry should be readable"); + let mut contents = String::new(); + reader + .read_to_string_checked(&mut contents) + .await + .expect("wheel entry should be valid UTF-8"); + contents + }) + } + + async fn read_wheel(wheel_path: &Path) -> ZipFileReader { + ZipFileReader::new(fs_err::read(wheel_path).expect("wheel should be readable")) + .await + .expect("wheel should be valid") + } + fn format_file_list(file_list: FileList, src: &Path) -> String { file_list .into_iter() @@ -779,13 +823,7 @@ mod tests { built_by_uv-0.1.0.dist-info/METADATA (generated) "); - let mut wheel = zip::ZipArchive::new(File::open(wheel_path).unwrap()).unwrap(); - let mut record = String::new(); - wheel - .by_name("built_by_uv-0.1.0.dist-info/RECORD") - .unwrap() - .read_to_string(&mut record) - .unwrap(); + let record = wheel_entry(&wheel_path, "built_by_uv-0.1.0.dist-info/RECORD"); assert_snapshot!(record, @" built_by_uv/__init__.py,sha256=AJ7XpTNWxYktP97ydb81UpnNqoebH7K4sHRakAMQKG4,44 built_by_uv/arithmetic/__init__.py,sha256=x2agwFbJAafc9Z6TdJ0K6b6bLMApQdvRSQjP4iy7IEI,67 @@ -860,14 +898,7 @@ mod tests { let wheel = output_dir .path() .join("pep_pep639_license-1.0.0-py3-none-any.whl"); - let mut wheel = zip::ZipArchive::new(File::open(wheel).unwrap()).unwrap(); - - let mut metadata = String::new(); - wheel - .by_name("pep_pep639_license-1.0.0.dist-info/METADATA") - .unwrap() - .read_to_string(&mut metadata) - .unwrap(); + let metadata = wheel_entry(&wheel, "pep_pep639_license-1.0.0.dist-info/METADATA"); assert_snapshot!(metadata, @" Metadata-Version: 2.3 @@ -934,14 +965,7 @@ mod tests { let wheel = output_dir .path() .join("two_step_build-1.0.0-py3-none-any.whl"); - let mut wheel = zip::ZipArchive::new(File::open(wheel).unwrap()).unwrap(); - - let mut metadata_wheel = String::new(); - wheel - .by_name("two_step_build-1.0.0.dist-info/METADATA") - .unwrap() - .read_to_string(&mut metadata_wheel) - .unwrap(); + let metadata_wheel = wheel_entry(&wheel, "two_step_build-1.0.0.dist-info/METADATA"); assert_eq!(metadata_prepared, metadata_wheel); diff --git a/crates/uv/Cargo.toml b/crates/uv/Cargo.toml index 0040659ede..b51ffd6866 100644 --- a/crates/uv/Cargo.toml +++ b/crates/uv/Cargo.toml @@ -151,7 +151,6 @@ tempfile = { workspace = true } tokio-stream = { workspace = true } tokio-util = { workspace = true } wiremock = { workspace = true } -zip = { workspace = true } [target.'cfg(unix)'.dependencies] nix = { workspace = true } diff --git a/crates/uv/tests/it/build.rs b/crates/uv/tests/it/build.rs index 48c5d0d3cb..ceab878114 100644 --- a/crates/uv/tests/it/build.rs +++ b/crates/uv/tests/it/build.rs @@ -1,11 +1,13 @@ use anyhow::Result; use assert_cmd::assert::OutputAssertExt; use assert_fs::prelude::*; -use fs_err::File; +use async_zip::base::read::mem::ZipFileReader; +use futures::executor::block_on; use indoc::{formatdoc, indoc}; use insta::assert_snapshot; use predicates::prelude::predicate; use std::env::current_dir; +use std::path::Path; use url::Url; use uv_static::EnvVars; use uv_test::{DEFAULT_PYTHON_VERSION, apply_filters, uv_snapshot}; @@ -13,7 +15,20 @@ use wiremock::{ Mock, MockServer, ResponseTemplate, matchers::{method, path as url_path}, }; -use zip::ZipArchive; + +fn zip_file_names(path: &Path) -> Result> { + block_on(async { + let wheel = ZipFileReader::new(fs_err::read(path)?).await?; + let mut files: Vec<_> = wheel + .file() + .entries() + .iter() + .map(|entry| Ok(entry.filename().as_str()?.to_string())) + .collect::>()?; + files.sort(); + Ok(files) + }) +} #[test] fn build_basic() -> Result<()> { @@ -1836,12 +1851,7 @@ fn build_git_boundary_in_dist_build() -> Result<()> { "); // Check that the source file is included - let reader = File::open(project.join("dist/demo-0.1.0-py3-none-any.whl"))?; - let mut files: Vec<_> = ZipArchive::new(reader)? - .file_names() - .map(ToString::to_string) - .collect(); - files.sort(); + let files = zip_file_names(&project.join("dist/demo-0.1.0-py3-none-any.whl"))?; assert_snapshot!(files.join("\n"), @" demo-0.1.0.dist-info/METADATA demo-0.1.0.dist-info/RECORD diff --git a/crates/uv/tests/it/lock.rs b/crates/uv/tests/it/lock.rs index 3850490f5c..96d773effb 100644 --- a/crates/uv/tests/it/lock.rs +++ b/crates/uv/tests/it/lock.rs @@ -3,7 +3,6 @@ use assert_cmd::assert::OutputAssertExt; use assert_fs::prelude::*; use indoc::{formatdoc, indoc}; use insta::assert_snapshot; -use std::io::BufReader; use url::Url; use uv_fs::Simplified; @@ -13646,8 +13645,7 @@ fn lock_sources_source_tree() -> Result<()> { // Unzip the file. let file = fs_err::File::open(&*workspace_archive)?; - let mut archive = zip::ZipArchive::new(BufReader::new(file))?; - archive.extract(&context.temp_dir)?; + uv_extract::unzip(file, &context.temp_dir)?; let pyproject_toml = context.temp_dir.child("pyproject.toml"); pyproject_toml.write_str(&formatdoc! { diff --git a/crates/uv/tests/it/pip_install.rs b/crates/uv/tests/it/pip_install.rs index 9ac05a06d8..69784ca76e 100644 --- a/crates/uv/tests/it/pip_install.rs +++ b/crates/uv/tests/it/pip_install.rs @@ -1,4 +1,3 @@ -use std::io; use std::io::Cursor; use std::path::PathBuf; use std::process::Command; @@ -6,9 +5,12 @@ use std::process::Command; use anyhow::{Result, anyhow}; use assert_cmd::prelude::*; use assert_fs::prelude::*; +use async_zip::base::write::ZipFileWriter; +use async_zip::{Compression, ZipEntryBuilder}; use flate2::write::GzEncoder; use fs_err as fs; use fs_err::File; +use futures::executor::block_on; use indoc::{formatdoc, indoc}; use insta::assert_snapshot; use predicates::prelude::predicate; @@ -18,8 +20,6 @@ use wiremock::{ Mock, MockServer, ResponseTemplate, matchers::{basic_auth, method, path}, }; -use zip::write::SimpleFileOptions; -use zip::{ZipArchive, ZipWriter}; use uv_fs::{PortablePath, Simplified}; use uv_static::EnvVars; @@ -15424,7 +15424,7 @@ fn handle_record_mismatches() -> Result<()> { context.build().arg("--wheel").arg("foo").assert().success(); let built_wheel = context.temp_dir.join("foo/dist/foo-0.1.0-py3-none-any.whl"); let unpacked = context.temp_dir.join("foo-unpacked"); - ZipArchive::new(File::open(built_wheel)?)?.extract(&unpacked)?; + uv_extract::unzip(File::open(&built_wheel)?, &unpacked)?; // Snapshot the current (correct) RECORD. let record = unpacked.join("foo-0.1.0.dist-info/RECORD"); @@ -15451,8 +15451,7 @@ fn handle_record_mismatches() -> Result<()> { // Repack the wheel. let repacked_wheel = context.temp_dir.join("foo-0.1.0-py3-none-any.whl"); - let mut writer = ZipWriter::new(File::create(&repacked_wheel)?); - let options = SimpleFileOptions::default(); + let mut writer = ZipFileWriter::new(Vec::new()); for entry in WalkDir::new(&unpacked) { let entry = entry?; let path = entry.path(); @@ -15461,15 +15460,17 @@ fn handle_record_mismatches() -> Result<()> { continue; } // Zip entries must use forward slashes, even on Windows. - let name = PortablePath::from(name).to_string(); + let mut name = PortablePath::from(name).to_string(); if path.is_dir() { - writer.add_directory(&name, options)?; + name.push('/'); + let entry = ZipEntryBuilder::new(name.into(), Compression::Stored); + block_on(writer.write_entry_whole(entry, &[]))?; } else { - writer.start_file(&name, options)?; - io::copy(&mut File::open(path)?, &mut writer)?; + let entry = ZipEntryBuilder::new(name.into(), Compression::Stored); + block_on(writer.write_entry_whole(entry, &fs_err::read(path)?))?; } } - writer.finish()?; + fs_err::write(&repacked_wheel, block_on(writer.close())?)?; uv_snapshot!(context.filters(), context.pip_install() .arg("--find-links")