mirror of
https://github.com/nushell/nushell
synced 2024-12-26 04:53:09 +00:00
Use directories for autoloading (#13382)
fixes https://github.com/nushell/nushell/issues/13378 # Description This PR tries to improve usage of system APIs to determine the location of vendored autoload files. # User-Facing Changes The paths listed in #13180 and #13217 are changing. This has not been part of a release yet, so arguably the user facing changes are only to unreleased features anyway. # Tests + Formatting Haven't done, but if someone wants to help me here, I'm open to doing it. I just don't know how to properly test this. # After Submitting
This commit is contained in:
parent
e281c03403
commit
4665323bb4
6 changed files with 107 additions and 51 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -3344,6 +3344,8 @@ dependencies = [
|
|||
"chrono",
|
||||
"chrono-humanize",
|
||||
"convert_case",
|
||||
"dirs",
|
||||
"dirs-sys",
|
||||
"fancy-regex",
|
||||
"indexmap",
|
||||
"log",
|
||||
|
@ -3367,6 +3369,7 @@ dependencies = [
|
|||
"tempfile",
|
||||
"thiserror",
|
||||
"typetag",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -84,6 +84,7 @@ deunicode = "1.6.0"
|
|||
dialoguer = { default-features = false, version = "0.11" }
|
||||
digest = { default-features = false, version = "0.10" }
|
||||
dirs = "5.0"
|
||||
dirs-sys = "0.4"
|
||||
dtparse = "2.0"
|
||||
encoding_rs = "0.8"
|
||||
fancy-regex = "0.13"
|
||||
|
@ -178,6 +179,7 @@ v_htmlescape = "0.15.0"
|
|||
wax = "0.6"
|
||||
which = "6.0.0"
|
||||
windows = "0.54"
|
||||
windows-sys = "0.48"
|
||||
winreg = "0.52"
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -833,7 +833,7 @@ fn variables_completions() {
|
|||
"plugin-path".into(),
|
||||
"startup-time".into(),
|
||||
"temp-path".into(),
|
||||
"vendor-autoload-dir".into(),
|
||||
"vendor-autoload-dirs".into(),
|
||||
];
|
||||
|
||||
// Match results
|
||||
|
|
|
@ -23,6 +23,7 @@ byte-unit = { version = "5.1", features = [ "serde" ] }
|
|||
chrono = { workspace = true, features = [ "serde", "std", "unstable-locales" ], default-features = false }
|
||||
chrono-humanize = { workspace = true }
|
||||
convert_case = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
fancy-regex = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
lru = { workspace = true }
|
||||
|
@ -38,6 +39,10 @@ log = { workspace = true }
|
|||
[target.'cfg(unix)'.dependencies]
|
||||
nix = { workspace = true, default-features = false, features = ["signal"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
dirs-sys = { workspace = true }
|
||||
windows-sys = { workspace = true }
|
||||
|
||||
[features]
|
||||
plugin = [
|
||||
"brotli",
|
||||
|
|
|
@ -185,24 +185,15 @@ pub(crate) fn create_nu_constant(engine_state: &EngineState, span: Span) -> Valu
|
|||
},
|
||||
);
|
||||
|
||||
// Create a system level directory for nushell scripts, modules, completions, etc
|
||||
// that can be changed by setting the NU_VENDOR_AUTOLOAD_DIR env var on any platform
|
||||
// before nushell is compiled OR if NU_VENDOR_AUTOLOAD_DIR is not set for non-windows
|
||||
// systems, the PREFIX env var can be set before compile and used as PREFIX/nushell/vendor/autoload
|
||||
record.push(
|
||||
"vendor-autoload-dir",
|
||||
// pseudo code
|
||||
// if env var NU_VENDOR_AUTOLOAD_DIR is set, in any platform, use it
|
||||
// if not, if windows, use ALLUSERPROFILE\nushell\vendor\autoload
|
||||
// if not, if non-windows, if env var PREFIX is set, use PREFIX/share/nushell/vendor/autoload
|
||||
// if not, use the default /usr/share/nushell/vendor/autoload
|
||||
|
||||
// check to see if NU_VENDOR_AUTOLOAD_DIR env var is set, if not, use the default
|
||||
if let Some(path) = get_vendor_autoload_dir(engine_state) {
|
||||
Value::string(path.to_string_lossy(), span)
|
||||
} else {
|
||||
Value::error(ShellError::ConfigDirNotFound { span: Some(span) }, span)
|
||||
},
|
||||
"vendor-autoload-dirs",
|
||||
Value::list(
|
||||
get_vendor_autoload_dirs(engine_state)
|
||||
.iter()
|
||||
.map(|path| Value::string(path.to_string_lossy(), span))
|
||||
.collect(),
|
||||
span,
|
||||
),
|
||||
);
|
||||
|
||||
record.push("temp-path", {
|
||||
|
@ -259,39 +250,95 @@ pub(crate) fn create_nu_constant(engine_state: &EngineState, span: Span) -> Valu
|
|||
Value::record(record, span)
|
||||
}
|
||||
|
||||
pub fn get_vendor_autoload_dir(engine_state: &EngineState) -> Option<PathBuf> {
|
||||
// pseudo code
|
||||
// if env var NU_VENDOR_AUTOLOAD_DIR is set, in any platform, use it
|
||||
// if not, if windows, use ALLUSERPROFILE\nushell\vendor\autoload
|
||||
// if not, if non-windows, if env var PREFIX is set, use PREFIX/share/nushell/vendor/autoload
|
||||
// if not, use the default /usr/share/nushell/vendor/autoload
|
||||
pub fn get_vendor_autoload_dirs(_engine_state: &EngineState) -> Vec<PathBuf> {
|
||||
// load order for autoload dirs
|
||||
// /Library/Application Support/nushell/vendor/autoload on macOS
|
||||
// <dir>/nushell/vendor/autoload for every dir in XDG_DATA_DIRS in reverse order on platforms other than windows. If XDG_DATA_DIRS is not set, it falls back to <PREFIX>/share if PREFIX ends in local, or <PREFIX>/local/share:<PREFIX>/share otherwise. If PREFIX is not set, fall back to /usr/local/share:/usr/share.
|
||||
// %ProgramData%\nushell\vendor\autoload on windows
|
||||
// NU_VENDOR_AUTOLOAD_DIR from compile time, if env var is set at compile time
|
||||
// if on macOS, additionally check XDG_DATA_HOME, which `dirs` is only doing on Linux
|
||||
// <data_dir>/nushell/vendor/autoload of the current user according to the `dirs` crate
|
||||
// NU_VENDOR_AUTOLOAD_DIR at runtime, if env var is set
|
||||
|
||||
// check to see if NU_VENDOR_AUTOLOAD_DIR env var is set, if not, use the default
|
||||
Some(
|
||||
option_env!("NU_VENDOR_AUTOLOAD_DIR")
|
||||
.map(String::from)
|
||||
.unwrap_or_else(|| {
|
||||
if cfg!(windows) {
|
||||
let all_user_profile = match engine_state.get_env_var("ALLUSERPROFILE") {
|
||||
Some(v) => format!(
|
||||
"{}\\nushell\\vendor\\autoload",
|
||||
v.coerce_string().unwrap_or("C:\\ProgramData".into())
|
||||
),
|
||||
None => "C:\\ProgramData\\nushell\\vendor\\autoload".into(),
|
||||
};
|
||||
all_user_profile
|
||||
} else {
|
||||
// In non-Windows environments, if NU_VENDOR_AUTOLOAD_DIR is not set
|
||||
// check to see if PREFIX env var is set, and use it as PREFIX/nushell/vendor/autoload
|
||||
// otherwise default to /usr/share/nushell/vendor/autoload
|
||||
option_env!("PREFIX").map(String::from).map_or_else(
|
||||
|| "/usr/local/share/nushell/vendor/autoload".into(),
|
||||
|prefix| format!("{}/share/nushell/vendor/autoload", prefix),
|
||||
)
|
||||
}
|
||||
let into_autoload_path_fn = |mut path: PathBuf| {
|
||||
path.push("nushell");
|
||||
path.push("vendor");
|
||||
path.push("autoload");
|
||||
path
|
||||
};
|
||||
|
||||
let mut dirs = Vec::new();
|
||||
|
||||
let mut append_fn = |path: PathBuf| {
|
||||
if !dirs.contains(&path) {
|
||||
dirs.push(path)
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
std::iter::once("/Library/Application Support")
|
||||
.map(PathBuf::from)
|
||||
.map(into_autoload_path_fn)
|
||||
.for_each(&mut append_fn);
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
std::env::var_os("XDG_DATA_DIRS")
|
||||
.or_else(|| {
|
||||
option_env!("PREFIX").map(|prefix| {
|
||||
if prefix.ends_with("local") {
|
||||
std::ffi::OsString::from(format!("{prefix}/share"))
|
||||
} else {
|
||||
std::ffi::OsString::from(format!("{prefix}/local/share:{prefix}/share"))
|
||||
}
|
||||
})
|
||||
})
|
||||
.into(),
|
||||
)
|
||||
.unwrap_or_else(|| std::ffi::OsString::from("/usr/local/share/:/usr/share/"))
|
||||
.as_encoded_bytes()
|
||||
.split(|b| *b == b':')
|
||||
.map(|split| into_autoload_path_fn(PathBuf::from(std::ffi::OsStr::from_bytes(split))))
|
||||
.rev()
|
||||
.for_each(&mut append_fn);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
dirs_sys::known_folder(windows_sys::Win32::UI::Shell::FOLDERID_ProgramData)
|
||||
.into_iter()
|
||||
.map(into_autoload_path_fn)
|
||||
.for_each(&mut append_fn);
|
||||
|
||||
option_env!("NU_VENDOR_AUTOLOAD_DIR")
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.for_each(&mut append_fn);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
std::env::var("XDG_DATA_HOME")
|
||||
.ok()
|
||||
.map(PathBuf::from)
|
||||
.or_else(|| {
|
||||
dirs::home_dir().map(|mut home| {
|
||||
home.push(".local");
|
||||
home.push("share");
|
||||
home
|
||||
})
|
||||
})
|
||||
.map(into_autoload_path_fn)
|
||||
.into_iter()
|
||||
.for_each(&mut append_fn);
|
||||
|
||||
dirs::data_dir()
|
||||
.into_iter()
|
||||
.map(into_autoload_path_fn)
|
||||
.for_each(&mut append_fn);
|
||||
|
||||
std::env::var_os("NU_VENDOR_AUTOLOAD_DIR")
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.for_each(&mut append_fn);
|
||||
|
||||
dirs
|
||||
}
|
||||
|
||||
fn eval_const_call(
|
||||
|
|
|
@ -200,8 +200,7 @@ pub(crate) fn read_vendor_autoload_files(engine_state: &mut EngineState, stack:
|
|||
column!()
|
||||
);
|
||||
|
||||
// read and source vendor_autoload_files file if exists
|
||||
if let Some(autoload_dir) = nu_protocol::eval_const::get_vendor_autoload_dir(engine_state) {
|
||||
for autoload_dir in nu_protocol::eval_const::get_vendor_autoload_dirs(engine_state) {
|
||||
warn!("read_vendor_autoload_files: {}", autoload_dir.display());
|
||||
|
||||
if autoload_dir.exists() {
|
||||
|
|
Loading…
Reference in a new issue