//! which //! //! A Rust equivalent of Unix command `which(1)`. //! # Example: //! //! To find which rustc executable binary is using: //! //! ```no_run //! use which::which; //! use std::path::PathBuf; //! //! let result = which::which("rustc").unwrap(); //! assert_eq!(result, PathBuf::from("/usr/bin/rustc")); //! //! ``` mod checker; mod error; mod finder; #[cfg(windows)] mod helper; use std::env; use std::fmt; use std::path; use std::ffi::OsStr; use crate::checker::{CompositeChecker, ExecutableChecker, ExistedChecker}; pub use crate::error::*; use crate::finder::Finder; /// Find a exectable binary's path by name. /// /// If given an absolute path, returns it if the file exists and is executable. /// /// If given a relative path, returns an absolute path to the file if /// it exists and is executable. /// /// 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("rustc").unwrap(); /// assert_eq!(result, PathBuf::from("/usr/bin/rustc")); /// /// ``` pub fn which>(binary_name: T) -> Result { 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>(binary_name: T) -> Result> { let cwd = env::current_dir().map_err(|_| Error::CannotGetCurrentDir)?; 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(binary_name: T, paths: Option, cwd: V) -> Result where T: AsRef, U: AsRef, V: AsRef, { 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( binary_name: T, paths: Option, cwd: V, ) -> Result> where T: AsRef, U: AsRef, V: AsRef, { 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) } /// 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 /// advantage of being a type distinct from `std::path::Path` and `std::path::PathBuf`. /// /// It can be beneficial to use `which::Path` instead of `std::path::Path` when you want the type /// system to enforce the need for a path that exists and points to a binary that is executable. /// /// 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)] pub struct Path { inner: path::PathBuf, } impl Path { /// Returns the path of an executable binary by name. /// /// This calls `which` and maps the result into a `Path`. pub fn new>(binary_name: T) -> Result { 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>(binary_name: T) -> Result> { 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. /// /// This calls `which_in` and maps the result into a `Path`. pub fn new_in(binary_name: T, paths: Option, cwd: V) -> Result where T: AsRef, U: AsRef, V: AsRef, { 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( binary_name: T, paths: Option, cwd: V, ) -> Result> where T: AsRef, U: AsRef, V: AsRef, { 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() } /// Consumes the `which::Path`, yielding its underlying `std::path::PathBuf`. pub fn into_path_buf(self) -> path::PathBuf { self.inner } } impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.inner, f) } } impl std::ops::Deref for Path { type Target = path::Path; fn deref(&self) -> &path::Path { self.inner.deref() } } impl AsRef for Path { fn as_ref(&self) -> &path::Path { self.as_path() } } impl AsRef for Path { fn as_ref(&self) -> &OsStr { self.as_os_str() } } impl Eq for Path {} impl PartialEq for Path { fn eq(&self, other: &path::PathBuf) -> bool { self.inner == *other } } impl PartialEq for path::PathBuf { fn eq(&self, other: &Path) -> bool { *self == other.inner } } /// An owned, immutable wrapper around a `PathBuf` containing the _canonical_ path of an /// executable. /// /// The constructed `PathBuf` is the result of `which` or `which_in` followed by /// `Path::canonicalize`, but `CanonicalPath` has the advantage of being a type distinct from /// `std::path::Path` and `std::path::PathBuf`. /// /// It can be beneficial to use `CanonicalPath` instead of `std::path::Path` when you want the type /// system to enforce the need for a path that exists, points to a binary that is executable, is /// absolute, has all components normalized, and has all symbolic links resolved /// /// Since `CanonicalPath` implements `Deref` for `std::path::Path`, all methods on /// `&std::path::Path` are also available to `&CanonicalPath` values. #[derive(Clone, PartialEq)] pub struct CanonicalPath { inner: path::PathBuf, } impl CanonicalPath { /// Returns the canonical path of an executable binary by name. /// /// This calls `which` and `Path::canonicalize` and maps the result into a `CanonicalPath`. pub fn new>(binary_name: T) -> Result { which(binary_name) .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize)) .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>( binary_name: T, ) -> Result>> { 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_in` and `Path::canonicalize` and maps the result into a `CanonicalPath`. pub fn new_in(binary_name: T, paths: Option, cwd: V) -> Result where T: AsRef, U: AsRef, V: AsRef, { which_in(binary_name, paths, cwd) .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize)) .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( binary_name: T, paths: Option, cwd: V, ) -> Result>> where T: AsRef, U: AsRef, V: AsRef, { 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() } /// Consumes the `which::CanonicalPath`, yielding its underlying `std::path::PathBuf`. pub fn into_path_buf(self) -> path::PathBuf { self.inner } } impl fmt::Debug for CanonicalPath { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.inner, f) } } impl std::ops::Deref for CanonicalPath { type Target = path::Path; fn deref(&self) -> &path::Path { self.inner.deref() } } impl AsRef for CanonicalPath { fn as_ref(&self) -> &path::Path { self.as_path() } } impl AsRef for CanonicalPath { fn as_ref(&self) -> &OsStr { self.as_os_str() } } impl Eq for CanonicalPath {} impl PartialEq for CanonicalPath { fn eq(&self, other: &path::PathBuf) -> bool { self.inner == *other } } impl PartialEq for path::PathBuf { fn eq(&self, other: &CanonicalPath) -> bool { *self == other.inner } }