diff options
Diffstat (limited to 'src/finder.rs')
-rw-r--r-- | src/finder.rs | 95 |
1 files changed, 63 insertions, 32 deletions
diff --git a/src/finder.rs b/src/finder.rs index 9b64294..858a224 100644 --- a/src/finder.rs +++ b/src/finder.rs @@ -9,7 +9,7 @@ use regex::Regex; use std::borrow::Borrow; use std::env; use std::ffi::OsStr; -#[cfg(feature = "regex")] +#[cfg(any(feature = "regex", target_os = "windows"))] use std::fs; use std::iter; use std::path::{Path, PathBuf}; @@ -80,7 +80,9 @@ impl Finder { } }; - Ok(binary_path_candidates.filter(move |p| binary_checker.is_valid(p))) + Ok(binary_path_candidates + .filter(move |p| binary_checker.is_valid(p)) + .map(correct_casing)) } #[cfg(feature = "regex")] @@ -151,29 +153,31 @@ impl Finder { where P: IntoIterator<Item = PathBuf>, { + use once_cell::sync::Lazy; + // Sample %PATHEXT%: .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC // PATH_EXTENSIONS is then [".COM", ".EXE", ".BAT", …]. // (In one use of PATH_EXTENSIONS we skip the dot, but in the other we need it; // hence its retention.) - lazy_static! { - static ref PATH_EXTENSIONS: Vec<String> = - env::var("PATHEXT") - .map(|pathext| { - pathext.split(';') - .filter_map(|s| { - if s.as_bytes().first() == Some(&b'.') { - Some(s.to_owned()) - } else { - // Invalid segment; just ignore it. - None - } - }) - .collect() - }) - // PATHEXT not being set or not being a proper Unicode string is exceedingly - // improbable and would probably break Windows badly. Still, don't crash: - .unwrap_or_default(); - } + static PATH_EXTENSIONS: Lazy<Vec<String>> = Lazy::new(|| { + env::var("PATHEXT") + .map(|pathext| { + pathext + .split(';') + .filter_map(|s| { + if s.as_bytes().first() == Some(&b'.') { + Some(s.to_owned()) + } else { + // Invalid segment; just ignore it. + None + } + }) + .collect() + }) + // PATHEXT not being set or not being a proper Unicode string is exceedingly + // improbable and would probably break Windows badly. Still, don't crash: + .unwrap_or_default() + }); paths .into_iter() @@ -182,20 +186,47 @@ impl Finder { if has_executable_extension(&p, &PATH_EXTENSIONS) { Box::new(iter::once(p)) } else { + let bare_file = p.extension().map(|_| p.clone()); // Appended paths with windows executable extensions. - // e.g. path `c:/windows/bin` will expend to: - // c:/windows/bin.COM - // c:/windows/bin.EXE - // c:/windows/bin.CMD + // e.g. path `c:/windows/bin[.ext]` will expand to: + // [c:/windows/bin.ext] + // c:/windows/bin[.ext].COM + // c:/windows/bin[.ext].EXE + // c:/windows/bin[.ext].CMD // ... - Box::new(PATH_EXTENSIONS.iter().map(move |e| { - // Append the extension. - let mut p = p.clone().into_os_string(); - p.push(e); - - PathBuf::from(p) - })) + Box::new( + bare_file + .into_iter() + .chain(PATH_EXTENSIONS.iter().map(move |e| { + // Append the extension. + let mut p = p.clone().into_os_string(); + p.push(e); + + PathBuf::from(p) + })), + ) } }) } } + +#[cfg(target_os = "windows")] +fn correct_casing(mut p: PathBuf) -> PathBuf { + if let (Some(parent), Some(file_name)) = (p.parent(), p.file_name()) { + if let Ok(iter) = fs::read_dir(parent) { + for e in iter.filter_map(std::result::Result::ok) { + if e.file_name().eq_ignore_ascii_case(file_name) { + p.pop(); + p.push(e.file_name()); + break; + } + } + } + } + p +} + +#[cfg(not(target_os = "windows"))] +fn correct_casing(p: PathBuf) -> PathBuf { + p +} |