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