aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/checker.rs2
-rw-r--r--src/error.rs23
-rw-r--r--src/finder.rs29
-rw-r--r--src/lib.rs106
4 files changed, 120 insertions, 40 deletions
diff --git a/src/checker.rs b/src/checker.rs
index 94ef31a..62b78a2 100644
--- a/src/checker.rs
+++ b/src/checker.rs
@@ -1,4 +1,4 @@
-use finder::Checker;
+use crate::finder::Checker;
#[cfg(unix)]
use libc;
#[cfg(unix)]
diff --git a/src/error.rs b/src/error.rs
index 708c884..6d800a6 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,17 +1,26 @@
-use thiserror;
+use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
-#[derive(thiserror::Error, Copy, Clone, Eq, PartialEq, Debug)]
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Error {
- #[error("bad absolute path")]
BadAbsolutePath,
- #[error("bad relative path")]
BadRelativePath,
- #[error("cannot find binary path")]
CannotFindBinaryPath,
- #[error("cannot get current directory")]
CannotGetCurrentDir,
- #[error("cannot canonicalize path")]
CannotCanonicalize,
}
+
+impl std::error::Error for Error {}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Error::BadAbsolutePath => write!(f, "bad absolute path"),
+ Error::BadRelativePath => write!(f, "bad relative path"),
+ Error::CannotFindBinaryPath => write!(f, "cannot find binary path"),
+ Error::CannotGetCurrentDir => write!(f, "cannot get current directory"),
+ Error::CannotCanonicalize => write!(f, "cannot canonicalize path"),
+ }
+ }
+}
diff --git a/src/finder.rs b/src/finder.rs
index d23cbaa..91c6cab 100644
--- a/src/finder.rs
+++ b/src/finder.rs
@@ -1,6 +1,8 @@
-use error::*;
+use crate::checker::CompositeChecker;
+use crate::error::*;
+use either::Either;
#[cfg(windows)]
-use helper::has_executable_extension;
+use crate::helper::has_executable_extension;
use std::env;
use std::ffi::OsStr;
#[cfg(windows)]
@@ -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,18 @@ 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>
diff --git a/src/lib.rs b/src/lib.rs
index 8ea0e7e..4aea3e6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,17 +5,15 @@
//!
//! To find which rustc executable binary is using:
//!
-//! ``` norun
+//! ```no_run
//! use which::which;
+//! use std::path::PathBuf;
//!
//! let result = which::which("rustc").unwrap();
//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
//!
//! ```
-extern crate libc;
-extern crate thiserror;
-
mod checker;
mod error;
mod finder;
@@ -28,11 +26,9 @@ use std::path;
use std::ffi::OsStr;
-use checker::CompositeChecker;
-use checker::ExecutableChecker;
-use checker::ExistedChecker;
-pub use error::*;
-use finder::Finder;
+use crate::checker::{CompositeChecker, ExecutableChecker, ExistedChecker};
+pub use crate::error::*;
+use crate::finder::Finder;
/// Find a exectable binary's path by name.
///
@@ -47,7 +43,7 @@ use finder::Finder;
///
/// # Example
///
-/// ``` norun
+/// ```no_run
/// use which::which;
/// use std::path::PathBuf;
///
@@ -56,9 +52,14 @@ 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.
@@ -68,13 +69,28 @@ where
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>,
+ V: AsRef<path::Path>,
+{
let binary_checker = CompositeChecker::new()
.add_checker(Box::new(ExistedChecker::new()))
.add_checker(Box::new(ExecutableChecker::new()));
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.
@@ -100,6 +116,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.
///
@@ -113,6 +136,23 @@ 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()
@@ -192,10 +232,26 @@ 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>,
@@ -207,6 +263,30 @@ 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()