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