From 04a2398c901fe20c5a76dba550736fb40892baaa Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 6 Sep 2025 12:50:18 +0200 Subject: [PATCH] config_paths: separate ifdef'd path logic into functions No functional change, only reduce the number of times we check for presence of the embed-data feature. While at it, move ConfigPaths? --- src/bin/fish.rs | 3 +- src/env/config_paths.rs | 174 ++++++++++++++++++++-------------------- src/env/environment.rs | 3 +- src/env/mod.rs | 2 +- src/env/var.rs | 12 --- 5 files changed, 93 insertions(+), 101 deletions(-) diff --git a/src/bin/fish.rs b/src/bin/fish.rs index e10a6fcb4..56c0ac9fb 100644 --- a/src/bin/fish.rs +++ b/src/bin/fish.rs @@ -35,8 +35,9 @@ PROFILING_ACTIVE, PROGRAM_NAME, }, env::{ + config_paths::ConfigPaths, environment::{env_init, EnvStack, Environment}, - ConfigPaths, EnvMode, Statuses, CONFIG_PATHS, + EnvMode, Statuses, CONFIG_PATHS, }, eprintf, event::{self, Event}, diff --git a/src/env/config_paths.rs b/src/env/config_paths.rs index 10ad690cd..a1b055781 100644 --- a/src/env/config_paths.rs +++ b/src/env/config_paths.rs @@ -1,15 +1,18 @@ -use super::ConfigPaths; use crate::{common::get_executable_path, FLOG, FLOGF}; -use fish_build_helper::workspace_root; use once_cell::sync::Lazy; +use std::path::Path; use std::path::PathBuf; -const DOC_DIR: &str = env!("DOCDIR"); -const DATA_DIR: &str = env!("DATADIR"); -const DATA_DIR_SUBDIR: &str = env!("DATADIR_SUBDIR"); -const SYSCONF_DIR: &str = env!("SYSCONFDIR"); -const LOCALE_DIR: &str = env!("LOCALEDIR"); -const BIN_DIR: &str = env!("BINDIR"); +/// A struct of configuration directories, determined in main() that fish will optionally pass to +/// env_init. +#[derive(Default)] +pub struct ConfigPaths { + pub data: Option, // e.g., /usr/local/share + pub sysconf: PathBuf, // e.g., /usr/local/etc + pub doc: PathBuf, // e.g., /usr/local/share/doc/fish + pub bin: Option, // e.g., /usr/local/bin + pub locale: Option, // e.g., /usr/local/share/locale +} pub static CONFIG_PATHS: Lazy = Lazy::new(|| { // Read the current executable and follow all symlinks to it. @@ -22,86 +25,9 @@ std::env::current_exe().unwrap_or(argv0) }; let argv0 = argv0.canonicalize().unwrap_or(argv0); - let mut paths = ConfigPaths::default(); - #[allow(unused_mut)] - let mut done = false; let exec_path = get_executable_path(&argv0); - #[cfg(not(feature = "embed-data"))] - if let Ok(exec_path) = exec_path.canonicalize() { - FLOG!( - config, - format!("exec_path: {:?}, argv[0]: {:?}", exec_path, &argv0) - ); - // TODO: we should determine program_name from argv0 somewhere in this file - // If we're in Cargo's target directory or CMake's build directory, use the source files. - if exec_path.starts_with(env!("FISH_BUILD_DIR")) { - let workspace_root = workspace_root(); - FLOG!( - config, - "Running out of target directory, using paths relative to workspace root:\n", - workspace_root.display() - ); - done = true; - paths = ConfigPaths { - data: Some(workspace_root.join("share")), - sysconf: workspace_root.join("etc"), - doc: workspace_root.join("user_doc/html"), - bin: Some(exec_path.parent().unwrap().to_owned()), - locale: Some(workspace_root.join("share/locale")), - } - } - - if !done { - // The next check is that we are in a relocatable directory tree - if exec_path.ends_with("bin/fish") { - let base_path = exec_path.parent().unwrap().parent().unwrap(); - paths = ConfigPaths { - data: Some(base_path.join("share/fish")), - sysconf: base_path.join("etc/fish"), - doc: base_path.join("share/doc/fish"), - bin: Some(base_path.join("bin")), - locale: Some(base_path.join("share/locale")), - } - } - - if paths.data.clone().is_some_and(|x| x.exists()) && paths.sysconf.exists() { - // The docs dir may not exist; in that case fall back to the compiled in path. - if !paths.doc.exists() { - paths.doc = PathBuf::from(DOC_DIR); - } - done = true; - } - } - } - - if !done { - // Fall back to what got compiled in. - let data = if cfg!(feature = "embed-data") { - None - } else { - Some(PathBuf::from(DATA_DIR).join(DATA_DIR_SUBDIR)) - }; - let bin = if cfg!(feature = "embed-data") { - exec_path.parent().map(|x| x.to_path_buf()) - } else { - Some(PathBuf::from(BIN_DIR)) - }; - let locale = if cfg!(feature = "embed-data") { - None - } else { - Some(PathBuf::from(LOCALE_DIR)) - }; - - FLOG!(config, "Using compiled in paths:"); - paths = ConfigPaths { - data, - sysconf: PathBuf::from(SYSCONF_DIR).join("fish"), - doc: DOC_DIR.into(), - bin, - locale, - } - } + let paths = ConfigPaths::new(&argv0, exec_path); FLOGF!( config, @@ -128,3 +54,79 @@ paths }); + +const SYSCONF_DIR: &str = env!("SYSCONFDIR"); +const DOC_DIR: &str = env!("DOCDIR"); + +impl ConfigPaths { + #[cfg(feature = "embed-data")] + fn new(_argv0: &Path, exec_path: PathBuf) -> Self { + FLOG!(config, "embed-data feature is active, ignoring data paths"); + ConfigPaths { + data: None, + sysconf: PathBuf::from(SYSCONF_DIR).join("fish"), + doc: DOC_DIR.into(), + bin: exec_path.parent().map(|x| x.to_path_buf()), + locale: None, + } + } + + #[cfg(not(feature = "embed-data"))] + fn new(argv0: &Path, exec_path: PathBuf) -> Self { + if let Ok(exec_path) = exec_path.canonicalize() { + FLOG!( + config, + format!("exec_path: {:?}, argv[0]: {:?}", exec_path, &argv0) + ); + // TODO: we should determine program_name from argv0 somewhere in this file + + // If we're in Cargo's target directory or CMake's build directory, use the source files. + if exec_path.starts_with(env!("FISH_BUILD_DIR")) { + let workspace_root = fish_build_helper::workspace_root(); + FLOG!( + config, + "Running out of target directory, using paths relative to workspace root:\n", + workspace_root.display() + ); + return ConfigPaths { + data: Some(workspace_root.join("share")), + sysconf: workspace_root.join("etc"), + doc: workspace_root.join("user_doc/html"), + bin: Some(exec_path.parent().unwrap().to_owned()), + locale: Some(workspace_root.join("share/locale")), + }; + } + + let mut paths = ConfigPaths::default(); + // The next check is that we are in a relocatable directory tree + if exec_path.ends_with("bin/fish") { + let base_path = exec_path.parent().unwrap().parent().unwrap(); + paths = ConfigPaths { + data: Some(base_path.join("share/fish")), + sysconf: base_path.join("etc/fish"), + doc: base_path.join("share/doc/fish"), + bin: Some(base_path.join("bin")), + locale: Some(base_path.join("share/locale")), + } + } + + if paths.data.clone().is_some_and(|x| x.exists()) && paths.sysconf.exists() { + // The docs dir may not exist; in that case fall back to the compiled in path. + if !paths.doc.exists() { + paths.doc = PathBuf::from(DOC_DIR); + } + return paths; + } + } + + // Fall back to what got compiled in. + FLOG!(config, "Using compiled in paths:"); + ConfigPaths { + data: Some(PathBuf::from(env!("DATADIR")).join(env!("DATADIR_SUBDIR"))), + sysconf: PathBuf::from(SYSCONF_DIR).join("fish"), + doc: DOC_DIR.into(), + bin: Some(PathBuf::from(env!("BINDIR"))), + locale: Some(PathBuf::from(env!("LOCALEDIR"))), + } + } +} diff --git a/src/env/environment.rs b/src/env/environment.rs index 94b66c241..e09092d79 100644 --- a/src/env/environment.rs +++ b/src/env/environment.rs @@ -2,10 +2,11 @@ colon_split, uvars, EnvMutex, EnvMutexGuard, EnvScopedImpl, EnvStackImpl, ModResult, UVAR_SCOPE_IS_GLOBAL, }; -use super::{ConfigPaths, ElectricVar}; +use super::ElectricVar; use crate::abbrs::{abbrs_get_set, Abbreviation, Position}; use crate::builtins::shared::{BuiltinResult, SUCCESS}; use crate::common::{str2wcstring, unescape_string, wcs2zstring, UnescapeStringStyle}; +use crate::env::config_paths::ConfigPaths; use crate::env::{EnvMode, EnvVar, Statuses}; use crate::env_dispatch::{env_dispatch_init, env_dispatch_var_change}; use crate::event::Event; diff --git a/src/env/mod.rs b/src/env/mod.rs index 8c5821fda..5d09c813b 100644 --- a/src/env/mod.rs +++ b/src/env/mod.rs @@ -1,4 +1,4 @@ -mod config_paths; +pub mod config_paths; pub mod environment; mod environment_impl; pub mod var; diff --git a/src/env/var.rs b/src/env/var.rs index 8a115e808..0c2ba8a0e 100644 --- a/src/env/var.rs +++ b/src/env/var.rs @@ -4,7 +4,6 @@ use bitflags::bitflags; use libc::c_int; use std::collections::HashMap; -use std::path::PathBuf; use std::sync::Arc; /// The character used to delimit path and non-path variables in exporting and in string expansion. @@ -46,17 +45,6 @@ fn from(val: EnvMode) -> Self { } } -/// A struct of configuration directories, determined in main() that fish will optionally pass to -/// env_init. -#[derive(Default)] -pub struct ConfigPaths { - pub data: Option, // e.g., /usr/local/share - pub sysconf: PathBuf, // e.g., /usr/local/etc - pub doc: PathBuf, // e.g., /usr/local/share/doc/fish - pub bin: Option, // e.g., /usr/local/bin - pub locale: Option, // e.g., /usr/local/share/locale -} - /// A collection of status and pipestatus. #[derive(Clone, Debug)] pub struct Statuses {