Skip to content

Commit 5c07d72

Browse files
committed
reduce sys::Sys requirements, add some tracing for otherwise silent errors
1 parent a0a6daf commit 5c07d72

File tree

4 files changed

+47
-22
lines changed

4 files changed

+47
-22
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ keywords = ["which", "which-rs", "unix", "command"]
1616
default = ["real-sys"]
1717
regex = ["dep:regex"]
1818
tracing = ["dep:tracing"]
19-
real-sys = ["env_home", "rustix", "winsafe"]
19+
real-sys = ["dep:env_home", "dep:rustix", "dep:winsafe"]
2020

2121
[dependencies]
2222
either = "1.9.0"

src/lib.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item =
9292

9393
Finder::new(sys::RealSys).find(
9494
binary_name,
95-
sys::RealSys.env_var_os(OsStr::new("PATH")),
95+
sys::RealSys.env_path(),
9696
cwd,
9797
CompositeChecker::new(sys::RealSys),
9898
Noop,
@@ -106,7 +106,7 @@ pub fn which_all_global<T: AsRef<OsStr>>(
106106
) -> Result<impl Iterator<Item = path::PathBuf>> {
107107
Finder::new(sys::RealSys).find(
108108
binary_name,
109-
sys::RealSys.env_var_os(OsStr::new("PATH")),
109+
sys::RealSys.env_path(),
110110
Option::<&Path>::None,
111111
CompositeChecker::new(sys::RealSys),
112112
Noop,
@@ -149,7 +149,7 @@ pub fn which_all_global<T: AsRef<OsStr>>(
149149
pub fn which_re(
150150
regex: impl std::borrow::Borrow<Regex>,
151151
) -> Result<impl Iterator<Item = path::PathBuf>> {
152-
which_re_in(regex, sys::RealSys.env_var_os(OsStr::new("PATH")))
152+
which_re_in(regex, sys::RealSys.env_path())
153153
}
154154

155155
/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
@@ -465,9 +465,7 @@ impl<'a, TSys: Sys, F: NonFatalErrorHandler + 'a> WhichConfig<TSys, F> {
465465

466466
/// Finishes configuring, runs the query and returns all results.
467467
pub fn all_results(self) -> Result<impl Iterator<Item = path::PathBuf> + 'a> {
468-
let paths = self
469-
.custom_path_list
470-
.or_else(|| self.sys.env_var_os(OsStr::new("PATH")));
468+
let paths = self.custom_path_list.or_else(|| self.sys.env_path());
471469

472470
#[cfg(feature = "regex")]
473471
if let Some(regex) = self.regex {

src/sys.rs

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::borrow::Cow;
2-
use std::env::VarError;
32
use std::ffi::OsStr;
43
use std::ffi::OsString;
54
use std::io;
@@ -63,14 +62,10 @@ pub trait Sys: Clone {
6362
fn home_dir(&self) -> Option<PathBuf>;
6463
/// Splits a platform-specific PATH variable into a list of paths.
6564
fn env_split_paths(&self, paths: &OsStr) -> Vec<PathBuf>;
66-
/// Gets the value of an environment variable.
67-
fn env_var_os(&self, name: &OsStr) -> Option<OsString>;
68-
fn env_var(&self, key: &OsStr) -> Result<String, VarError> {
69-
match self.env_var_os(key) {
70-
Some(val) => val.into_string().map_err(VarError::NotUnicode),
71-
None => Err(VarError::NotPresent),
72-
}
73-
}
65+
/// Gets the value of the PATH environment variable.
66+
fn env_path(&self) -> Option<OsString>;
67+
/// Gets the value of the PATHEXT environment variable. If not on Windows, simply return None.
68+
fn env_path_ext(&self) -> Option<OsString>;
7469
/// Gets and parses the PATHEXT environment variable on Windows.
7570
///
7671
/// Override this to enable caching the parsed PATHEXT.
@@ -80,7 +75,19 @@ pub trait Sys: Clone {
8075
/// can work in Wasm.
8176
fn env_windows_path_ext(&self) -> Cow<'static, [String]> {
8277
Cow::Owned(
83-
self.env_var(OsStr::new("PATHEXT"))
78+
self.env_path_ext()
79+
.and_then(|pathext| {
80+
// If tracing feature enabled then this lint is incorrect, so disable it.
81+
#[allow(clippy::manual_ok_err)]
82+
match pathext.into_string() {
83+
Ok(pathext) => Some(pathext),
84+
Err(_) => {
85+
#[cfg(feature = "tracing")]
86+
tracing::error!("pathext is not valid unicode");
87+
None
88+
}
89+
}
90+
})
8491
.map(|pathext| parse_path_ext(&pathext))
8592
// PATHEXT not being set or not being a proper Unicode string is exceedingly
8693
// improbable and would probably break Windows badly. Still, don't crash:
@@ -180,7 +187,15 @@ impl Sys for RealSys {
180187
// hence its retention.)
181188
static PATH_EXTENSIONS: OnceLock<Vec<String>> = OnceLock::new();
182189
let path_extensions = PATH_EXTENSIONS.get_or_init(|| {
183-
self.env_var(OsStr::new("PATHEXT"))
190+
self.env_path_ext()
191+
.and_then(|pathext| match pathext.into_string() {
192+
Ok(pathext) => Some(pathext),
193+
Err(_) => {
194+
#[cfg(feature = "tracing")]
195+
tracing::error!("pathext is not valid unicode");
196+
None
197+
}
198+
})
184199
.map(|s| parse_path_ext(&s))
185200
// PATHEXT not being set or not being a proper Unicode string is exceedingly
186201
// improbable and would probably break Windows badly. Still, don't crash:
@@ -190,9 +205,15 @@ impl Sys for RealSys {
190205
}
191206

192207
#[inline]
193-
fn env_var_os(&self, name: &OsStr) -> Option<OsString> {
208+
fn env_path(&self) -> Option<OsString> {
209+
#[allow(clippy::disallowed_methods)] // ok, sys implementation
210+
std::env::var_os("PATH")
211+
}
212+
213+
#[inline]
214+
fn env_path_ext(&self) -> Option<OsString> {
194215
#[allow(clippy::disallowed_methods)] // ok, sys implementation
195-
std::env::var_os(name)
216+
std::env::var_os("PATHEXT")
196217
}
197218

198219
#[inline]
@@ -241,6 +262,8 @@ fn parse_path_ext(pathext: &str) -> Vec<String> {
241262
Some(s.to_owned())
242263
} else {
243264
// Invalid segment; just ignore it.
265+
#[cfg(feature = "tracing")]
266+
tracing::debug!("PATHEXT segment \"{s}\" missing leading dot, ignoring");
244267
None
245268
}
246269
})

tests/basic.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -767,8 +767,12 @@ mod in_memory {
767767
.collect()
768768
}
769769

770-
fn env_var_os(&self, name: &OsStr) -> Option<OsString> {
771-
self.env_vars.get(name).cloned()
770+
fn env_path(&self) -> Option<OsString> {
771+
self.env_vars.get(OsStr::new("PATH")).cloned()
772+
}
773+
774+
fn env_path_ext(&self) -> Option<OsString> {
775+
self.env_vars.get(OsStr::new("PATHEXT")).cloned()
772776
}
773777

774778
fn metadata(&self, path: &Path) -> io::Result<Self::Metadata> {

0 commit comments

Comments
 (0)