diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 04:45:59 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 04:45:59 +0000 |
commit | 7a60549820726e160c1b20b9c6908dc1a06aa905 (patch) | |
tree | bb7fed649d07e5b24e581d19ccf3c547b2b86c62 | |
parent | 6f0fadcda199702a28974afba6e4b75bf6a20b2a (diff) | |
parent | 878f532dd57bdcbce44364b7eecb1811140e99b7 (diff) | |
download | which-aml_ase_340913000.tar.gz |
Snap for 10453563 from 878f532dd57bdcbce44364b7eecb1811140e99b7 to mainline-appsearch-releaseaml_ase_341510000aml_ase_341410000aml_ase_341310010aml_ase_341113000aml_ase_340913000android14-mainline-appsearch-release
Change-Id: I4ec2126e3186990980b8c0d5f4edd6efa5436d86
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | .github/workflows/rust.yml | 6 | ||||
-rw-r--r-- | Android.bp | 9 | ||||
-rw-r--r-- | Cargo.toml | 30 | ||||
-rw-r--r-- | Cargo.toml.orig | 12 | ||||
-rw-r--r-- | METADATA | 14 | ||||
-rw-r--r-- | TEST_MAPPING | 14 | ||||
-rw-r--r-- | src/checker.rs | 4 | ||||
-rw-r--r-- | src/finder.rs | 98 | ||||
-rw-r--r-- | src/lib.rs | 231 | ||||
-rw-r--r-- | tests/basic.rs | 65 |
11 files changed, 377 insertions, 108 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 692ca11..0dcc2ff 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "8fbe34239c16af9cd253e36e9c2d3384f9b55f83" + "sha1": "13722854453a50002d72faa1d0960f70b68ceea4" }, "path_in_vcs": "" }
\ No newline at end of file diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index dd380d3..aa13ec5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -28,7 +28,7 @@ jobs: name: Clippy [Linter] strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - name: Setup | Checkout @@ -46,7 +46,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --workspace --all-targets --all-features + args: --workspace --all-targets --all-features -- -Dwarnings # Ensure that the project could be successfully compiled cargo_check: @@ -75,7 +75,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest, macos-latest] rust: [stable, nightly] steps: - name: Setup | Checkout @@ -20,14 +20,21 @@ license { rust_library { name: "libwhich", + // has rustc warnings host_supported: true, crate_name: "which", cargo_env_compat: true, - cargo_pkg_version: "4.2.4", + cargo_pkg_version: "4.4.0", srcs: ["src/lib.rs"], edition: "2018", rustlibs: [ "libeither", "liblibc", ], + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + product_available: true, + vendor_available: true, } @@ -12,27 +12,39 @@ [package] edition = "2018" name = "which" -version = "4.2.4" +version = "4.4.0" authors = ["Harry Fei <tiziyuanfang@gmail.com>"] description = "A Rust equivalent of Unix command \"which\". Locate installed executable in cross platforms." documentation = "https://docs.rs/which/" readme = "README.md" -keywords = ["which", "which-rs", "unix", "command"] -categories = ["os", "filesystem"] +keywords = [ + "which", + "which-rs", + "unix", + "command", +] +categories = [ + "os", + "filesystem", +] license = "MIT" repository = "https://github.com/harryfei/which-rs.git" + [package.metadata.docs.rs] all-features = true + [dependencies.either] -version = "1.6" +version = "1.6.1" [dependencies.libc] -version = "0.2.65" +version = "0.2.121" [dependencies.regex] -version = "1.5.4" +version = "1.5.5" optional = true -[dev-dependencies.tempdir] -version = "0.3.7" -[target."cfg(windows)".dependencies.lazy_static] + +[dev-dependencies.tempfile] +version = "3.3.0" + +[target."cfg(windows)".dependencies.once_cell] version = "1" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index ec31c55..e05adb3 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "which" -version = "4.2.4" +version = "4.4.0" edition = "2018" authors = ["Harry Fei <tiziyuanfang@gmail.com>"] repository = "https://github.com/harryfei/which-rs.git" @@ -12,15 +12,15 @@ categories = ["os", "filesystem"] keywords = ["which", "which-rs", "unix", "command"] [dependencies] -either = "1.6" -libc = "0.2.65" -regex = { version = "1.5.4", optional = true } +either = "1.6.1" +libc = "0.2.121" +regex = { version = "1.5.5", optional = true } [target.'cfg(windows)'.dependencies] -lazy_static = "1" +once_cell = "1" [dev-dependencies] -tempdir = "0.3.7" +tempfile = "3.3.0" [package.metadata.docs.rs] all-features = true @@ -1,3 +1,7 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/which +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "which" description: "A Rust equivalent of Unix command \"which\". Locate installed executable in cross platforms." third_party { @@ -7,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/which/which-4.2.4.crate" + value: "https://static.crates.io/crates/which/which-4.4.0.crate" } - version: "4.2.4" + version: "4.4.0" license_type: NOTICE last_upgrade_date { - year: 2022 - month: 3 - day: 1 + year: 2023 + month: 2 + day: 17 } } diff --git a/TEST_MAPPING b/TEST_MAPPING index e4ec3b3..23bbdf9 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -3,22 +3,12 @@ "imports": [ { "path": "external/rust/crates/libsqlite3-sys" - } - ], - "presubmit": [ - { - "name": "keystore2_test" }, { - "name": "legacykeystore_test" - } - ], - "presubmit-rust": [ - { - "name": "keystore2_test" + "path": "system/security/keystore2" }, { - "name": "legacykeystore_test" + "path": "system/security/keystore2/legacykeystore" } ] } diff --git a/src/checker.rs b/src/checker.rs index 62b78a2..0e92c6a 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -1,7 +1,5 @@ use crate::finder::Checker; #[cfg(unix)] -use libc; -#[cfg(unix)] use std::ffi::CString; use std::fs; #[cfg(unix)] @@ -20,7 +18,7 @@ impl Checker for ExecutableChecker { #[cfg(unix)] fn is_valid(&self, path: &Path) -> bool { CString::new(path.as_os_str().as_bytes()) - .and_then(|c| Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 })) + .map(|c| unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 }) .unwrap_or(false) } diff --git a/src/finder.rs b/src/finder.rs index 43b659d..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")] @@ -94,6 +96,9 @@ impl Finder { T: AsRef<OsStr>, { let p = paths.ok_or(Error::CannotFindBinaryPath)?; + // Collect needs to happen in order to not have to + // change the API to borrow on `paths`. + #[allow(clippy::needless_collect)] let paths: Vec<_> = env::split_paths(&p).collect(); let matching_re = paths @@ -148,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(vec![]); - } + 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() @@ -179,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 +} @@ -14,10 +14,6 @@ //! //! ``` -#[cfg(windows)] -#[macro_use] -extern crate lazy_static; - mod checker; mod error; mod finder; @@ -25,20 +21,18 @@ mod finder; mod helper; #[cfg(feature = "regex")] -use regex::Regex; -#[cfg(feature = "regex")] use std::borrow::Borrow; use std::env; use std::fmt; use std::path; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use crate::checker::{CompositeChecker, ExecutableChecker, ExistedChecker}; pub use crate::error::*; use crate::finder::Finder; -/// Find a exectable binary's path by name. +/// Find an executable binary's path by name. /// /// If given an absolute path, returns it if the file exists and is executable. /// @@ -63,7 +57,31 @@ pub fn which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> { which_all(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath)) } -/// Find all binaries with `binary_name` in the path list `paths`, using `cwd` to resolve relative paths. +/// Find an executable binary's path by name, ignoring `cwd`. +/// +/// If given an absolute path, returns it if the file exists and is executable. +/// +/// Does not resolve relative paths. +/// +/// If given a string without path separators, looks for a file named +/// `binary_name` at each directory in `$PATH` and if it finds an executable +/// file there, returns it. +/// +/// # Example +/// +/// ```no_run +/// use which::which; +/// use std::path::PathBuf; +/// +/// let result = which::which_global("rustc").unwrap(); +/// assert_eq!(result, PathBuf::from("/usr/bin/rustc")); +/// +/// ``` +pub fn which_global<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> { + which_all_global(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath)) +} + +/// Find all binaries with `binary_name` using `cwd` to resolve relative paths. pub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = path::PathBuf>> { let cwd = env::current_dir().ok(); @@ -74,6 +92,22 @@ pub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = finder.find(binary_name, env::var_os("PATH"), cwd, binary_checker) } +/// Find all binaries with `binary_name` ignoring `cwd`. +pub fn which_all_global<T: AsRef<OsStr>>( + binary_name: T, +) -> Result<impl Iterator<Item = path::PathBuf>> { + let binary_checker = build_binary_checker(); + + let finder = Finder::new(); + + finder.find( + binary_name, + env::var_os("PATH"), + Option::<&Path>::None, + binary_checker, + ) +} + /// Find all binaries matching a regular expression in a the system PATH. /// /// Only available when feature `regex` is enabled. @@ -178,12 +212,183 @@ where finder.find(binary_name, paths, Some(cwd), binary_checker) } +/// Find all binaries with `binary_name` in the path list `paths`, ignoring `cwd`. +pub fn which_in_global<T, U>( + binary_name: T, + paths: Option<U>, +) -> Result<impl Iterator<Item = path::PathBuf>> +where + T: AsRef<OsStr>, + U: AsRef<OsStr>, +{ + let binary_checker = build_binary_checker(); + + let finder = Finder::new(); + + finder.find(binary_name, paths, Option::<&Path>::None, binary_checker) +} + fn build_binary_checker() -> CompositeChecker { CompositeChecker::new() .add_checker(Box::new(ExistedChecker::new())) .add_checker(Box::new(ExecutableChecker::new())) } +/// A wrapper containing all functionality in this crate. +pub struct WhichConfig { + cwd: Option<either::Either<bool, path::PathBuf>>, + custom_path_list: Option<OsString>, + binary_name: Option<OsString>, + #[cfg(feature = "regex")] + regex: Option<Regex>, +} + +impl Default for WhichConfig { + fn default() -> Self { + Self { + cwd: Some(either::Either::Left(true)), + custom_path_list: None, + binary_name: None, + #[cfg(feature = "regex")] + regex: None, + } + } +} + +#[cfg(feature = "regex")] +type Regex = regex::Regex; + +#[cfg(not(feature = "regex"))] +type Regex = (); + +impl WhichConfig { + pub fn new() -> Self { + Self::default() + } + + /// Whether or not to use the current working directory. `true` by default. + /// + /// # Panics + /// + /// If regex was set previously, and you've just passed in `use_cwd: true`, this will panic. + pub fn system_cwd(mut self, use_cwd: bool) -> Self { + #[cfg(feature = "regex")] + if self.regex.is_some() && use_cwd { + panic!("which can't use regex and cwd at the same time!") + } + self.cwd = Some(either::Either::Left(use_cwd)); + self + } + + /// Sets a custom path for resolving relative paths. + /// + /// # Panics + /// + /// If regex was set previously, this will panic. + pub fn custom_cwd(mut self, cwd: path::PathBuf) -> Self { + #[cfg(feature = "regex")] + if self.regex.is_some() { + panic!("which can't use regex and cwd at the same time!") + } + self.cwd = Some(either::Either::Right(cwd)); + self + } + + /// Sets the path name regex to search for. You ***MUST*** call this, or [`Self::binary_name`] prior to searching. + /// + /// When `Regex` is disabled this function takes the unit type as a stand in. The parameter will change when + /// `Regex` is enabled. + /// + /// # Panics + /// + /// If the `regex` feature wasn't turned on for this crate this will always panic. Additionally if a + /// `cwd` (aka current working directory) or `binary_name` was set previously, this will panic, as those options + /// are incompatible with `regex`. + #[allow(unused_variables)] + pub fn regex(mut self, regex: Regex) -> Self { + #[cfg(not(feature = "regex"))] + { + panic!("which's regex feature was not enabled in your Cargo.toml!") + } + #[cfg(feature = "regex")] + { + if self.cwd != Some(either::Either::Left(false)) && self.cwd.is_some() { + panic!("which can't use regex and cwd at the same time!") + } + if self.binary_name.is_some() { + panic!("which can't use `binary_name` and `regex` at the same time!"); + } + self.regex = Some(regex); + self + } + } + + /// Sets the path name to search for. You ***MUST*** call this, or [`Self::regex`] prior to searching. + /// + /// # Panics + /// + /// If a `regex` was set previously this will panic as this is not compatible with `regex`. + pub fn binary_name(mut self, name: OsString) -> Self { + #[cfg(feature = "regex")] + if self.regex.is_some() { + panic!("which can't use `binary_name` and `regex` at the same time!"); + } + self.binary_name = Some(name); + self + } + + /// Uses the given string instead of the `PATH` env variable. + pub fn custom_path_list(mut self, custom_path_list: OsString) -> Self { + self.custom_path_list = Some(custom_path_list); + self + } + + /// Uses the `PATH` env variable. Enabled by default. + pub fn system_path_list(mut self) -> Self { + self.custom_path_list = None; + self + } + + /// Finishes configuring, runs the query and returns the first result. + pub fn first_result(self) -> Result<path::PathBuf> { + self.all_results() + .and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath)) + } + + /// Finishes configuring, runs the query and returns all results. + pub fn all_results(self) -> Result<impl Iterator<Item = path::PathBuf>> { + let binary_checker = build_binary_checker(); + + let finder = Finder::new(); + + let paths = self.custom_path_list.or_else(|| env::var_os("PATH")); + + #[cfg(feature = "regex")] + if let Some(regex) = self.regex { + return finder + .find_re(regex, paths, binary_checker) + .map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf>>); + } + + let cwd = match self.cwd { + Some(either::Either::Left(false)) => None, + Some(either::Either::Right(custom)) => Some(custom), + None | Some(either::Either::Left(true)) => env::current_dir().ok(), + }; + + finder + .find( + self.binary_name.expect( + "binary_name not set! You must set binary_name or regex before searching!", + ), + paths, + cwd, + binary_checker, + ) + .map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf>>) + } +} + /// An owned, immutable wrapper around a `PathBuf` containing the path of an executable. /// /// The constructed `PathBuf` is the output of `which` or `which_in`, but `which::Path` has the @@ -194,7 +399,7 @@ fn build_binary_checker() -> CompositeChecker { /// /// Since `which::Path` implements `Deref` for `std::path::Path`, all methods on `&std::path::Path` /// are also available to `&which::Path` values. -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq)] pub struct Path { inner: path::PathBuf, } @@ -281,8 +486,6 @@ impl AsRef<OsStr> for Path { } } -impl Eq for Path {} - impl PartialEq<path::PathBuf> for Path { fn eq(&self, other: &path::PathBuf) -> bool { self.inner == *other @@ -308,7 +511,7 @@ impl PartialEq<Path> for path::PathBuf { /// /// Since `CanonicalPath` implements `Deref` for `std::path::Path`, all methods on /// `&std::path::Path` are also available to `&CanonicalPath` values. -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq)] pub struct CanonicalPath { inner: path::PathBuf, } @@ -415,8 +618,6 @@ impl AsRef<OsStr> for CanonicalPath { } } -impl Eq for CanonicalPath {} - impl PartialEq<path::PathBuf> for CanonicalPath { fn eq(&self, other: &path::PathBuf) -> bool { self.inner == *other diff --git a/tests/basic.rs b/tests/basic.rs index 897e912..32a1a28 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -1,14 +1,13 @@ -extern crate tempdir; extern crate which; -#[cfg(feature = "regex")] +#[cfg(all(unix, feature = "regex"))] use regex::Regex; use std::ffi::{OsStr, OsString}; use std::fs; use std::io; use std::path::{Path, PathBuf}; use std::{env, vec}; -use tempdir::TempDir; +use tempfile::TempDir; struct TestFixture { /// Temp directory. @@ -19,8 +18,8 @@ struct TestFixture { pub bins: Vec<PathBuf>, } -const SUBDIRS: &'static [&'static str] = &["a", "b", "c"]; -const BIN_NAME: &'static str = "bin"; +const SUBDIRS: &[&str] = &["a", "b", "c"]; +const BIN_NAME: &str = "bin"; #[cfg(unix)] fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> { @@ -55,7 +54,7 @@ impl TestFixture { // tmp/c/bin.exe // tmp/c/bin.cmd pub fn new() -> TestFixture { - let tempdir = TempDir::new("which_tests").unwrap(); + let tempdir = tempfile::tempdir().unwrap(); let mut builder = fs::DirBuilder::new(); builder.recursive(true); let mut paths = vec![]; @@ -63,25 +62,29 @@ impl TestFixture { for d in SUBDIRS.iter() { let p = tempdir.path().join(d); builder.create(&p).unwrap(); - bins.push(mk_bin(&p, &BIN_NAME, "").unwrap()); - bins.push(mk_bin(&p, &BIN_NAME, "exe").unwrap()); - bins.push(mk_bin(&p, &BIN_NAME, "cmd").unwrap()); + bins.push(mk_bin(&p, BIN_NAME, "").unwrap()); + bins.push(mk_bin(&p, BIN_NAME, "exe").unwrap()); + bins.push(mk_bin(&p, BIN_NAME, "cmd").unwrap()); paths.push(p); } + let p = tempdir.path().join("win-bin"); + builder.create(&p).unwrap(); + bins.push(mk_bin(&p, "win-bin", "exe").unwrap()); + paths.push(p); TestFixture { - tempdir: tempdir, + tempdir, paths: env::join_paths(paths).unwrap(), - bins: bins, + bins, } } #[allow(dead_code)] pub fn touch(&self, path: &str, extension: &str) -> io::Result<PathBuf> { - touch(self.tempdir.path(), &path, &extension) + touch(self.tempdir.path(), path, extension) } pub fn mk_bin(&self, path: &str, extension: &str) -> io::Result<PathBuf> { - mk_bin(self.tempdir.path(), &path, &extension) + mk_bin(self.tempdir.path(), path, extension) } } @@ -89,11 +92,11 @@ fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> which::Result<which::Can which::CanonicalPath::new_in(path, Some(f.paths.clone()), f.tempdir.path()) } -fn _which_all<T: AsRef<OsStr>>( - f: &TestFixture, +fn _which_all<'a, T: AsRef<OsStr> + 'a>( + f: &'a TestFixture, path: T, -) -> which::Result<impl Iterator<Item = which::Result<which::CanonicalPath>>> { - which::CanonicalPath::all_in(path, Some(f.paths.clone()), f.tempdir.path().to_path_buf()) +) -> which::Result<impl Iterator<Item = which::Result<which::CanonicalPath>> + '_> { + which::CanonicalPath::all_in(path, Some(f.paths.clone()), f.tempdir.path()) } #[test] @@ -165,10 +168,18 @@ fn test_which_re_in_without_matches() { #[test] #[cfg(all(unix, feature = "regex"))] fn test_which_re_accepts_owned_and_borrow() { - which::which_re(Regex::new(r".").unwrap()); - which::which_re(&Regex::new(r".").unwrap()); - which::which_re_in(Regex::new(r".").unwrap(), Some("pth")); - which::which_re_in(&Regex::new(r".").unwrap(), Some("pth")); + which::which_re(Regex::new(r".").unwrap()) + .unwrap() + .for_each(drop); + which::which_re(&Regex::new(r".").unwrap()) + .unwrap() + .for_each(drop); + which::which_re_in(Regex::new(r".").unwrap(), Some("pth")) + .unwrap() + .for_each(drop); + which::which_re_in(&Regex::new(r".").unwrap(), Some("pth")) + .unwrap() + .for_each(drop); } #[test] @@ -188,6 +199,17 @@ fn test_which_extension() { } #[test] +#[cfg(windows)] +fn test_which_no_extension() { + let f = TestFixture::new(); + let b = Path::new("win-bin"); + let which_result = which::which_in(&b, Some(&f.paths), ".").unwrap(); + // Make sure the extension is the correct case. + assert_eq!(which_result.extension(), f.bins[9].extension()); + assert_eq!(fs::canonicalize(&which_result).unwrap(), f.bins[9]) +} + +#[test] fn test_which_not_found() { let f = TestFixture::new(); assert!(_which(&f, "a").is_err()); @@ -214,6 +236,7 @@ fn test_which_all() { .collect::<Vec<_>>(); #[cfg(windows)] { + expected.retain(|p| p.file_stem().unwrap() == BIN_NAME); expected.retain(|p| p.extension().map(|ext| ext == "exe" || ext == "cmd") == Some(true)); } #[cfg(not(windows))] |