diff --git a/Cargo.lock b/Cargo.lock index 066981fdff1d..9027df1955f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -911,27 +911,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "directories" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - [[package]] name = "doc-comment" version = "0.3.3" @@ -2142,12 +2121,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - [[package]] name = "overload" version = "0.1.1" @@ -2643,17 +2616,6 @@ dependencies = [ "bitflags 2.6.0", ] -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - [[package]] name = "reflink-copy" version = "0.1.19" @@ -4304,7 +4266,6 @@ name = "uv-cache" version = "0.0.1" dependencies = [ "clap", - "directories", "etcetera", "fs-err", "nanoid", @@ -5137,7 +5098,7 @@ name = "uv-settings" version = "0.0.1" dependencies = [ "clap", - "dirs-sys", + "etcetera", "fs-err", "schemars", "serde", @@ -5179,7 +5140,6 @@ dependencies = [ name = "uv-state" version = "0.0.1" dependencies = [ - "directories", "etcetera", "fs-err", "tempfile", @@ -5193,7 +5153,7 @@ version = "0.0.1" name = "uv-tool" version = "0.0.1" dependencies = [ - "dirs-sys", + "etcetera", "fs-err", "pathdiff", "serde", @@ -5508,7 +5468,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 60c8a33b523a..3a6e9e7640e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,8 +90,6 @@ csv = { version = "1.3.0" } ctrlc = { version = "3.4.5" } dashmap = { version = "6.1.0" } data-encoding = { version = "2.6.0" } -directories = { version = "5.0.1" } -dirs-sys = { version = "0.4.1" } dunce = { version = "1.0.5" } either = { version = "1.13.0" } encoding_rs_io = { version = "0.1.7" } diff --git a/crates/uv-cache/Cargo.toml b/crates/uv-cache/Cargo.toml index 8f33d81f0370..c7f182212bb8 100644 --- a/crates/uv-cache/Cargo.toml +++ b/crates/uv-cache/Cargo.toml @@ -26,7 +26,6 @@ uv-pypi-types = { workspace = true } uv-static = { workspace = true } clap = { workspace = true, features = ["derive", "env"], optional = true } -directories = { workspace = true } etcetera = { workspace = true } fs-err = { workspace = true, features = ["tokio"] } nanoid = { workspace = true } diff --git a/crates/uv-cache/src/cli.rs b/crates/uv-cache/src/cli.rs index 781b740175cc..92903caaead5 100644 --- a/crates/uv-cache/src/cli.rs +++ b/crates/uv-cache/src/cli.rs @@ -4,7 +4,6 @@ use uv_static::EnvVars; use crate::Cache; use clap::Parser; -use directories::ProjectDirs; use etcetera::BaseStrategy; use tracing::{debug, warn}; @@ -31,6 +30,19 @@ pub struct CacheArgs { pub cache_dir: Option, } +fn legacy_cache_dir() -> Option { + etcetera::base_strategy::choose_native_strategy() + .ok() + .map(|dirs| dirs.cache_dir().join("uv")) + .map(|dir| { + if cfg!(windows) { + dir.join("cache") + } else { + dir + } + }) +} + impl Cache { /// Prefer, in order: /// @@ -45,10 +57,7 @@ impl Cache { Self::temp() } else if let Some(cache_dir) = cache_dir { Ok(Self::from_path(cache_dir)) - } else if let Some(cache_dir) = ProjectDirs::from("", "", "uv") - .map(|dirs| dirs.cache_dir().to_path_buf()) - .filter(|dir| dir.exists()) - { + } else if let Some(cache_dir) = legacy_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. diff --git a/crates/uv-settings/Cargo.toml b/crates/uv-settings/Cargo.toml index 683b9aae3c8c..feda8a66ee3f 100644 --- a/crates/uv-settings/Cargo.toml +++ b/crates/uv-settings/Cargo.toml @@ -32,7 +32,7 @@ uv-static = { workspace = true } uv-warnings = { workspace = true } clap = { workspace = true } -dirs-sys = { workspace = true } +etcetera = { workspace = true } fs-err = { workspace = true } schemars = { workspace = true, optional = true } serde = { workspace = true } diff --git a/crates/uv-settings/src/lib.rs b/crates/uv-settings/src/lib.rs index 2ee366bf92f0..a541eacc0a24 100644 --- a/crates/uv-settings/src/lib.rs +++ b/crates/uv-settings/src/lib.rs @@ -1,11 +1,10 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; +use etcetera::BaseStrategy; use tracing::debug; use uv_fs::Simplified; -#[cfg(not(windows))] -use uv_static::EnvVars; use uv_warnings::warn_user; pub use crate::combine::*; @@ -168,23 +167,12 @@ impl From for FilesystemOptions { /// Returns the path to the user configuration directory. /// -/// This is similar to the `config_dir()` returned by the `dirs` crate, but it uses the -/// `XDG_CONFIG_HOME` environment variable on both Linux _and_ macOS, rather than the -/// `Application Support` directory on macOS. +/// On Windows, use, e.g., C:\Users\Alice\AppData\Roaming +/// On Linux and macOS, use `XDG_CONFIG_HOME` or $HOME/.config, e.g., /home/alice/.config. fn config_dir() -> Option { - // On Windows, use, e.g., C:\Users\Alice\AppData\Roaming - #[cfg(windows)] - { - dirs_sys::known_folder_roaming_app_data() - } - - // On Linux and macOS, use, e.g., /home/alice/.config. - #[cfg(not(windows))] - { - std::env::var_os(EnvVars::XDG_CONFIG_HOME) - .and_then(dirs_sys::is_absolute_path) - .or_else(|| dirs_sys::home_dir().map(|path| path.join(".config"))) - } + etcetera::choose_base_strategy() + .map(|dirs| dirs.config_dir()) + .ok() } /// Load [`Options`] from a `uv.toml` file. diff --git a/crates/uv-state/Cargo.toml b/crates/uv-state/Cargo.toml index f90413be4526..841f3dc3da42 100644 --- a/crates/uv-state/Cargo.toml +++ b/crates/uv-state/Cargo.toml @@ -16,7 +16,6 @@ doctest = false workspace = true [dependencies] -directories = { workspace = true } etcetera = { workspace = true } tempfile = { workspace = true } fs-err = { workspace = true } diff --git a/crates/uv-state/src/lib.rs b/crates/uv-state/src/lib.rs index 9d1f65485e70..b6c4572d1d6a 100644 --- a/crates/uv-state/src/lib.rs +++ b/crates/uv-state/src/lib.rs @@ -4,7 +4,6 @@ use std::{ sync::Arc, }; -use directories::ProjectDirs; use etcetera::BaseStrategy; use fs_err as fs; use tempfile::{tempdir, TempDir}; @@ -85,10 +84,7 @@ impl StateStore { pub fn from_settings(state_dir: Option) -> Result { if let Some(state_dir) = state_dir { StateStore::from_path(state_dir) - } else if let Some(data_dir) = ProjectDirs::from("", "", "uv") - .map(|dirs| dirs.data_dir().to_path_buf()) - .filter(|dir| dir.exists()) - { + } else if let Some(data_dir) = legacy_data_dir().filter(|dir| dir.exists()) { // If the user has an existing directory at (e.g.) `/Users/user/Library/Application Support/uv`, // respect it for backwards compatibility. Otherwise, prefer the XDG strategy, even on // macOS. @@ -104,6 +100,13 @@ impl StateStore { } } +fn legacy_data_dir() -> Option { + etcetera::base_strategy::choose_native_strategy() + .ok() + .map(|dirs| dirs.data_dir().join("uv")) + .map(|dir| if cfg!(windows) { dir.join("data") } else { dir }) +} + /// The different kinds of data in the state store are stored in different bucket, which in our case /// are subdirectories of the state store root. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] diff --git a/crates/uv-tool/Cargo.toml b/crates/uv-tool/Cargo.toml index f74b29fc248b..98121758deeb 100644 --- a/crates/uv-tool/Cargo.toml +++ b/crates/uv-tool/Cargo.toml @@ -29,7 +29,7 @@ uv-state = { workspace = true } uv-static = { workspace = true } uv-virtualenv = { workspace = true } -dirs-sys = { workspace = true } +etcetera = { workspace = true } fs-err = { workspace = true } pathdiff = { workspace = true } serde = { workspace = true } diff --git a/crates/uv-tool/src/lib.rs b/crates/uv-tool/src/lib.rs index 20b3e559f195..caa95fc13fbf 100644 --- a/crates/uv-tool/src/lib.rs +++ b/crates/uv-tool/src/lib.rs @@ -1,6 +1,6 @@ use core::fmt; - use fs_err as fs; +use std::ffi::OsString; use uv_pep440::Version; use uv_pep508::{InvalidNameError, PackageName}; @@ -354,6 +354,15 @@ impl fmt::Display for InstalledTool { } } +fn is_absolute_path(path: OsString) -> Option { + let path = PathBuf::from(path); + if path.is_absolute() { + Some(path) + } else { + None + } +} + /// Find a directory to place executables in. /// /// This follows, in order: @@ -368,20 +377,16 @@ impl fmt::Display for InstalledTool { /// Errors if a directory cannot be found. pub fn find_executable_directory() -> Result { std::env::var_os(EnvVars::UV_TOOL_BIN_DIR) - .and_then(dirs_sys::is_absolute_path) - .or_else(|| std::env::var_os(EnvVars::XDG_BIN_HOME).and_then(dirs_sys::is_absolute_path)) + .and_then(is_absolute_path) + .or_else(|| std::env::var_os(EnvVars::XDG_BIN_HOME).and_then(is_absolute_path)) .or_else(|| { std::env::var_os(EnvVars::XDG_DATA_HOME) - .and_then(dirs_sys::is_absolute_path) + .and_then(is_absolute_path) .map(|path| path.join("../bin")) }) .or_else(|| { - // See https://github.com/dirs-dev/dirs-rs/blob/50b50f31f3363b7656e5e63b3fa1060217cbc844/src/win.rs#L5C58-L5C78 - #[cfg(windows)] - let home_dir = dirs_sys::known_folder_profile(); - #[cfg(not(windows))] - let home_dir = dirs_sys::home_dir(); - home_dir.map(|path| path.join(".local").join("bin")) + let home_dir = etcetera::home_dir(); + home_dir.map(|path| path.join(".local").join("bin")).ok() }) .ok_or(Error::NoExecutableDirectory) }