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