aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:07:41 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:07:41 +0000
commit223666ff9cc4ec72ae625ee348e1e7e90d386703 (patch)
treebb7fed649d07e5b24e581d19ccf3c547b2b86c62
parente42091b9afa8b1d9cb0d0418bba7a2b1e23eeca8 (diff)
parent878f532dd57bdcbce44364b7eecb1811140e99b7 (diff)
downloadwhich-android14-mainline-os-statsd-release.tar.gz
Change-Id: I7dfb065f060cc66a8e522bb9cc42ae35e957cd5d
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/rust.yml6
-rw-r--r--Android.bp9
-rw-r--r--Cargo.toml30
-rw-r--r--Cargo.toml.orig12
-rw-r--r--METADATA14
-rw-r--r--TEST_MAPPING14
-rw-r--r--src/checker.rs4
-rw-r--r--src/finder.rs98
-rw-r--r--src/lib.rs231
-rw-r--r--tests/basic.rs65
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
diff --git a/Android.bp b/Android.bp
index 3d469f9..22790af 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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,
}
diff --git a/Cargo.toml b/Cargo.toml
index 850a29c..ff6894a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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
diff --git a/METADATA b/METADATA
index 6a034c4..d2123d9 100644
--- a/METADATA
+++ b/METADATA
@@ -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
+}
diff --git a/src/lib.rs b/src/lib.rs
index 2b27094..3e556eb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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))]