From be8ad0c50773199f90afbc734fee8bc00ed70248 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 22 Aug 2024 22:04:57 -0400 Subject: [PATCH] Restore `cache` suffix on Windows cache path (#6482) ## Summary We accidentally changed the Windows cache directory from `C:\Users\User\AppData\Local\uv\cache` to `C:\Users\User\AppData\Local\uv` in v0.3.0. We're considering this a bug, since it does _not_ match the documentation, and prior to v0.3.0, we always used the former. This PR migrates back to the previous location. It should be seamless for users, as we move the cache items to the new location on startup. Closes https://github.com/astral-sh/uv/issues/6417. --- crates/uv-cache/src/cli.rs | 77 +++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/crates/uv-cache/src/cli.rs b/crates/uv-cache/src/cli.rs index 78d278fad..303b9cd8c 100644 --- a/crates/uv-cache/src/cli.rs +++ b/crates/uv-cache/src/cli.rs @@ -1,10 +1,11 @@ use std::io; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use crate::Cache; use clap::Parser; use directories::ProjectDirs; use etcetera::BaseStrategy; +use tracing::{debug, warn}; #[derive(Parser, Debug, Clone)] #[command(next_help_heading = "Cache options")] @@ -55,7 +56,26 @@ impl Cache { .ok() .map(|dirs| dirs.cache_dir().join("uv")) { - Ok(Self::from_path(cache_dir)) + if cfg!(windows) { + // On Windows, we append `cache` to the LocalAppData directory, i.e., prefer + // `C:\Users\User\AppData\Local\uv\cache` over `C:\Users\User\AppData\Local\uv`. + // + // Unfortunately, v0.3.0 and v0.3.1 used the latter, so we need to migrate the cache + // for those users. + let destination = cache_dir.join("cache"); + let source = cache_dir; + if let Err(err) = migrate_windows_cache(&source, &destination) { + warn!( + "Failed to migrate cache from `{}` to `{}`: {err}", + source.display(), + destination.display() + ); + } + + Ok(Self::from_path(destination)) + } else { + Ok(Self::from_path(cache_dir)) + } } else { Ok(Self::from_path(".uv_cache")) } @@ -69,3 +89,56 @@ impl TryFrom for Cache { Cache::from_settings(value.no_cache, value.cache_dir) } } + +/// Migrate the Windows cache from `C:\Users\User\AppData\Local\uv` to `C:\Users\User\AppData\Local\uv\cache`. +fn migrate_windows_cache(source: &Path, destination: &Path) -> Result<(), io::Error> { + // The list of expected cache buckets in v0.3.0. + for directory in [ + "built-wheels-v3", + "flat-index-v0", + "git-v0", + "interpreter-v2", + "simple-v12", + "wheels-v1", + "archive-v0", + "builds-v0", + "environments-v1", + ] { + let source = source.join(directory); + let destination = destination.join(directory); + + // Migrate the cache bucket. + if source.exists() { + debug!( + "Migrating cache bucket from {} to {}", + source.display(), + destination.display() + ); + if let Some(parent) = destination.parent() { + fs_err::create_dir_all(parent)?; + } + fs_err::rename(&source, &destination)?; + } + } + + // The list of expected cache files in v0.3.0. + for file in [".gitignore", "CACHEDIR.TAG"] { + let source = source.join(file); + let destination = destination.join(file); + + // Migrate the cache file. + if source.exists() { + debug!( + "Migrating cache file from {} to {}", + source.display(), + destination.display() + ); + if let Some(parent) = destination.parent() { + fs_err::create_dir_all(parent)?; + } + fs_err::rename(&source, &destination)?; + } + } + + Ok(()) +}