mirror of https://github.com/astral-sh/uv
141 lines
4.7 KiB
Rust
141 lines
4.7 KiB
Rust
use std::io;
|
|
use std::path::{Path, PathBuf};
|
|
use uv_static::EnvVars;
|
|
|
|
use crate::Cache;
|
|
use clap::Parser;
|
|
use tracing::{debug, warn};
|
|
|
|
#[derive(Parser, Debug, Clone)]
|
|
#[command(next_help_heading = "Cache options")]
|
|
pub struct CacheArgs {
|
|
/// Avoid reading from or writing to the cache, instead using a temporary directory for the
|
|
/// duration of the operation.
|
|
#[arg(
|
|
global = true,
|
|
long,
|
|
short,
|
|
alias = "no-cache-dir",
|
|
env = EnvVars::UV_NO_CACHE,
|
|
value_parser = clap::builder::BoolishValueParser::new(),
|
|
)]
|
|
pub no_cache: bool,
|
|
|
|
/// Path to the cache directory.
|
|
///
|
|
/// Defaults to `$XDG_CACHE_HOME/uv` or `$HOME/.cache/uv` on macOS and Linux, and
|
|
/// `%LOCALAPPDATA%\uv\cache` on Windows.
|
|
///
|
|
/// To view the location of the cache directory, run `uv cache dir`.
|
|
#[arg(global = true, long, env = EnvVars::UV_CACHE_DIR)]
|
|
pub cache_dir: Option<PathBuf>,
|
|
}
|
|
|
|
impl Cache {
|
|
/// Prefer, in order:
|
|
///
|
|
/// 1. A temporary cache directory, if the user requested `--no-cache`.
|
|
/// 2. The specific cache directory specified by the user via `--cache-dir` or `UV_CACHE_DIR`.
|
|
/// 3. The system-appropriate cache directory.
|
|
/// 4. A `.uv_cache` directory in the current working directory.
|
|
///
|
|
/// Returns an absolute cache dir.
|
|
pub fn from_settings(no_cache: bool, cache_dir: Option<PathBuf>) -> Result<Self, io::Error> {
|
|
if no_cache {
|
|
Self::temp()
|
|
} else if let Some(cache_dir) = cache_dir {
|
|
Ok(Self::from_path(cache_dir))
|
|
} else if let Some(cache_dir) = uv_dirs::legacy_user_cache_dir().filter(|dir| dir.exists())
|
|
{
|
|
// If the user has an existing directory at (e.g.) `/Users/user/Library/Caches/uv`,
|
|
// respect it for backwards compatibility. Otherwise, prefer the XDG strategy, even on
|
|
// macOS.
|
|
Ok(Self::from_path(cache_dir))
|
|
} else if let Some(cache_dir) = uv_dirs::user_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"))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<CacheArgs> for Cache {
|
|
type Error = io::Error;
|
|
|
|
fn try_from(value: CacheArgs) -> Result<Self, Self::Error> {
|
|
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(())
|
|
}
|