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?
This commit is contained in:
Johannes Altmanninger
2025-09-06 12:50:18 +02:00
parent f05ad46980
commit 04a2398c90
5 changed files with 93 additions and 101 deletions

View File

@@ -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},

View File

@@ -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<PathBuf>, // 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<PathBuf>, // e.g., /usr/local/bin
pub locale: Option<PathBuf>, // e.g., /usr/local/share/locale
}
pub static CONFIG_PATHS: Lazy<ConfigPaths> = 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"))),
}
}
}

View File

@@ -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;

2
src/env/mod.rs vendored
View File

@@ -1,4 +1,4 @@
mod config_paths;
pub mod config_paths;
pub mod environment;
mod environment_impl;
pub mod var;

12
src/env/var.rs vendored
View File

@@ -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<PathBuf>, // 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<PathBuf>, // e.g., /usr/local/bin
pub locale: Option<PathBuf>, // e.g., /usr/local/share/locale
}
/// A collection of status and pipestatus.
#[derive(Clone, Debug)]
pub struct Statuses {