mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00
ci: Make Windows tests ~27% faster by putting temp folder in dev drive (#6680)
## Summary This PR makes `cargo test | windows` faster in CI. ### Before  ### After  ## Also This PR disables the `brotli` feature of `async-compression` since it's not strictly needed, but this has little to do with the improvements (it's still less code to build). This PR introduces additional code in uv tool uninstall to ignore errors (that only seem to happen on ReFS, ie. on Dev Drives) akin to "the thing we're trying to delete cannot be deleted because it's already being deleted". If `raw_os_error` was stable we could do u32 matching instead of that `.to_string().contains()` abomination.
This commit is contained in:
parent
ffb0c304d1
commit
2c5cc62106
5 changed files with 54 additions and 41 deletions
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
@ -285,6 +285,7 @@ jobs:
|
|||
env:
|
||||
CARGO_HOME: ${{ env.DEV_DRIVE }}/.cargo
|
||||
RUSTUP_HOME: ${{ env.DEV_DRIVE }}/.rustup
|
||||
UV_INTERNAL__TEST_DIR: ${{ env.DEV_DRIVE }}/tmp-uv
|
||||
run: |
|
||||
cargo nextest run --no-default-features --features python,pypi --workspace --status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow
|
||||
|
||||
|
|
37
Cargo.lock
generated
37
Cargo.lock
generated
|
@ -43,21 +43,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc-no-stdlib"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
|
||||
|
||||
[[package]]
|
||||
name = "alloc-stdlib"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
|
@ -211,7 +196,6 @@ version = "0.4.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"bzip2",
|
||||
"flate2",
|
||||
"futures-core",
|
||||
|
@ -461,27 +445,6 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "510a90332002c1af3317ef6b712f0dab697f30bbe809b86965eac2923c0bca8e"
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.10.0"
|
||||
|
|
|
@ -119,7 +119,7 @@ quote = { version = "1.0.36" }
|
|||
rayon = { version = "1.8.0" }
|
||||
reflink-copy = { version = "0.1.15" }
|
||||
regex = { version = "1.10.2" }
|
||||
reqwest = { version = "0.12.3", default-features = false, features = ["json", "gzip", "brotli", "stream", "rustls-tls", "rustls-tls-native-roots"] }
|
||||
reqwest = { version = "0.12.3", default-features = false, features = ["json", "gzip", "stream", "rustls-tls", "rustls-tls-native-roots"] }
|
||||
reqwest-middleware = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "5e3eaf254b5bd481c75d2710eed055f95b756913" }
|
||||
reqwest-retry = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "5e3eaf254b5bd481c75d2710eed055f95b756913" }
|
||||
rkyv = { version = "0.7.43", features = ["strict", "validation"] }
|
||||
|
|
|
@ -135,7 +135,14 @@ impl Cache {
|
|||
|
||||
/// Create a temporary cache directory.
|
||||
pub fn temp() -> Result<Self, io::Error> {
|
||||
let temp_dir = tempfile::tempdir()?;
|
||||
let temp_dir =
|
||||
if let Ok(test_dir) = std::env::var("UV_INTERNAL__TEST_DIR").map(PathBuf::from) {
|
||||
let uv_cache_dir = test_dir.join("uv-cache");
|
||||
let _ = fs_err::create_dir_all(&uv_cache_dir);
|
||||
tempfile::tempdir_in(uv_cache_dir)?
|
||||
} else {
|
||||
tempfile::tempdir()?
|
||||
};
|
||||
Ok(Self {
|
||||
root: temp_dir.path().to_path_buf(),
|
||||
refresh: Refresh::None(Timestamp::now()),
|
||||
|
|
|
@ -32,10 +32,14 @@ pub(crate) async fn uninstall(name: Option<PackageName>, printer: Printer) -> Re
|
|||
|
||||
// Clean up any empty directories.
|
||||
if uv_fs::directories(installed_tools.root()).all(|path| uv_fs::is_temporary(&path)) {
|
||||
fs_err::tokio::remove_dir_all(&installed_tools.root()).await?;
|
||||
fs_err::tokio::remove_dir_all(&installed_tools.root())
|
||||
.await
|
||||
.ignore_currently_being_deleted()?;
|
||||
if let Some(top_level) = installed_tools.root().parent() {
|
||||
if uv_fs::directories(top_level).all(|path| uv_fs::is_temporary(&path)) {
|
||||
fs_err::tokio::remove_dir_all(top_level).await?;
|
||||
fs_err::tokio::remove_dir_all(top_level)
|
||||
.await
|
||||
.ignore_currently_being_deleted()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +47,44 @@ pub(crate) async fn uninstall(name: Option<PackageName>, printer: Printer) -> Re
|
|||
Ok(ExitStatus::Success)
|
||||
}
|
||||
|
||||
trait IoErrorExt: std::error::Error + 'static {
|
||||
#[inline]
|
||||
fn is_in_process_of_being_deleted(&self) -> bool {
|
||||
if cfg!(target_os = "windows") {
|
||||
use std::error::Error;
|
||||
let mut e: &dyn Error = &self;
|
||||
loop {
|
||||
if e.to_string().contains("The file cannot be opened because it is in the process of being deleted. (os error 303)") {
|
||||
return true;
|
||||
}
|
||||
e = match e.source() {
|
||||
Some(e) => e,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl IoErrorExt for std::io::Error {}
|
||||
|
||||
/// An extension trait to suppress "cannot open file because it's currently being deleted"
|
||||
trait IgnoreCurrentlyBeingDeleted {
|
||||
fn ignore_currently_being_deleted(self) -> Self;
|
||||
}
|
||||
|
||||
impl IgnoreCurrentlyBeingDeleted for Result<(), std::io::Error> {
|
||||
fn ignore_currently_being_deleted(self) -> Self {
|
||||
match self {
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) if err.is_in_process_of_being_deleted() => Ok(()),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform the uninstallation.
|
||||
async fn do_uninstall(
|
||||
installed_tools: &InstalledTools,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue