1b3ba51a1Sopenharmony_ci//! which 2b3ba51a1Sopenharmony_ci//! 3b3ba51a1Sopenharmony_ci//! A Rust equivalent of Unix command `which(1)`. 4b3ba51a1Sopenharmony_ci//! # Example: 5b3ba51a1Sopenharmony_ci//! 6b3ba51a1Sopenharmony_ci//! To find which rustc executable binary is using: 7b3ba51a1Sopenharmony_ci//! 8b3ba51a1Sopenharmony_ci//! ```no_run 9b3ba51a1Sopenharmony_ci//! use which::which; 10b3ba51a1Sopenharmony_ci//! use std::path::PathBuf; 11b3ba51a1Sopenharmony_ci//! 12b3ba51a1Sopenharmony_ci//! let result = which("rustc").unwrap(); 13b3ba51a1Sopenharmony_ci//! assert_eq!(result, PathBuf::from("/usr/bin/rustc")); 14b3ba51a1Sopenharmony_ci//! 15b3ba51a1Sopenharmony_ci//! ``` 16b3ba51a1Sopenharmony_ci 17b3ba51a1Sopenharmony_cimod checker; 18b3ba51a1Sopenharmony_cimod error; 19b3ba51a1Sopenharmony_cimod finder; 20b3ba51a1Sopenharmony_ci#[cfg(windows)] 21b3ba51a1Sopenharmony_cimod helper; 22b3ba51a1Sopenharmony_ci 23b3ba51a1Sopenharmony_ci#[cfg(feature = "regex")] 24b3ba51a1Sopenharmony_ciuse std::borrow::Borrow; 25b3ba51a1Sopenharmony_ciuse std::env; 26b3ba51a1Sopenharmony_ciuse std::fmt; 27b3ba51a1Sopenharmony_ciuse std::path; 28b3ba51a1Sopenharmony_ci 29b3ba51a1Sopenharmony_ciuse std::ffi::{OsStr, OsString}; 30b3ba51a1Sopenharmony_ci 31b3ba51a1Sopenharmony_ciuse crate::checker::{CompositeChecker, ExecutableChecker, ExistedChecker}; 32b3ba51a1Sopenharmony_cipub use crate::error::*; 33b3ba51a1Sopenharmony_ciuse crate::finder::Finder; 34b3ba51a1Sopenharmony_ci 35b3ba51a1Sopenharmony_ci/// Find an executable binary's path by name. 36b3ba51a1Sopenharmony_ci/// 37b3ba51a1Sopenharmony_ci/// If given an absolute path, returns it if the file exists and is executable. 38b3ba51a1Sopenharmony_ci/// 39b3ba51a1Sopenharmony_ci/// If given a relative path, returns an absolute path to the file if 40b3ba51a1Sopenharmony_ci/// it exists and is executable. 41b3ba51a1Sopenharmony_ci/// 42b3ba51a1Sopenharmony_ci/// If given a string without path separators, looks for a file named 43b3ba51a1Sopenharmony_ci/// `binary_name` at each directory in `$PATH` and if it finds an executable 44b3ba51a1Sopenharmony_ci/// file there, returns it. 45b3ba51a1Sopenharmony_ci/// 46b3ba51a1Sopenharmony_ci/// # Example 47b3ba51a1Sopenharmony_ci/// 48b3ba51a1Sopenharmony_ci/// ```no_run 49b3ba51a1Sopenharmony_ci/// use which::which; 50b3ba51a1Sopenharmony_ci/// use std::path::PathBuf; 51b3ba51a1Sopenharmony_ci/// 52b3ba51a1Sopenharmony_ci/// let result = which::which("rustc").unwrap(); 53b3ba51a1Sopenharmony_ci/// assert_eq!(result, PathBuf::from("/usr/bin/rustc")); 54b3ba51a1Sopenharmony_ci/// 55b3ba51a1Sopenharmony_ci/// ``` 56b3ba51a1Sopenharmony_cipub fn which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> { 57b3ba51a1Sopenharmony_ci which_all(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath)) 58b3ba51a1Sopenharmony_ci} 59b3ba51a1Sopenharmony_ci 60b3ba51a1Sopenharmony_ci/// Find an executable binary's path by name, ignoring `cwd`. 61b3ba51a1Sopenharmony_ci/// 62b3ba51a1Sopenharmony_ci/// If given an absolute path, returns it if the file exists and is executable. 63b3ba51a1Sopenharmony_ci/// 64b3ba51a1Sopenharmony_ci/// Does not resolve relative paths. 65b3ba51a1Sopenharmony_ci/// 66b3ba51a1Sopenharmony_ci/// If given a string without path separators, looks for a file named 67b3ba51a1Sopenharmony_ci/// `binary_name` at each directory in `$PATH` and if it finds an executable 68b3ba51a1Sopenharmony_ci/// file there, returns it. 69b3ba51a1Sopenharmony_ci/// 70b3ba51a1Sopenharmony_ci/// # Example 71b3ba51a1Sopenharmony_ci/// 72b3ba51a1Sopenharmony_ci/// ```no_run 73b3ba51a1Sopenharmony_ci/// use which::which; 74b3ba51a1Sopenharmony_ci/// use std::path::PathBuf; 75b3ba51a1Sopenharmony_ci/// 76b3ba51a1Sopenharmony_ci/// let result = which::which_global("rustc").unwrap(); 77b3ba51a1Sopenharmony_ci/// assert_eq!(result, PathBuf::from("/usr/bin/rustc")); 78b3ba51a1Sopenharmony_ci/// 79b3ba51a1Sopenharmony_ci/// ``` 80b3ba51a1Sopenharmony_cipub fn which_global<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> { 81b3ba51a1Sopenharmony_ci which_all_global(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath)) 82b3ba51a1Sopenharmony_ci} 83b3ba51a1Sopenharmony_ci 84b3ba51a1Sopenharmony_ci/// Find all binaries with `binary_name` using `cwd` to resolve relative paths. 85b3ba51a1Sopenharmony_cipub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = path::PathBuf>> { 86b3ba51a1Sopenharmony_ci let cwd = env::current_dir().ok(); 87b3ba51a1Sopenharmony_ci 88b3ba51a1Sopenharmony_ci let binary_checker = build_binary_checker(); 89b3ba51a1Sopenharmony_ci 90b3ba51a1Sopenharmony_ci let finder = Finder::new(); 91b3ba51a1Sopenharmony_ci 92b3ba51a1Sopenharmony_ci finder.find(binary_name, env::var_os("PATH"), cwd, binary_checker) 93b3ba51a1Sopenharmony_ci} 94b3ba51a1Sopenharmony_ci 95b3ba51a1Sopenharmony_ci/// Find all binaries with `binary_name` ignoring `cwd`. 96b3ba51a1Sopenharmony_cipub fn which_all_global<T: AsRef<OsStr>>( 97b3ba51a1Sopenharmony_ci binary_name: T, 98b3ba51a1Sopenharmony_ci) -> Result<impl Iterator<Item = path::PathBuf>> { 99b3ba51a1Sopenharmony_ci let binary_checker = build_binary_checker(); 100b3ba51a1Sopenharmony_ci 101b3ba51a1Sopenharmony_ci let finder = Finder::new(); 102b3ba51a1Sopenharmony_ci 103b3ba51a1Sopenharmony_ci finder.find( 104b3ba51a1Sopenharmony_ci binary_name, 105b3ba51a1Sopenharmony_ci env::var_os("PATH"), 106b3ba51a1Sopenharmony_ci Option::<&Path>::None, 107b3ba51a1Sopenharmony_ci binary_checker, 108b3ba51a1Sopenharmony_ci ) 109b3ba51a1Sopenharmony_ci} 110b3ba51a1Sopenharmony_ci 111b3ba51a1Sopenharmony_ci/// Find all binaries matching a regular expression in a the system PATH. 112b3ba51a1Sopenharmony_ci/// 113b3ba51a1Sopenharmony_ci/// Only available when feature `regex` is enabled. 114b3ba51a1Sopenharmony_ci/// 115b3ba51a1Sopenharmony_ci/// # Arguments 116b3ba51a1Sopenharmony_ci/// 117b3ba51a1Sopenharmony_ci/// * `regex` - A regular expression to match binaries with 118b3ba51a1Sopenharmony_ci/// 119b3ba51a1Sopenharmony_ci/// # Examples 120b3ba51a1Sopenharmony_ci/// 121b3ba51a1Sopenharmony_ci/// Find Python executables: 122b3ba51a1Sopenharmony_ci/// 123b3ba51a1Sopenharmony_ci/// ```no_run 124b3ba51a1Sopenharmony_ci/// use regex::Regex; 125b3ba51a1Sopenharmony_ci/// use which::which; 126b3ba51a1Sopenharmony_ci/// use std::path::PathBuf; 127b3ba51a1Sopenharmony_ci/// 128b3ba51a1Sopenharmony_ci/// let re = Regex::new(r"python\d$").unwrap(); 129b3ba51a1Sopenharmony_ci/// let binaries: Vec<PathBuf> = which::which_re(re).unwrap().collect(); 130b3ba51a1Sopenharmony_ci/// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")]; 131b3ba51a1Sopenharmony_ci/// assert_eq!(binaries, python_paths); 132b3ba51a1Sopenharmony_ci/// ``` 133b3ba51a1Sopenharmony_ci/// 134b3ba51a1Sopenharmony_ci/// Find all cargo subcommand executables on the path: 135b3ba51a1Sopenharmony_ci/// 136b3ba51a1Sopenharmony_ci/// ``` 137b3ba51a1Sopenharmony_ci/// use which::which_re; 138b3ba51a1Sopenharmony_ci/// use regex::Regex; 139b3ba51a1Sopenharmony_ci/// 140b3ba51a1Sopenharmony_ci/// which_re(Regex::new("^cargo-.*").unwrap()).unwrap() 141b3ba51a1Sopenharmony_ci/// .for_each(|pth| println!("{}", pth.to_string_lossy())); 142b3ba51a1Sopenharmony_ci/// ``` 143b3ba51a1Sopenharmony_ci#[cfg(feature = "regex")] 144b3ba51a1Sopenharmony_cipub fn which_re(regex: impl Borrow<Regex>) -> Result<impl Iterator<Item = path::PathBuf>> { 145b3ba51a1Sopenharmony_ci which_re_in(regex, env::var_os("PATH")) 146b3ba51a1Sopenharmony_ci} 147b3ba51a1Sopenharmony_ci 148b3ba51a1Sopenharmony_ci/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths. 149b3ba51a1Sopenharmony_cipub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<path::PathBuf> 150b3ba51a1Sopenharmony_ciwhere 151b3ba51a1Sopenharmony_ci T: AsRef<OsStr>, 152b3ba51a1Sopenharmony_ci U: AsRef<OsStr>, 153b3ba51a1Sopenharmony_ci V: AsRef<path::Path>, 154b3ba51a1Sopenharmony_ci{ 155b3ba51a1Sopenharmony_ci which_in_all(binary_name, paths, cwd) 156b3ba51a1Sopenharmony_ci .and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath)) 157b3ba51a1Sopenharmony_ci} 158b3ba51a1Sopenharmony_ci 159b3ba51a1Sopenharmony_ci/// Find all binaries matching a regular expression in a list of paths. 160b3ba51a1Sopenharmony_ci/// 161b3ba51a1Sopenharmony_ci/// Only available when feature `regex` is enabled. 162b3ba51a1Sopenharmony_ci/// 163b3ba51a1Sopenharmony_ci/// # Arguments 164b3ba51a1Sopenharmony_ci/// 165b3ba51a1Sopenharmony_ci/// * `regex` - A regular expression to match binaries with 166b3ba51a1Sopenharmony_ci/// * `paths` - A string containing the paths to search 167b3ba51a1Sopenharmony_ci/// (separated in the same way as the PATH environment variable) 168b3ba51a1Sopenharmony_ci/// 169b3ba51a1Sopenharmony_ci/// # Examples 170b3ba51a1Sopenharmony_ci/// 171b3ba51a1Sopenharmony_ci/// ```no_run 172b3ba51a1Sopenharmony_ci/// use regex::Regex; 173b3ba51a1Sopenharmony_ci/// use which::which; 174b3ba51a1Sopenharmony_ci/// use std::path::PathBuf; 175b3ba51a1Sopenharmony_ci/// 176b3ba51a1Sopenharmony_ci/// let re = Regex::new(r"python\d$").unwrap(); 177b3ba51a1Sopenharmony_ci/// let paths = Some("/usr/bin:/usr/local/bin"); 178b3ba51a1Sopenharmony_ci/// let binaries: Vec<PathBuf> = which::which_re_in(re, paths).unwrap().collect(); 179b3ba51a1Sopenharmony_ci/// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")]; 180b3ba51a1Sopenharmony_ci/// assert_eq!(binaries, python_paths); 181b3ba51a1Sopenharmony_ci/// ``` 182b3ba51a1Sopenharmony_ci#[cfg(feature = "regex")] 183b3ba51a1Sopenharmony_cipub fn which_re_in<T>( 184b3ba51a1Sopenharmony_ci regex: impl Borrow<Regex>, 185b3ba51a1Sopenharmony_ci paths: Option<T>, 186b3ba51a1Sopenharmony_ci) -> Result<impl Iterator<Item = path::PathBuf>> 187b3ba51a1Sopenharmony_ciwhere 188b3ba51a1Sopenharmony_ci T: AsRef<OsStr>, 189b3ba51a1Sopenharmony_ci{ 190b3ba51a1Sopenharmony_ci let binary_checker = build_binary_checker(); 191b3ba51a1Sopenharmony_ci 192b3ba51a1Sopenharmony_ci let finder = Finder::new(); 193b3ba51a1Sopenharmony_ci 194b3ba51a1Sopenharmony_ci finder.find_re(regex, paths, binary_checker) 195b3ba51a1Sopenharmony_ci} 196b3ba51a1Sopenharmony_ci 197b3ba51a1Sopenharmony_ci/// Find all binaries with `binary_name` in the path list `paths`, using `cwd` to resolve relative paths. 198b3ba51a1Sopenharmony_cipub fn which_in_all<T, U, V>( 199b3ba51a1Sopenharmony_ci binary_name: T, 200b3ba51a1Sopenharmony_ci paths: Option<U>, 201b3ba51a1Sopenharmony_ci cwd: V, 202b3ba51a1Sopenharmony_ci) -> Result<impl Iterator<Item = path::PathBuf>> 203b3ba51a1Sopenharmony_ciwhere 204b3ba51a1Sopenharmony_ci T: AsRef<OsStr>, 205b3ba51a1Sopenharmony_ci U: AsRef<OsStr>, 206b3ba51a1Sopenharmony_ci V: AsRef<path::Path>, 207b3ba51a1Sopenharmony_ci{ 208b3ba51a1Sopenharmony_ci let binary_checker = build_binary_checker(); 209b3ba51a1Sopenharmony_ci 210b3ba51a1Sopenharmony_ci let finder = Finder::new(); 211b3ba51a1Sopenharmony_ci 212b3ba51a1Sopenharmony_ci finder.find(binary_name, paths, Some(cwd), binary_checker) 213b3ba51a1Sopenharmony_ci} 214b3ba51a1Sopenharmony_ci 215b3ba51a1Sopenharmony_ci/// Find all binaries with `binary_name` in the path list `paths`, ignoring `cwd`. 216b3ba51a1Sopenharmony_cipub fn which_in_global<T, U>( 217b3ba51a1Sopenharmony_ci binary_name: T, 218b3ba51a1Sopenharmony_ci paths: Option<U>, 219b3ba51a1Sopenharmony_ci) -> Result<impl Iterator<Item = path::PathBuf>> 220b3ba51a1Sopenharmony_ciwhere 221b3ba51a1Sopenharmony_ci T: AsRef<OsStr>, 222b3ba51a1Sopenharmony_ci U: AsRef<OsStr>, 223b3ba51a1Sopenharmony_ci{ 224b3ba51a1Sopenharmony_ci let binary_checker = build_binary_checker(); 225b3ba51a1Sopenharmony_ci 226b3ba51a1Sopenharmony_ci let finder = Finder::new(); 227b3ba51a1Sopenharmony_ci 228b3ba51a1Sopenharmony_ci finder.find(binary_name, paths, Option::<&Path>::None, binary_checker) 229b3ba51a1Sopenharmony_ci} 230b3ba51a1Sopenharmony_ci 231b3ba51a1Sopenharmony_cifn build_binary_checker() -> CompositeChecker { 232b3ba51a1Sopenharmony_ci CompositeChecker::new() 233b3ba51a1Sopenharmony_ci .add_checker(Box::new(ExistedChecker::new())) 234b3ba51a1Sopenharmony_ci .add_checker(Box::new(ExecutableChecker::new())) 235b3ba51a1Sopenharmony_ci} 236b3ba51a1Sopenharmony_ci 237b3ba51a1Sopenharmony_ci/// A wrapper containing all functionality in this crate. 238b3ba51a1Sopenharmony_cipub struct WhichConfig { 239b3ba51a1Sopenharmony_ci cwd: Option<either::Either<bool, path::PathBuf>>, 240b3ba51a1Sopenharmony_ci custom_path_list: Option<OsString>, 241b3ba51a1Sopenharmony_ci binary_name: Option<OsString>, 242b3ba51a1Sopenharmony_ci #[cfg(feature = "regex")] 243b3ba51a1Sopenharmony_ci regex: Option<Regex>, 244b3ba51a1Sopenharmony_ci} 245b3ba51a1Sopenharmony_ci 246b3ba51a1Sopenharmony_ciimpl Default for WhichConfig { 247b3ba51a1Sopenharmony_ci fn default() -> Self { 248b3ba51a1Sopenharmony_ci Self { 249b3ba51a1Sopenharmony_ci cwd: Some(either::Either::Left(true)), 250b3ba51a1Sopenharmony_ci custom_path_list: None, 251b3ba51a1Sopenharmony_ci binary_name: None, 252b3ba51a1Sopenharmony_ci #[cfg(feature = "regex")] 253b3ba51a1Sopenharmony_ci regex: None, 254b3ba51a1Sopenharmony_ci } 255b3ba51a1Sopenharmony_ci } 256b3ba51a1Sopenharmony_ci} 257b3ba51a1Sopenharmony_ci 258b3ba51a1Sopenharmony_ci#[cfg(feature = "regex")] 259b3ba51a1Sopenharmony_citype Regex = regex::Regex; 260b3ba51a1Sopenharmony_ci 261b3ba51a1Sopenharmony_ci#[cfg(not(feature = "regex"))] 262b3ba51a1Sopenharmony_citype Regex = (); 263b3ba51a1Sopenharmony_ci 264b3ba51a1Sopenharmony_ciimpl WhichConfig { 265b3ba51a1Sopenharmony_ci pub fn new() -> Self { 266b3ba51a1Sopenharmony_ci Self::default() 267b3ba51a1Sopenharmony_ci } 268b3ba51a1Sopenharmony_ci 269b3ba51a1Sopenharmony_ci /// Whether or not to use the current working directory. `true` by default. 270b3ba51a1Sopenharmony_ci /// 271b3ba51a1Sopenharmony_ci /// # Panics 272b3ba51a1Sopenharmony_ci /// 273b3ba51a1Sopenharmony_ci /// If regex was set previously, and you've just passed in `use_cwd: true`, this will panic. 274b3ba51a1Sopenharmony_ci pub fn system_cwd(mut self, use_cwd: bool) -> Self { 275b3ba51a1Sopenharmony_ci #[cfg(feature = "regex")] 276b3ba51a1Sopenharmony_ci if self.regex.is_some() && use_cwd { 277b3ba51a1Sopenharmony_ci panic!("which can't use regex and cwd at the same time!") 278b3ba51a1Sopenharmony_ci } 279b3ba51a1Sopenharmony_ci self.cwd = Some(either::Either::Left(use_cwd)); 280b3ba51a1Sopenharmony_ci self 281b3ba51a1Sopenharmony_ci } 282b3ba51a1Sopenharmony_ci 283b3ba51a1Sopenharmony_ci /// Sets a custom path for resolving relative paths. 284b3ba51a1Sopenharmony_ci /// 285b3ba51a1Sopenharmony_ci /// # Panics 286b3ba51a1Sopenharmony_ci /// 287b3ba51a1Sopenharmony_ci /// If regex was set previously, this will panic. 288b3ba51a1Sopenharmony_ci pub fn custom_cwd(mut self, cwd: path::PathBuf) -> Self { 289b3ba51a1Sopenharmony_ci #[cfg(feature = "regex")] 290b3ba51a1Sopenharmony_ci if self.regex.is_some() { 291b3ba51a1Sopenharmony_ci panic!("which can't use regex and cwd at the same time!") 292b3ba51a1Sopenharmony_ci } 293b3ba51a1Sopenharmony_ci self.cwd = Some(either::Either::Right(cwd)); 294b3ba51a1Sopenharmony_ci self 295b3ba51a1Sopenharmony_ci } 296b3ba51a1Sopenharmony_ci 297b3ba51a1Sopenharmony_ci /// Sets the path name regex to search for. You ***MUST*** call this, or [`Self::binary_name`] prior to searching. 298b3ba51a1Sopenharmony_ci /// 299b3ba51a1Sopenharmony_ci /// When `Regex` is disabled this function takes the unit type as a stand in. The parameter will change when 300b3ba51a1Sopenharmony_ci /// `Regex` is enabled. 301b3ba51a1Sopenharmony_ci /// 302b3ba51a1Sopenharmony_ci /// # Panics 303b3ba51a1Sopenharmony_ci /// 304b3ba51a1Sopenharmony_ci /// If the `regex` feature wasn't turned on for this crate this will always panic. Additionally if a 305b3ba51a1Sopenharmony_ci /// `cwd` (aka current working directory) or `binary_name` was set previously, this will panic, as those options 306b3ba51a1Sopenharmony_ci /// are incompatible with `regex`. 307b3ba51a1Sopenharmony_ci #[allow(unused_variables)] 308b3ba51a1Sopenharmony_ci pub fn regex(mut self, regex: Regex) -> Self { 309b3ba51a1Sopenharmony_ci #[cfg(not(feature = "regex"))] 310b3ba51a1Sopenharmony_ci { 311b3ba51a1Sopenharmony_ci panic!("which's regex feature was not enabled in your Cargo.toml!") 312b3ba51a1Sopenharmony_ci } 313b3ba51a1Sopenharmony_ci #[cfg(feature = "regex")] 314b3ba51a1Sopenharmony_ci { 315b3ba51a1Sopenharmony_ci if self.cwd != Some(either::Either::Left(false)) && self.cwd.is_some() { 316b3ba51a1Sopenharmony_ci panic!("which can't use regex and cwd at the same time!") 317b3ba51a1Sopenharmony_ci } 318b3ba51a1Sopenharmony_ci if self.binary_name.is_some() { 319b3ba51a1Sopenharmony_ci panic!("which can't use `binary_name` and `regex` at the same time!"); 320b3ba51a1Sopenharmony_ci } 321b3ba51a1Sopenharmony_ci self.regex = Some(regex); 322b3ba51a1Sopenharmony_ci self 323b3ba51a1Sopenharmony_ci } 324b3ba51a1Sopenharmony_ci } 325b3ba51a1Sopenharmony_ci 326b3ba51a1Sopenharmony_ci /// Sets the path name to search for. You ***MUST*** call this, or [`Self::regex`] prior to searching. 327b3ba51a1Sopenharmony_ci /// 328b3ba51a1Sopenharmony_ci /// # Panics 329b3ba51a1Sopenharmony_ci /// 330b3ba51a1Sopenharmony_ci /// If a `regex` was set previously this will panic as this is not compatible with `regex`. 331b3ba51a1Sopenharmony_ci pub fn binary_name(mut self, name: OsString) -> Self { 332b3ba51a1Sopenharmony_ci #[cfg(feature = "regex")] 333b3ba51a1Sopenharmony_ci if self.regex.is_some() { 334b3ba51a1Sopenharmony_ci panic!("which can't use `binary_name` and `regex` at the same time!"); 335b3ba51a1Sopenharmony_ci } 336b3ba51a1Sopenharmony_ci self.binary_name = Some(name); 337b3ba51a1Sopenharmony_ci self 338b3ba51a1Sopenharmony_ci } 339b3ba51a1Sopenharmony_ci 340b3ba51a1Sopenharmony_ci /// Uses the given string instead of the `PATH` env variable. 341b3ba51a1Sopenharmony_ci pub fn custom_path_list(mut self, custom_path_list: OsString) -> Self { 342b3ba51a1Sopenharmony_ci self.custom_path_list = Some(custom_path_list); 343b3ba51a1Sopenharmony_ci self 344b3ba51a1Sopenharmony_ci } 345b3ba51a1Sopenharmony_ci 346b3ba51a1Sopenharmony_ci /// Uses the `PATH` env variable. Enabled by default. 347b3ba51a1Sopenharmony_ci pub fn system_path_list(mut self) -> Self { 348b3ba51a1Sopenharmony_ci self.custom_path_list = None; 349b3ba51a1Sopenharmony_ci self 350b3ba51a1Sopenharmony_ci } 351b3ba51a1Sopenharmony_ci 352b3ba51a1Sopenharmony_ci /// Finishes configuring, runs the query and returns the first result. 353b3ba51a1Sopenharmony_ci pub fn first_result(self) -> Result<path::PathBuf> { 354b3ba51a1Sopenharmony_ci self.all_results() 355b3ba51a1Sopenharmony_ci .and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath)) 356b3ba51a1Sopenharmony_ci } 357b3ba51a1Sopenharmony_ci 358b3ba51a1Sopenharmony_ci /// Finishes configuring, runs the query and returns all results. 359b3ba51a1Sopenharmony_ci pub fn all_results(self) -> Result<impl Iterator<Item = path::PathBuf>> { 360b3ba51a1Sopenharmony_ci let binary_checker = build_binary_checker(); 361b3ba51a1Sopenharmony_ci 362b3ba51a1Sopenharmony_ci let finder = Finder::new(); 363b3ba51a1Sopenharmony_ci 364b3ba51a1Sopenharmony_ci let paths = self.custom_path_list.or_else(|| env::var_os("PATH")); 365b3ba51a1Sopenharmony_ci 366b3ba51a1Sopenharmony_ci #[cfg(feature = "regex")] 367b3ba51a1Sopenharmony_ci if let Some(regex) = self.regex { 368b3ba51a1Sopenharmony_ci return finder 369b3ba51a1Sopenharmony_ci .find_re(regex, paths, binary_checker) 370b3ba51a1Sopenharmony_ci .map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf>>); 371b3ba51a1Sopenharmony_ci } 372b3ba51a1Sopenharmony_ci 373b3ba51a1Sopenharmony_ci let cwd = match self.cwd { 374b3ba51a1Sopenharmony_ci Some(either::Either::Left(false)) => None, 375b3ba51a1Sopenharmony_ci Some(either::Either::Right(custom)) => Some(custom), 376b3ba51a1Sopenharmony_ci None | Some(either::Either::Left(true)) => env::current_dir().ok(), 377b3ba51a1Sopenharmony_ci }; 378b3ba51a1Sopenharmony_ci 379b3ba51a1Sopenharmony_ci finder 380b3ba51a1Sopenharmony_ci .find( 381b3ba51a1Sopenharmony_ci self.binary_name.expect( 382b3ba51a1Sopenharmony_ci "binary_name not set! You must set binary_name or regex before searching!", 383b3ba51a1Sopenharmony_ci ), 384b3ba51a1Sopenharmony_ci paths, 385b3ba51a1Sopenharmony_ci cwd, 386b3ba51a1Sopenharmony_ci binary_checker, 387b3ba51a1Sopenharmony_ci ) 388b3ba51a1Sopenharmony_ci .map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf>>) 389b3ba51a1Sopenharmony_ci } 390b3ba51a1Sopenharmony_ci} 391b3ba51a1Sopenharmony_ci 392b3ba51a1Sopenharmony_ci/// An owned, immutable wrapper around a `PathBuf` containing the path of an executable. 393b3ba51a1Sopenharmony_ci/// 394b3ba51a1Sopenharmony_ci/// The constructed `PathBuf` is the output of `which` or `which_in`, but `which::Path` has the 395b3ba51a1Sopenharmony_ci/// advantage of being a type distinct from `std::path::Path` and `std::path::PathBuf`. 396b3ba51a1Sopenharmony_ci/// 397b3ba51a1Sopenharmony_ci/// It can be beneficial to use `which::Path` instead of `std::path::Path` when you want the type 398b3ba51a1Sopenharmony_ci/// system to enforce the need for a path that exists and points to a binary that is executable. 399b3ba51a1Sopenharmony_ci/// 400b3ba51a1Sopenharmony_ci/// Since `which::Path` implements `Deref` for `std::path::Path`, all methods on `&std::path::Path` 401b3ba51a1Sopenharmony_ci/// are also available to `&which::Path` values. 402b3ba51a1Sopenharmony_ci#[derive(Clone, PartialEq, Eq)] 403b3ba51a1Sopenharmony_cipub struct Path { 404b3ba51a1Sopenharmony_ci inner: path::PathBuf, 405b3ba51a1Sopenharmony_ci} 406b3ba51a1Sopenharmony_ci 407b3ba51a1Sopenharmony_ciimpl Path { 408b3ba51a1Sopenharmony_ci /// Returns the path of an executable binary by name. 409b3ba51a1Sopenharmony_ci /// 410b3ba51a1Sopenharmony_ci /// This calls `which` and maps the result into a `Path`. 411b3ba51a1Sopenharmony_ci pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path> { 412b3ba51a1Sopenharmony_ci which(binary_name).map(|inner| Path { inner }) 413b3ba51a1Sopenharmony_ci } 414b3ba51a1Sopenharmony_ci 415b3ba51a1Sopenharmony_ci /// Returns the paths of all executable binaries by a name. 416b3ba51a1Sopenharmony_ci /// 417b3ba51a1Sopenharmony_ci /// this calls `which_all` and maps the results into `Path`s. 418b3ba51a1Sopenharmony_ci pub fn all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = Path>> { 419b3ba51a1Sopenharmony_ci which_all(binary_name).map(|inner| inner.map(|inner| Path { inner })) 420b3ba51a1Sopenharmony_ci } 421b3ba51a1Sopenharmony_ci 422b3ba51a1Sopenharmony_ci /// Returns the path of an executable binary by name in the path list `paths` and using the 423b3ba51a1Sopenharmony_ci /// current working directory `cwd` to resolve relative paths. 424b3ba51a1Sopenharmony_ci /// 425b3ba51a1Sopenharmony_ci /// This calls `which_in` and maps the result into a `Path`. 426b3ba51a1Sopenharmony_ci pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<Path> 427b3ba51a1Sopenharmony_ci where 428b3ba51a1Sopenharmony_ci T: AsRef<OsStr>, 429b3ba51a1Sopenharmony_ci U: AsRef<OsStr>, 430b3ba51a1Sopenharmony_ci V: AsRef<path::Path>, 431b3ba51a1Sopenharmony_ci { 432b3ba51a1Sopenharmony_ci which_in(binary_name, paths, cwd).map(|inner| Path { inner }) 433b3ba51a1Sopenharmony_ci } 434b3ba51a1Sopenharmony_ci 435b3ba51a1Sopenharmony_ci /// Returns all paths of an executable binary by name in the path list `paths` and using the 436b3ba51a1Sopenharmony_ci /// current working directory `cwd` to resolve relative paths. 437b3ba51a1Sopenharmony_ci /// 438b3ba51a1Sopenharmony_ci /// This calls `which_in_all` and maps the results into a `Path`. 439b3ba51a1Sopenharmony_ci pub fn all_in<T, U, V>( 440b3ba51a1Sopenharmony_ci binary_name: T, 441b3ba51a1Sopenharmony_ci paths: Option<U>, 442b3ba51a1Sopenharmony_ci cwd: V, 443b3ba51a1Sopenharmony_ci ) -> Result<impl Iterator<Item = Path>> 444b3ba51a1Sopenharmony_ci where 445b3ba51a1Sopenharmony_ci T: AsRef<OsStr>, 446b3ba51a1Sopenharmony_ci U: AsRef<OsStr>, 447b3ba51a1Sopenharmony_ci V: AsRef<path::Path>, 448b3ba51a1Sopenharmony_ci { 449b3ba51a1Sopenharmony_ci which_in_all(binary_name, paths, cwd).map(|inner| inner.map(|inner| Path { inner })) 450b3ba51a1Sopenharmony_ci } 451b3ba51a1Sopenharmony_ci 452b3ba51a1Sopenharmony_ci /// Returns a reference to a `std::path::Path`. 453b3ba51a1Sopenharmony_ci pub fn as_path(&self) -> &path::Path { 454b3ba51a1Sopenharmony_ci self.inner.as_path() 455b3ba51a1Sopenharmony_ci } 456b3ba51a1Sopenharmony_ci 457b3ba51a1Sopenharmony_ci /// Consumes the `which::Path`, yielding its underlying `std::path::PathBuf`. 458b3ba51a1Sopenharmony_ci pub fn into_path_buf(self) -> path::PathBuf { 459b3ba51a1Sopenharmony_ci self.inner 460b3ba51a1Sopenharmony_ci } 461b3ba51a1Sopenharmony_ci} 462b3ba51a1Sopenharmony_ci 463b3ba51a1Sopenharmony_ciimpl fmt::Debug for Path { 464b3ba51a1Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 465b3ba51a1Sopenharmony_ci fmt::Debug::fmt(&self.inner, f) 466b3ba51a1Sopenharmony_ci } 467b3ba51a1Sopenharmony_ci} 468b3ba51a1Sopenharmony_ci 469b3ba51a1Sopenharmony_ciimpl std::ops::Deref for Path { 470b3ba51a1Sopenharmony_ci type Target = path::Path; 471b3ba51a1Sopenharmony_ci 472b3ba51a1Sopenharmony_ci fn deref(&self) -> &path::Path { 473b3ba51a1Sopenharmony_ci self.inner.deref() 474b3ba51a1Sopenharmony_ci } 475b3ba51a1Sopenharmony_ci} 476b3ba51a1Sopenharmony_ci 477b3ba51a1Sopenharmony_ciimpl AsRef<path::Path> for Path { 478b3ba51a1Sopenharmony_ci fn as_ref(&self) -> &path::Path { 479b3ba51a1Sopenharmony_ci self.as_path() 480b3ba51a1Sopenharmony_ci } 481b3ba51a1Sopenharmony_ci} 482b3ba51a1Sopenharmony_ci 483b3ba51a1Sopenharmony_ciimpl AsRef<OsStr> for Path { 484b3ba51a1Sopenharmony_ci fn as_ref(&self) -> &OsStr { 485b3ba51a1Sopenharmony_ci self.as_os_str() 486b3ba51a1Sopenharmony_ci } 487b3ba51a1Sopenharmony_ci} 488b3ba51a1Sopenharmony_ci 489b3ba51a1Sopenharmony_ciimpl PartialEq<path::PathBuf> for Path { 490b3ba51a1Sopenharmony_ci fn eq(&self, other: &path::PathBuf) -> bool { 491b3ba51a1Sopenharmony_ci self.inner == *other 492b3ba51a1Sopenharmony_ci } 493b3ba51a1Sopenharmony_ci} 494b3ba51a1Sopenharmony_ci 495b3ba51a1Sopenharmony_ciimpl PartialEq<Path> for path::PathBuf { 496b3ba51a1Sopenharmony_ci fn eq(&self, other: &Path) -> bool { 497b3ba51a1Sopenharmony_ci *self == other.inner 498b3ba51a1Sopenharmony_ci } 499b3ba51a1Sopenharmony_ci} 500b3ba51a1Sopenharmony_ci 501b3ba51a1Sopenharmony_ci/// An owned, immutable wrapper around a `PathBuf` containing the _canonical_ path of an 502b3ba51a1Sopenharmony_ci/// executable. 503b3ba51a1Sopenharmony_ci/// 504b3ba51a1Sopenharmony_ci/// The constructed `PathBuf` is the result of `which` or `which_in` followed by 505b3ba51a1Sopenharmony_ci/// `Path::canonicalize`, but `CanonicalPath` has the advantage of being a type distinct from 506b3ba51a1Sopenharmony_ci/// `std::path::Path` and `std::path::PathBuf`. 507b3ba51a1Sopenharmony_ci/// 508b3ba51a1Sopenharmony_ci/// It can be beneficial to use `CanonicalPath` instead of `std::path::Path` when you want the type 509b3ba51a1Sopenharmony_ci/// system to enforce the need for a path that exists, points to a binary that is executable, is 510b3ba51a1Sopenharmony_ci/// absolute, has all components normalized, and has all symbolic links resolved 511b3ba51a1Sopenharmony_ci/// 512b3ba51a1Sopenharmony_ci/// Since `CanonicalPath` implements `Deref` for `std::path::Path`, all methods on 513b3ba51a1Sopenharmony_ci/// `&std::path::Path` are also available to `&CanonicalPath` values. 514b3ba51a1Sopenharmony_ci#[derive(Clone, PartialEq, Eq)] 515b3ba51a1Sopenharmony_cipub struct CanonicalPath { 516b3ba51a1Sopenharmony_ci inner: path::PathBuf, 517b3ba51a1Sopenharmony_ci} 518b3ba51a1Sopenharmony_ci 519b3ba51a1Sopenharmony_ciimpl CanonicalPath { 520b3ba51a1Sopenharmony_ci /// Returns the canonical path of an executable binary by name. 521b3ba51a1Sopenharmony_ci /// 522b3ba51a1Sopenharmony_ci /// This calls `which` and `Path::canonicalize` and maps the result into a `CanonicalPath`. 523b3ba51a1Sopenharmony_ci pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath> { 524b3ba51a1Sopenharmony_ci which(binary_name) 525b3ba51a1Sopenharmony_ci .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize)) 526b3ba51a1Sopenharmony_ci .map(|inner| CanonicalPath { inner }) 527b3ba51a1Sopenharmony_ci } 528b3ba51a1Sopenharmony_ci 529b3ba51a1Sopenharmony_ci /// Returns the canonical paths of an executable binary by name. 530b3ba51a1Sopenharmony_ci /// 531b3ba51a1Sopenharmony_ci /// This calls `which_all` and `Path::canonicalize` and maps the results into `CanonicalPath`s. 532b3ba51a1Sopenharmony_ci pub fn all<T: AsRef<OsStr>>( 533b3ba51a1Sopenharmony_ci binary_name: T, 534b3ba51a1Sopenharmony_ci ) -> Result<impl Iterator<Item = Result<CanonicalPath>>> { 535b3ba51a1Sopenharmony_ci which_all(binary_name).map(|inner| { 536b3ba51a1Sopenharmony_ci inner.map(|inner| { 537b3ba51a1Sopenharmony_ci inner 538b3ba51a1Sopenharmony_ci .canonicalize() 539b3ba51a1Sopenharmony_ci .map_err(|_| Error::CannotCanonicalize) 540b3ba51a1Sopenharmony_ci .map(|inner| CanonicalPath { inner }) 541b3ba51a1Sopenharmony_ci }) 542b3ba51a1Sopenharmony_ci }) 543b3ba51a1Sopenharmony_ci } 544b3ba51a1Sopenharmony_ci 545b3ba51a1Sopenharmony_ci /// Returns the canonical path of an executable binary by name in the path list `paths` and 546b3ba51a1Sopenharmony_ci /// using the current working directory `cwd` to resolve relative paths. 547b3ba51a1Sopenharmony_ci /// 548b3ba51a1Sopenharmony_ci /// This calls `which_in` and `Path::canonicalize` and maps the result into a `CanonicalPath`. 549b3ba51a1Sopenharmony_ci pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<CanonicalPath> 550b3ba51a1Sopenharmony_ci where 551b3ba51a1Sopenharmony_ci T: AsRef<OsStr>, 552b3ba51a1Sopenharmony_ci U: AsRef<OsStr>, 553b3ba51a1Sopenharmony_ci V: AsRef<path::Path>, 554b3ba51a1Sopenharmony_ci { 555b3ba51a1Sopenharmony_ci which_in(binary_name, paths, cwd) 556b3ba51a1Sopenharmony_ci .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize)) 557b3ba51a1Sopenharmony_ci .map(|inner| CanonicalPath { inner }) 558b3ba51a1Sopenharmony_ci } 559b3ba51a1Sopenharmony_ci 560b3ba51a1Sopenharmony_ci /// Returns all of the canonical paths of an executable binary by name in the path list `paths` and 561b3ba51a1Sopenharmony_ci /// using the current working directory `cwd` to resolve relative paths. 562b3ba51a1Sopenharmony_ci /// 563b3ba51a1Sopenharmony_ci /// This calls `which_in_all` and `Path::canonicalize` and maps the result into a `CanonicalPath`. 564b3ba51a1Sopenharmony_ci pub fn all_in<T, U, V>( 565b3ba51a1Sopenharmony_ci binary_name: T, 566b3ba51a1Sopenharmony_ci paths: Option<U>, 567b3ba51a1Sopenharmony_ci cwd: V, 568b3ba51a1Sopenharmony_ci ) -> Result<impl Iterator<Item = Result<CanonicalPath>>> 569b3ba51a1Sopenharmony_ci where 570b3ba51a1Sopenharmony_ci T: AsRef<OsStr>, 571b3ba51a1Sopenharmony_ci U: AsRef<OsStr>, 572b3ba51a1Sopenharmony_ci V: AsRef<path::Path>, 573b3ba51a1Sopenharmony_ci { 574b3ba51a1Sopenharmony_ci which_in_all(binary_name, paths, cwd).map(|inner| { 575b3ba51a1Sopenharmony_ci inner.map(|inner| { 576b3ba51a1Sopenharmony_ci inner 577b3ba51a1Sopenharmony_ci .canonicalize() 578b3ba51a1Sopenharmony_ci .map_err(|_| Error::CannotCanonicalize) 579b3ba51a1Sopenharmony_ci .map(|inner| CanonicalPath { inner }) 580b3ba51a1Sopenharmony_ci }) 581b3ba51a1Sopenharmony_ci }) 582b3ba51a1Sopenharmony_ci } 583b3ba51a1Sopenharmony_ci 584b3ba51a1Sopenharmony_ci /// Returns a reference to a `std::path::Path`. 585b3ba51a1Sopenharmony_ci pub fn as_path(&self) -> &path::Path { 586b3ba51a1Sopenharmony_ci self.inner.as_path() 587b3ba51a1Sopenharmony_ci } 588b3ba51a1Sopenharmony_ci 589b3ba51a1Sopenharmony_ci /// Consumes the `which::CanonicalPath`, yielding its underlying `std::path::PathBuf`. 590b3ba51a1Sopenharmony_ci pub fn into_path_buf(self) -> path::PathBuf { 591b3ba51a1Sopenharmony_ci self.inner 592b3ba51a1Sopenharmony_ci } 593b3ba51a1Sopenharmony_ci} 594b3ba51a1Sopenharmony_ci 595b3ba51a1Sopenharmony_ciimpl fmt::Debug for CanonicalPath { 596b3ba51a1Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 597b3ba51a1Sopenharmony_ci fmt::Debug::fmt(&self.inner, f) 598b3ba51a1Sopenharmony_ci } 599b3ba51a1Sopenharmony_ci} 600b3ba51a1Sopenharmony_ci 601b3ba51a1Sopenharmony_ciimpl std::ops::Deref for CanonicalPath { 602b3ba51a1Sopenharmony_ci type Target = path::Path; 603b3ba51a1Sopenharmony_ci 604b3ba51a1Sopenharmony_ci fn deref(&self) -> &path::Path { 605b3ba51a1Sopenharmony_ci self.inner.deref() 606b3ba51a1Sopenharmony_ci } 607b3ba51a1Sopenharmony_ci} 608b3ba51a1Sopenharmony_ci 609b3ba51a1Sopenharmony_ciimpl AsRef<path::Path> for CanonicalPath { 610b3ba51a1Sopenharmony_ci fn as_ref(&self) -> &path::Path { 611b3ba51a1Sopenharmony_ci self.as_path() 612b3ba51a1Sopenharmony_ci } 613b3ba51a1Sopenharmony_ci} 614b3ba51a1Sopenharmony_ci 615b3ba51a1Sopenharmony_ciimpl AsRef<OsStr> for CanonicalPath { 616b3ba51a1Sopenharmony_ci fn as_ref(&self) -> &OsStr { 617b3ba51a1Sopenharmony_ci self.as_os_str() 618b3ba51a1Sopenharmony_ci } 619b3ba51a1Sopenharmony_ci} 620b3ba51a1Sopenharmony_ci 621b3ba51a1Sopenharmony_ciimpl PartialEq<path::PathBuf> for CanonicalPath { 622b3ba51a1Sopenharmony_ci fn eq(&self, other: &path::PathBuf) -> bool { 623b3ba51a1Sopenharmony_ci self.inner == *other 624b3ba51a1Sopenharmony_ci } 625b3ba51a1Sopenharmony_ci} 626b3ba51a1Sopenharmony_ci 627b3ba51a1Sopenharmony_ciimpl PartialEq<CanonicalPath> for path::PathBuf { 628b3ba51a1Sopenharmony_ci fn eq(&self, other: &CanonicalPath) -> bool { 629b3ba51a1Sopenharmony_ci *self == other.inner 630b3ba51a1Sopenharmony_ci } 631b3ba51a1Sopenharmony_ci} 632