• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::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 use std::env;
24 use std::fmt;
25 use std::path;
26 
27 use std::ffi::OsStr;
28 
29 use crate::checker::{CompositeChecker, ExecutableChecker, ExistedChecker};
30 pub use crate::error::*;
31 use crate::finder::Finder;
32 
33 /// Find a exectable binary's path by name.
34 ///
35 /// If given an absolute path, returns it if the file exists and is executable.
36 ///
37 /// If given a relative path, returns an absolute path to the file if
38 /// it exists and is executable.
39 ///
40 /// If given a string without path separators, looks for a file named
41 /// `binary_name` at each directory in `$PATH` and if it finds an executable
42 /// file there, returns it.
43 ///
44 /// # Example
45 ///
46 /// ```no_run
47 /// use which::which;
48 /// use std::path::PathBuf;
49 ///
50 /// let result = which::which("rustc").unwrap();
51 /// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
52 ///
53 /// ```
which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf>54 pub fn which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> {
55     which_all(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
56 }
57 
58 /// Find all binaries with `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = path::PathBuf>>59 pub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = path::PathBuf>> {
60     let cwd = env::current_dir().map_err(|_| Error::CannotGetCurrentDir)?;
61 
62     which_in_all(binary_name, env::var_os("PATH"), cwd)
63 }
64 
65 /// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<path::PathBuf> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,66 pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<path::PathBuf>
67 where
68     T: AsRef<OsStr>,
69     U: AsRef<OsStr>,
70     V: AsRef<path::Path>,
71 {
72     which_in_all(binary_name, paths, cwd)
73         .and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
74 }
75 
76 /// Find all binaries with `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
which_in_all<T, U, V>( binary_name: T, paths: Option<U>, cwd: V, ) -> Result<impl Iterator<Item = path::PathBuf>> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,77 pub fn which_in_all<T, U, V>(
78     binary_name: T,
79     paths: Option<U>,
80     cwd: V,
81 ) -> Result<impl Iterator<Item = path::PathBuf>>
82 where
83     T: AsRef<OsStr>,
84     U: AsRef<OsStr>,
85     V: AsRef<path::Path>,
86 {
87     let binary_checker = CompositeChecker::new()
88         .add_checker(Box::new(ExistedChecker::new()))
89         .add_checker(Box::new(ExecutableChecker::new()));
90 
91     let finder = Finder::new();
92 
93     finder.find(binary_name, paths, cwd, binary_checker)
94 }
95 
96 /// An owned, immutable wrapper around a `PathBuf` containing the path of an executable.
97 ///
98 /// The constructed `PathBuf` is the output of `which` or `which_in`, but `which::Path` has the
99 /// advantage of being a type distinct from `std::path::Path` and `std::path::PathBuf`.
100 ///
101 /// It can be beneficial to use `which::Path` instead of `std::path::Path` when you want the type
102 /// system to enforce the need for a path that exists and points to a binary that is executable.
103 ///
104 /// Since `which::Path` implements `Deref` for `std::path::Path`, all methods on `&std::path::Path`
105 /// are also available to `&which::Path` values.
106 #[derive(Clone, PartialEq)]
107 pub struct Path {
108     inner: path::PathBuf,
109 }
110 
111 impl Path {
112     /// Returns the path of an executable binary by name.
113     ///
114     /// This calls `which` and maps the result into a `Path`.
new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path>115     pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path> {
116         which(binary_name).map(|inner| Path { inner })
117     }
118 
119     /// Returns the paths of all executable binaries by a name.
120     ///
121     /// this calls `which_all` and maps the results into `Path`s.
all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = Path>>122     pub fn all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = Path>> {
123         which_all(binary_name).map(|inner| inner.map(|inner| Path { inner }))
124     }
125 
126     /// Returns the path of an executable binary by name in the path list `paths` and using the
127     /// current working directory `cwd` to resolve relative paths.
128     ///
129     /// This calls `which_in` and maps the result into a `Path`.
new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<Path> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,130     pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<Path>
131     where
132         T: AsRef<OsStr>,
133         U: AsRef<OsStr>,
134         V: AsRef<path::Path>,
135     {
136         which_in(binary_name, paths, cwd).map(|inner| Path { inner })
137     }
138 
139     /// Returns all paths of an executable binary by name in the path list `paths` and using the
140     /// current working directory `cwd` to resolve relative paths.
141     ///
142     /// This calls `which_in_all` and maps the results into a `Path`.
all_in<T, U, V>( binary_name: T, paths: Option<U>, cwd: V, ) -> Result<impl Iterator<Item = Path>> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,143     pub fn all_in<T, U, V>(
144         binary_name: T,
145         paths: Option<U>,
146         cwd: V,
147     ) -> Result<impl Iterator<Item = Path>>
148     where
149         T: AsRef<OsStr>,
150         U: AsRef<OsStr>,
151         V: AsRef<path::Path>,
152     {
153         which_in_all(binary_name, paths, cwd).map(|inner| inner.map(|inner| Path { inner }))
154     }
155 
156     /// Returns a reference to a `std::path::Path`.
as_path(&self) -> &path::Path157     pub fn as_path(&self) -> &path::Path {
158         self.inner.as_path()
159     }
160 
161     /// Consumes the `which::Path`, yielding its underlying `std::path::PathBuf`.
into_path_buf(self) -> path::PathBuf162     pub fn into_path_buf(self) -> path::PathBuf {
163         self.inner
164     }
165 }
166 
167 impl fmt::Debug for Path {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result168     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169         fmt::Debug::fmt(&self.inner, f)
170     }
171 }
172 
173 impl std::ops::Deref for Path {
174     type Target = path::Path;
175 
deref(&self) -> &path::Path176     fn deref(&self) -> &path::Path {
177         self.inner.deref()
178     }
179 }
180 
181 impl AsRef<path::Path> for Path {
as_ref(&self) -> &path::Path182     fn as_ref(&self) -> &path::Path {
183         self.as_path()
184     }
185 }
186 
187 impl AsRef<OsStr> for Path {
as_ref(&self) -> &OsStr188     fn as_ref(&self) -> &OsStr {
189         self.as_os_str()
190     }
191 }
192 
193 impl Eq for Path {}
194 
195 impl PartialEq<path::PathBuf> for Path {
eq(&self, other: &path::PathBuf) -> bool196     fn eq(&self, other: &path::PathBuf) -> bool {
197         self.inner == *other
198     }
199 }
200 
201 impl PartialEq<Path> for path::PathBuf {
eq(&self, other: &Path) -> bool202     fn eq(&self, other: &Path) -> bool {
203         *self == other.inner
204     }
205 }
206 
207 /// An owned, immutable wrapper around a `PathBuf` containing the _canonical_ path of an
208 /// executable.
209 ///
210 /// The constructed `PathBuf` is the result of `which` or `which_in` followed by
211 /// `Path::canonicalize`, but `CanonicalPath` has the advantage of being a type distinct from
212 /// `std::path::Path` and `std::path::PathBuf`.
213 ///
214 /// It can be beneficial to use `CanonicalPath` instead of `std::path::Path` when you want the type
215 /// system to enforce the need for a path that exists, points to a binary that is executable, is
216 /// absolute, has all components normalized, and has all symbolic links resolved
217 ///
218 /// Since `CanonicalPath` implements `Deref` for `std::path::Path`, all methods on
219 /// `&std::path::Path` are also available to `&CanonicalPath` values.
220 #[derive(Clone, PartialEq)]
221 pub struct CanonicalPath {
222     inner: path::PathBuf,
223 }
224 
225 impl CanonicalPath {
226     /// Returns the canonical path of an executable binary by name.
227     ///
228     /// This calls `which` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath>229     pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath> {
230         which(binary_name)
231             .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize))
232             .map(|inner| CanonicalPath { inner })
233     }
234 
235     /// Returns the canonical paths of an executable binary by name.
236     ///
237     /// This calls `which_all` and `Path::canonicalize` and maps the results into `CanonicalPath`s.
all<T: AsRef<OsStr>>( binary_name: T, ) -> Result<impl Iterator<Item = Result<CanonicalPath>>>238     pub fn all<T: AsRef<OsStr>>(
239         binary_name: T,
240     ) -> Result<impl Iterator<Item = Result<CanonicalPath>>> {
241         which_all(binary_name).map(|inner| {
242             inner.map(|inner| {
243                 inner
244                     .canonicalize()
245                     .map_err(|_| Error::CannotCanonicalize)
246                     .map(|inner| CanonicalPath { inner })
247             })
248         })
249     }
250 
251     /// Returns the canonical path of an executable binary by name in the path list `paths` and
252     /// using the current working directory `cwd` to resolve relative paths.
253     ///
254     /// This calls `which_in` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<CanonicalPath> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,255     pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<CanonicalPath>
256     where
257         T: AsRef<OsStr>,
258         U: AsRef<OsStr>,
259         V: AsRef<path::Path>,
260     {
261         which_in(binary_name, paths, cwd)
262             .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize))
263             .map(|inner| CanonicalPath { inner })
264     }
265 
266     /// Returns all of the canonical paths of an executable binary by name in the path list `paths` and
267     /// using the current working directory `cwd` to resolve relative paths.
268     ///
269     /// This calls `which_in_all` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
all_in<T, U, V>( binary_name: T, paths: Option<U>, cwd: V, ) -> Result<impl Iterator<Item = Result<CanonicalPath>>> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,270     pub fn all_in<T, U, V>(
271         binary_name: T,
272         paths: Option<U>,
273         cwd: V,
274     ) -> Result<impl Iterator<Item = Result<CanonicalPath>>>
275     where
276         T: AsRef<OsStr>,
277         U: AsRef<OsStr>,
278         V: AsRef<path::Path>,
279     {
280         which_in_all(binary_name, paths, cwd).map(|inner| {
281             inner.map(|inner| {
282                 inner
283                     .canonicalize()
284                     .map_err(|_| Error::CannotCanonicalize)
285                     .map(|inner| CanonicalPath { inner })
286             })
287         })
288     }
289 
290     /// Returns a reference to a `std::path::Path`.
as_path(&self) -> &path::Path291     pub fn as_path(&self) -> &path::Path {
292         self.inner.as_path()
293     }
294 
295     /// Consumes the `which::CanonicalPath`, yielding its underlying `std::path::PathBuf`.
into_path_buf(self) -> path::PathBuf296     pub fn into_path_buf(self) -> path::PathBuf {
297         self.inner
298     }
299 }
300 
301 impl fmt::Debug for CanonicalPath {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result302     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
303         fmt::Debug::fmt(&self.inner, f)
304     }
305 }
306 
307 impl std::ops::Deref for CanonicalPath {
308     type Target = path::Path;
309 
deref(&self) -> &path::Path310     fn deref(&self) -> &path::Path {
311         self.inner.deref()
312     }
313 }
314 
315 impl AsRef<path::Path> for CanonicalPath {
as_ref(&self) -> &path::Path316     fn as_ref(&self) -> &path::Path {
317         self.as_path()
318     }
319 }
320 
321 impl AsRef<OsStr> for CanonicalPath {
as_ref(&self) -> &OsStr322     fn as_ref(&self) -> &OsStr {
323         self.as_os_str()
324     }
325 }
326 
327 impl Eq for CanonicalPath {}
328 
329 impl PartialEq<path::PathBuf> for CanonicalPath {
eq(&self, other: &path::PathBuf) -> bool330     fn eq(&self, other: &path::PathBuf) -> bool {
331         self.inner == *other
332     }
333 }
334 
335 impl PartialEq<CanonicalPath> for path::PathBuf {
eq(&self, other: &CanonicalPath) -> bool336     fn eq(&self, other: &CanonicalPath) -> bool {
337         *self == other.inner
338     }
339 }
340