| //! 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("rustc").unwrap(); |
| //! assert_eq!(result, PathBuf::from("/usr/bin/rustc")); |
| //! |
| //! ``` |
| |
| #[cfg(windows)] |
| #[macro_use] |
| extern crate lazy_static; |
| |
| mod checker; |
| mod error; |
| mod finder; |
| #[cfg(windows)] |
| 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 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<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().ok(); |
| |
| let binary_checker = build_binary_checker(); |
| |
| let finder = Finder::new(); |
| |
| finder.find(binary_name, env::var_os("PATH"), cwd, binary_checker) |
| } |
| |
| /// Find all binaries matching a regular expression in a the system PATH. |
| /// |
| /// Only available when feature `regex` is enabled. |
| /// |
| /// # Arguments |
| /// |
| /// * `regex` - A regular expression to match binaries with |
| /// |
| /// # Examples |
| /// |
| /// Find Python executables: |
| /// |
| /// ```no_run |
| /// use regex::Regex; |
| /// use which::which; |
| /// use std::path::PathBuf; |
| /// |
| /// let re = Regex::new(r"python\d$").unwrap(); |
| /// let binaries: Vec<PathBuf> = which::which_re(re).unwrap().collect(); |
| /// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")]; |
| /// assert_eq!(binaries, python_paths); |
| /// ``` |
| /// |
| /// Find all cargo subcommand executables on the path: |
| /// |
| /// ``` |
| /// use which::which_re; |
| /// use regex::Regex; |
| /// |
| /// which_re(Regex::new("^cargo-.*").unwrap()).unwrap() |
| /// .for_each(|pth| println!("{}", pth.to_string_lossy())); |
| /// ``` |
| #[cfg(feature = "regex")] |
| pub fn which_re(regex: impl Borrow<Regex>) -> Result<impl Iterator<Item = path::PathBuf>> { |
| which_re_in(regex, env::var_os("PATH")) |
| } |
| |
| /// 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 matching a regular expression in a list of paths. |
| /// |
| /// Only available when feature `regex` is enabled. |
| /// |
| /// # Arguments |
| /// |
| /// * `regex` - A regular expression to match binaries with |
| /// * `paths` - A string containing the paths to search |
| /// (separated in the same way as the PATH environment variable) |
| /// |
| /// # Examples |
| /// |
| /// ```no_run |
| /// use regex::Regex; |
| /// use which::which; |
| /// use std::path::PathBuf; |
| /// |
| /// let re = Regex::new(r"python\d$").unwrap(); |
| /// let paths = Some("/usr/bin:/usr/local/bin"); |
| /// let binaries: Vec<PathBuf> = which::which_re_in(re, paths).unwrap().collect(); |
| /// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")]; |
| /// assert_eq!(binaries, python_paths); |
| /// ``` |
| #[cfg(feature = "regex")] |
| pub fn which_re_in<T>( |
| regex: impl Borrow<Regex>, |
| paths: Option<T>, |
| ) -> Result<impl Iterator<Item = path::PathBuf>> |
| where |
| T: AsRef<OsStr>, |
| { |
| let binary_checker = build_binary_checker(); |
| |
| let finder = Finder::new(); |
| |
| finder.find_re(regex, paths, binary_checker) |
| } |
| |
| /// 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 = build_binary_checker(); |
| |
| let finder = Finder::new(); |
| |
| finder.find(binary_name, paths, Some(cwd), binary_checker) |
| } |
| |
| fn build_binary_checker() -> CompositeChecker { |
| CompositeChecker::new() |
| .add_checker(Box::new(ExistedChecker::new())) |
| .add_checker(Box::new(ExecutableChecker::new())) |
| } |
| |
| /// 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<T: AsRef<OsStr>>(binary_name: T) -> Result<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. |
| /// |
| /// This calls `which_in` and maps the result into a `Path`. |
| pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<Path> |
| where |
| T: AsRef<OsStr>, |
| U: AsRef<OsStr>, |
| V: AsRef<path::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() |
| } |
| |
| /// 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<path::Path> for Path { |
| fn as_ref(&self) -> &path::Path { |
| self.as_path() |
| } |
| } |
| |
| impl AsRef<OsStr> for Path { |
| fn as_ref(&self) -> &OsStr { |
| self.as_os_str() |
| } |
| } |
| |
| impl Eq for Path {} |
| |
| impl PartialEq<path::PathBuf> for Path { |
| fn eq(&self, other: &path::PathBuf) -> bool { |
| self.inner == *other |
| } |
| } |
| |
| impl PartialEq<Path> 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<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath> { |
| 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<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_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>, |
| U: AsRef<OsStr>, |
| V: AsRef<path::Path>, |
| { |
| 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<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() |
| } |
| |
| /// 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<path::Path> for CanonicalPath { |
| fn as_ref(&self) -> &path::Path { |
| self.as_path() |
| } |
| } |
| |
| impl AsRef<OsStr> for CanonicalPath { |
| fn as_ref(&self) -> &OsStr { |
| self.as_os_str() |
| } |
| } |
| |
| impl Eq for CanonicalPath {} |
| |
| impl PartialEq<path::PathBuf> for CanonicalPath { |
| fn eq(&self, other: &path::PathBuf) -> bool { |
| self.inner == *other |
| } |
| } |
| |
| impl PartialEq<CanonicalPath> for path::PathBuf { |
| fn eq(&self, other: &CanonicalPath) -> bool { |
| *self == other.inner |
| } |
| } |