mirror of
https://gitee.com/openharmony/third_party_rust_which-rs
synced 2024-11-27 09:40:44 +00:00
Add support for finding all binaries with said name on path
This commit is contained in:
parent
3c34de1617
commit
84446f2862
@ -11,6 +11,7 @@ categories = ["os", "filesystem"]
|
||||
keywords = ["which", "which-rs", "unix", "command"]
|
||||
|
||||
[dependencies]
|
||||
either = "1.6"
|
||||
libc = "0.2.65"
|
||||
thiserror = "1.0"
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use either::Either;
|
||||
use error::*;
|
||||
#[cfg(windows)]
|
||||
use helper::has_executable_extension;
|
||||
@ -7,6 +8,7 @@ use std::ffi::OsStr;
|
||||
use std::ffi::OsString;
|
||||
use std::iter;
|
||||
use std::path::{Path, PathBuf};
|
||||
use checker::CompositeChecker;
|
||||
|
||||
pub trait Checker {
|
||||
fn is_valid(&self, path: &Path) -> bool;
|
||||
@ -51,8 +53,8 @@ impl Finder {
|
||||
binary_name: T,
|
||||
paths: Option<U>,
|
||||
cwd: V,
|
||||
binary_checker: &dyn Checker,
|
||||
) -> Result<PathBuf>
|
||||
binary_checker: CompositeChecker,
|
||||
) -> Result<impl Iterator<Item = PathBuf>>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
U: AsRef<OsStr>,
|
||||
@ -60,29 +62,21 @@ impl Finder {
|
||||
{
|
||||
let path = PathBuf::from(&binary_name);
|
||||
|
||||
let binary_path_candidates: Box<dyn Iterator<Item = _>> = if path.has_separator() {
|
||||
let binary_path_candidates = if path.has_separator() {
|
||||
// Search binary in cwd if the path have a path separator.
|
||||
let candidates = Self::cwd_search_candidates(path, cwd).into_iter();
|
||||
Box::new(candidates)
|
||||
Either::Left(Self::cwd_search_candidates(path, cwd).into_iter())
|
||||
} else {
|
||||
// Search binary in PATHs(defined in environment variable).
|
||||
let p = paths.ok_or(Error::CannotFindBinaryPath)?;
|
||||
let paths: Vec<_> = env::split_paths(&p).collect();
|
||||
|
||||
let candidates = Self::path_search_candidates(path, paths).into_iter();
|
||||
|
||||
Box::new(candidates)
|
||||
Either::Right(Self::path_search_candidates(path, paths).into_iter())
|
||||
};
|
||||
|
||||
for p in binary_path_candidates {
|
||||
// find a valid binary
|
||||
if binary_checker.is_valid(&p) {
|
||||
return Ok(p);
|
||||
}
|
||||
}
|
||||
|
||||
// can't find any binary
|
||||
Err(Error::CannotFindBinaryPath)
|
||||
Ok(
|
||||
binary_path_candidates
|
||||
.filter(move |p| binary_checker.is_valid(p))
|
||||
)
|
||||
}
|
||||
|
||||
fn cwd_search_candidates<C>(binary_name: PathBuf, cwd: C) -> impl IntoIterator<Item = PathBuf>
|
||||
|
70
src/lib.rs
70
src/lib.rs
@ -14,6 +14,7 @@
|
||||
//!
|
||||
//! ```
|
||||
|
||||
extern crate either;
|
||||
extern crate libc;
|
||||
extern crate thiserror;
|
||||
|
||||
@ -57,13 +58,28 @@ use finder::Finder;
|
||||
///
|
||||
/// ```
|
||||
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.
|
||||
pub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item=path::PathBuf>> {
|
||||
let cwd = env::current_dir().map_err(|_| Error::CannotGetCurrentDir)?;
|
||||
|
||||
which_in(binary_name, env::var_os("PATH"), &cwd)
|
||||
which_in_all(binary_name, env::var_os("PATH"), cwd)
|
||||
}
|
||||
|
||||
/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
|
||||
pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<path::PathBuf>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
U: AsRef<OsStr>,
|
||||
V: AsRef<path::Path>,
|
||||
{
|
||||
which_in_all(binary_name, paths, cwd).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.
|
||||
pub fn which_in_all<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<impl Iterator<Item=path::PathBuf>>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
U: AsRef<OsStr>,
|
||||
@ -75,7 +91,7 @@ where
|
||||
|
||||
let finder = Finder::new();
|
||||
|
||||
finder.find(binary_name, paths, cwd, &binary_checker)
|
||||
finder.find(binary_name, paths, cwd, binary_checker)
|
||||
}
|
||||
|
||||
/// An owned, immutable wrapper around a `PathBuf` containing the path of an executable.
|
||||
@ -101,6 +117,13 @@ impl Path {
|
||||
which(binary_name).map(|inner| Path { inner })
|
||||
}
|
||||
|
||||
/// Returns the paths of all executable binaries by a name.
|
||||
///
|
||||
/// this calls `which_all` and maps the results into `Path`s.
|
||||
pub fn all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item=Path>> {
|
||||
which_all(binary_name).map(|inner| inner.map(|inner| Path { inner }))
|
||||
}
|
||||
|
||||
/// Returns the path of an executable binary by name in the path list `paths` and using the
|
||||
/// current working directory `cwd` to resolve relative paths.
|
||||
///
|
||||
@ -114,6 +137,19 @@ impl Path {
|
||||
which_in(binary_name, paths, cwd).map(|inner| Path { inner })
|
||||
}
|
||||
|
||||
/// Returns all paths of an executable binary by name in the path list `paths` and using the
|
||||
/// current working directory `cwd` to resolve relative paths.
|
||||
///
|
||||
/// This calls `which_in_all` and maps the results into a `Path`.
|
||||
pub fn all_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<impl Iterator<Item=Path>>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
U: AsRef<OsStr>,
|
||||
V: AsRef<path::Path>,
|
||||
{
|
||||
which_in_all(binary_name, paths, cwd).map(|inner| inner.map(|inner| Path { inner }))
|
||||
}
|
||||
|
||||
/// Returns a reference to a `std::path::Path`.
|
||||
pub fn as_path(&self) -> &path::Path {
|
||||
self.inner.as_path()
|
||||
@ -193,10 +229,21 @@ impl CanonicalPath {
|
||||
.map(|inner| CanonicalPath { inner })
|
||||
}
|
||||
|
||||
/// Returns the canonical paths of an executable binary by name.
|
||||
///
|
||||
/// This calls `which_all` and `Path::canonicalize` and maps the results into `CanonicalPath`s.
|
||||
pub fn all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item=Result<CanonicalPath>>> {
|
||||
which_all(binary_name)
|
||||
.map(|inner| inner.map(|inner|
|
||||
inner.canonicalize().map_err(|_| Error::CannotCanonicalize)
|
||||
.map(|inner| CanonicalPath { inner })
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns the canonical path of an executable binary by name in the path list `paths` and
|
||||
/// using the current working directory `cwd` to resolve relative paths.
|
||||
///
|
||||
/// This calls `which` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
|
||||
/// This calls `which_in` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
|
||||
pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<CanonicalPath>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
@ -208,6 +255,23 @@ impl CanonicalPath {
|
||||
.map(|inner| CanonicalPath { inner })
|
||||
}
|
||||
|
||||
/// Returns all of the canonical paths of an executable binary by name in the path list `paths` and
|
||||
/// using the current working directory `cwd` to resolve relative paths.
|
||||
///
|
||||
/// This calls `which_in_all` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
|
||||
pub fn all_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<impl Iterator<Item=Result<CanonicalPath>>>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
U: AsRef<OsStr>,
|
||||
V: AsRef<path::Path>,
|
||||
{
|
||||
which_in_all(binary_name, paths, cwd)
|
||||
.map(|inner| inner.map(|inner|
|
||||
inner.canonicalize().map_err(|_| Error::CannotCanonicalize)
|
||||
.map(|inner| CanonicalPath { inner })
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns a reference to a `std::path::Path`.
|
||||
pub fn as_path(&self) -> &path::Path {
|
||||
self.inner.as_path()
|
||||
|
@ -87,6 +87,10 @@ 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, 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())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn it_works() {
|
||||
@ -147,6 +151,20 @@ fn test_which_second() {
|
||||
assert_eq!(_which(&f, "another").unwrap(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_which_all() {
|
||||
let f = TestFixture::new();
|
||||
let actual = _which_all(&f, BIN_NAME).unwrap().map(|c| c.unwrap()).collect::<Vec<_>>();
|
||||
let mut expected = f.bins.iter().map(|p| p.canonicalize().unwrap()).collect::<Vec<_>>();
|
||||
#[cfg(windows)] {
|
||||
expected.retain(|p| p.extension().map(|ext| ext == "exe" || ext == "cmd") == Some(true));
|
||||
}
|
||||
#[cfg(not(windows))] {
|
||||
expected.retain(|p| p.file_name().unwrap() == BIN_NAME);
|
||||
}
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_which_absolute() {
|
||||
|
Loading…
Reference in New Issue
Block a user