Browse Source

Support XDG convention in MacOS too (#1143)

* feat(macos): Support XDG conventions on macOS too

* store base strategy in FnmConfig

* add changeset

---------

Co-authored-by: Utkarsh Gupta <utkarshgupta137@gmail.com>
remotes/origin/fix-insecure-world-writable-dir
Gal Schlezinger 9 months ago committed by GitHub
parent
commit
f76a0011f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/cold-drinks-camp.md
  2. 70
      Cargo.lock
  3. 2
      Cargo.toml
  4. 3
      src/commands/env.rs
  5. 24
      src/config.rs
  6. 76
      src/directories.rs

5
.changeset/cold-drinks-camp.md

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
---
"fnm": minor
---
use XDG conventions in MacOS directories by default

70
Cargo.lock generated

@ -512,27 +512,6 @@ dependencies = [ @@ -512,27 +512,6 @@ dependencies = [
"subtle",
]
[[package]]
name = "dirs"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
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 = "displaydoc"
version = "0.2.4"
@ -639,6 +618,17 @@ dependencies = [ @@ -639,6 +618,17 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "etcetera"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
dependencies = [
"cfg-if",
"home",
"windows-sys 0.48.0",
]
[[package]]
name = "fastrand"
version = "2.1.0"
@ -677,11 +667,11 @@ dependencies = [ @@ -677,11 +667,11 @@ dependencies = [
"clap_complete",
"colored",
"csv",
"dirs",
"duct",
"embed-resource",
"encoding_rs_io",
"env_logger",
"etcetera",
"http",
"indicatif",
"indoc",
@ -821,6 +811,15 @@ dependencies = [ @@ -821,6 +811,15 @@ dependencies = [
"digest",
]
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "http"
version = "1.1.0"
@ -1039,16 +1038,6 @@ version = "0.2.155" @@ -1039,16 +1038,6 @@ version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.5.0",
"libc",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
@ -1252,12 +1241,6 @@ version = "0.1.5" @@ -1252,12 +1241,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 = "os_pipe"
version = "1.1.5"
@ -1433,17 +1416,6 @@ dependencies = [ @@ -1433,17 +1416,6 @@ dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_users"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "regex"
version = "1.10.4"

2
Cargo.toml

@ -16,7 +16,7 @@ chrono = { version = "0.4.38", features = ["serde", "now"], default-features = f @@ -16,7 +16,7 @@ chrono = { version = "0.4.38", features = ["serde", "now"], default-features = f
tar = "0.4.40"
xz2 = "0.1.7"
node-semver = "2.1.0"
dirs = "5.0.1"
etcetera = "0.8.0"
colored = "2.1.0"
zip = "2.1.0"
tempfile = "3.10.1"

3
src/commands/env.rs

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
use super::command::Command;
use crate::config::FnmConfig;
use crate::directories;
use crate::fs::symlink_dir;
use crate::outln;
use crate::path_ext::PathExt;
@ -36,7 +35,7 @@ fn generate_symlink_path() -> String { @@ -36,7 +35,7 @@ fn generate_symlink_path() -> String {
}
fn make_symlink(config: &FnmConfig) -> Result<std::path::PathBuf, Error> {
let base_dir = directories::multishell_storage().ensure_exists_silently();
let base_dir = config.multishell_storage().ensure_exists_silently();
let mut temp_dir = base_dir.join(generate_symlink_path());
while temp_dir.exists() {

24
src/config.rs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
use crate::arch::Arch;
use crate::directories::Directories;
use crate::log_level::LogLevel;
use crate::path_ext::PathExt;
use crate::version_file_strategy::VersionFileStrategy;
use dirs::{data_dir, home_dir};
use url::Url;
#[derive(clap::Parser, Debug)]
@ -87,6 +87,9 @@ pub struct FnmConfig { @@ -87,6 +87,9 @@ pub struct FnmConfig {
verbatim_doc_comment
)]
resolve_engines: bool,
#[clap(skip)]
directories: Directories,
}
impl Default for FnmConfig {
@ -100,6 +103,7 @@ impl Default for FnmConfig { @@ -100,6 +103,7 @@ impl Default for FnmConfig {
version_file_strategy: VersionFileStrategy::default(),
corepack_enabled: false,
resolve_engines: false,
directories: Directories::default(),
}
}
}
@ -134,19 +138,7 @@ impl FnmConfig { @@ -134,19 +138,7 @@ impl FnmConfig {
return dir;
}
let legacy = home_dir()
.map(|dir| dir.join(".fnm"))
.filter(|dir| dir.exists());
let modern = data_dir().map(|dir| dir.join("fnm"));
if let Some(dir) = legacy {
return dir;
}
modern
.expect("Can't get data directory")
.ensure_exists_silently()
self.directories.default_base_dir()
}
pub fn installations_dir(&self) -> std::path::PathBuf {
@ -165,6 +157,10 @@ impl FnmConfig { @@ -165,6 +157,10 @@ impl FnmConfig {
.ensure_exists_silently()
}
pub fn multishell_storage(&self) -> std::path::PathBuf {
self.directories.multishell_storage()
}
#[cfg(test)]
pub fn with_base_dir(mut self, base_dir: Option<std::path::PathBuf>) -> Self {
self.base_dir = base_dir;

76
src/directories.rs

@ -1,26 +1,78 @@ @@ -1,26 +1,78 @@
use etcetera::BaseStrategy;
use std::path::PathBuf;
use crate::path_ext::PathExt;
fn xdg_dir(env: &str) -> Option<PathBuf> {
if cfg!(windows) {
let env_var = std::env::var(env).ok()?;
Some(PathBuf::from(env_var))
} else {
// On non-Windows platforms, `etcetera` already handles XDG variables
None
}
}
fn state_dir() -> Option<PathBuf> {
xdg_dir("XDG_STATE_HOME").or_else(dirs::state_dir)
fn runtime_dir(basedirs: &impl BaseStrategy) -> Option<PathBuf> {
xdg_dir("XDG_RUNTIME_DIR").or_else(|| basedirs.runtime_dir())
}
fn cache_dir() -> Option<PathBuf> {
xdg_dir("XDG_CACHE_HOME").or_else(dirs::cache_dir)
fn state_dir(basedirs: &impl BaseStrategy) -> Option<PathBuf> {
xdg_dir("XDG_STATE_HOME").or_else(|| basedirs.state_dir())
}
fn runtime_dir() -> Option<PathBuf> {
xdg_dir("XDG_RUNTIME_DIR").or_else(dirs::runtime_dir)
fn cache_dir(basedirs: &impl BaseStrategy) -> PathBuf {
xdg_dir("XDG_CACHE_HOME").unwrap_or_else(|| basedirs.cache_dir())
}
pub fn multishell_storage() -> PathBuf {
runtime_dir()
.or_else(state_dir)
.or_else(cache_dir)
.unwrap_or_else(std::env::temp_dir)
.join("fnm_multishells")
/// A helper struct for directories in fnm that uses XDG Base Directory Specification
/// if applicable for the platform.
#[derive(Debug)]
pub struct Directories(
#[cfg(windows)] etcetera::base_strategy::Windows,
#[cfg(not(windows))] etcetera::base_strategy::Xdg,
);
impl Default for Directories {
fn default() -> Self {
Self(etcetera::choose_base_strategy().expect("choosing base strategy"))
}
}
impl Directories {
pub fn strategy(&self) -> &impl BaseStrategy {
&self.0
}
pub fn default_base_dir(&self) -> PathBuf {
let strategy = self.strategy();
let modern = strategy.data_dir().join("fnm");
if modern.exists() {
return modern;
}
let legacy = strategy.home_dir().join(".fnm");
if legacy.exists() {
return legacy;
}
#[cfg(target_os = "macos")]
{
let basedirs = etcetera::base_strategy::Apple::new().expect("Can't get home directory");
let legacy = basedirs.data_dir().join("fnm");
if legacy.exists() {
return legacy;
}
}
modern.ensure_exists_silently()
}
pub fn multishell_storage(&self) -> PathBuf {
let basedirs = self.strategy();
let dir = runtime_dir(basedirs)
.or_else(|| state_dir(basedirs))
.unwrap_or_else(|| cache_dir(basedirs));
dir.join("fnm_multishells")
}
}

Loading…
Cancel
Save