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 //! ``` norun
9 //! use which::which;
10 //!
11 //! let result = which::which("rustc").unwrap();
12 //! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
13 //!
14 //! ```
15 
16 extern crate libc;
17 extern crate thiserror;
18 
19 mod checker;
20 mod error;
21 mod finder;
22 #[cfg(windows)]
23 mod helper;
24 
25 use std::env;
26 use std::fmt;
27 use std::path;
28 
29 use std::ffi::OsStr;
30 
31 use checker::CompositeChecker;
32 use checker::ExecutableChecker;
33 use checker::ExistedChecker;
34 pub use error::*;
35 use finder::Finder;
36 
37 /// Find a exectable binary's path by name.
38 ///
39 /// If given an absolute path, returns it if the file exists and is executable.
40 ///
41 /// If given a relative path, returns an absolute path to the file if
42 /// it exists and is executable.
43 ///
44 /// If given a string without path separators, looks for a file named
45 /// `binary_name` at each directory in `$PATH` and if it finds an executable
46 /// file there, returns it.
47 ///
48 /// # Example
49 ///
50 /// ``` norun
51 /// use which::which;
52 /// use std::path::PathBuf;
53 ///
54 /// let result = which::which("rustc").unwrap();
55 /// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
56 ///
57 /// ```
which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf>58 pub fn which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> {
59     let cwd = env::current_dir().map_err(|_| Error::CannotGetCurrentDir)?;
60 
61     which_in(binary_name, env::var_os("PATH"), &cwd)
62 }
63 
64 /// 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>,65 pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<path::PathBuf>
66 where
67     T: AsRef<OsStr>,
68     U: AsRef<OsStr>,
69     V: AsRef<path::Path>,
70 {
71     let binary_checker = CompositeChecker::new()
72         .add_checker(Box::new(ExistedChecker::new()))
73         .add_checker(Box::new(ExecutableChecker::new()));
74 
75     let finder = Finder::new();
76 
77     finder.find(binary_name, paths, cwd, &binary_checker)
78 }
79 
80 /// An owned, immutable wrapper around a `PathBuf` containing the path of an executable.
81 ///
82 /// The constructed `PathBuf` is the output of `which` or `which_in`, but `which::Path` has the
83 /// advantage of being a type distinct from `std::path::Path` and `std::path::PathBuf`.
84 ///
85 /// It can be beneficial to use `which::Path` instead of `std::path::Path` when you want the type
86 /// system to enforce the need for a path that exists and points to a binary that is executable.
87 ///
88 /// Since `which::Path` implements `Deref` for `std::path::Path`, all methods on `&std::path::Path`
89 /// are also available to `&which::Path` values.
90 #[derive(Clone, PartialEq)]
91 pub struct Path {
92     inner: path::PathBuf,
93 }
94 
95 impl Path {
96     /// Returns the path of an executable binary by name.
97     ///
98     /// This calls `which` and maps the result into a `Path`.
new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path>99     pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path> {
100         which(binary_name).map(|inner| Path { inner })
101     }
102 
103     /// Returns the path of an executable binary by name in the path list `paths` and using the
104     /// current working directory `cwd` to resolve relative paths.
105     ///
106     /// 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>,107     pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<Path>
108     where
109         T: AsRef<OsStr>,
110         U: AsRef<OsStr>,
111         V: AsRef<path::Path>,
112     {
113         which_in(binary_name, paths, cwd).map(|inner| Path { inner })
114     }
115 
116     /// Returns a reference to a `std::path::Path`.
as_path(&self) -> &path::Path117     pub fn as_path(&self) -> &path::Path {
118         self.inner.as_path()
119     }
120 
121     /// Consumes the `which::Path`, yielding its underlying `std::path::PathBuf`.
into_path_buf(self) -> path::PathBuf122     pub fn into_path_buf(self) -> path::PathBuf {
123         self.inner
124     }
125 }
126 
127 impl fmt::Debug for Path {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result128     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129         fmt::Debug::fmt(&self.inner, f)
130     }
131 }
132 
133 impl std::ops::Deref for Path {
134     type Target = path::Path;
135 
deref(&self) -> &path::Path136     fn deref(&self) -> &path::Path {
137         self.inner.deref()
138     }
139 }
140 
141 impl AsRef<path::Path> for Path {
as_ref(&self) -> &path::Path142     fn as_ref(&self) -> &path::Path {
143         self.as_path()
144     }
145 }
146 
147 impl AsRef<OsStr> for Path {
as_ref(&self) -> &OsStr148     fn as_ref(&self) -> &OsStr {
149         self.as_os_str()
150     }
151 }
152 
153 impl Eq for Path {}
154 
155 impl PartialEq<path::PathBuf> for Path {
eq(&self, other: &path::PathBuf) -> bool156     fn eq(&self, other: &path::PathBuf) -> bool {
157         self.inner == *other
158     }
159 }
160 
161 impl PartialEq<Path> for path::PathBuf {
eq(&self, other: &Path) -> bool162     fn eq(&self, other: &Path) -> bool {
163         *self == other.inner
164     }
165 }
166 
167 /// An owned, immutable wrapper around a `PathBuf` containing the _canonical_ path of an
168 /// executable.
169 ///
170 /// The constructed `PathBuf` is the result of `which` or `which_in` followed by
171 /// `Path::canonicalize`, but `CanonicalPath` has the advantage of being a type distinct from
172 /// `std::path::Path` and `std::path::PathBuf`.
173 ///
174 /// It can be beneficial to use `CanonicalPath` instead of `std::path::Path` when you want the type
175 /// system to enforce the need for a path that exists, points to a binary that is executable, is
176 /// absolute, has all components normalized, and has all symbolic links resolved
177 ///
178 /// Since `CanonicalPath` implements `Deref` for `std::path::Path`, all methods on
179 /// `&std::path::Path` are also available to `&CanonicalPath` values.
180 #[derive(Clone, PartialEq)]
181 pub struct CanonicalPath {
182     inner: path::PathBuf,
183 }
184 
185 impl CanonicalPath {
186     /// Returns the canonical path of an executable binary by name.
187     ///
188     /// This calls `which` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath>189     pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath> {
190         which(binary_name)
191             .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize))
192             .map(|inner| CanonicalPath { inner })
193     }
194 
195     /// Returns the canonical path of an executable binary by name in the path list `paths` and
196     /// using the current working directory `cwd` to resolve relative paths.
197     ///
198     /// This calls `which` 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>,199     pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<CanonicalPath>
200     where
201         T: AsRef<OsStr>,
202         U: AsRef<OsStr>,
203         V: AsRef<path::Path>,
204     {
205         which_in(binary_name, paths, cwd)
206             .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize))
207             .map(|inner| CanonicalPath { inner })
208     }
209 
210     /// Returns a reference to a `std::path::Path`.
as_path(&self) -> &path::Path211     pub fn as_path(&self) -> &path::Path {
212         self.inner.as_path()
213     }
214 
215     /// Consumes the `which::CanonicalPath`, yielding its underlying `std::path::PathBuf`.
into_path_buf(self) -> path::PathBuf216     pub fn into_path_buf(self) -> path::PathBuf {
217         self.inner
218     }
219 }
220 
221 impl fmt::Debug for CanonicalPath {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result222     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223         fmt::Debug::fmt(&self.inner, f)
224     }
225 }
226 
227 impl std::ops::Deref for CanonicalPath {
228     type Target = path::Path;
229 
deref(&self) -> &path::Path230     fn deref(&self) -> &path::Path {
231         self.inner.deref()
232     }
233 }
234 
235 impl AsRef<path::Path> for CanonicalPath {
as_ref(&self) -> &path::Path236     fn as_ref(&self) -> &path::Path {
237         self.as_path()
238     }
239 }
240 
241 impl AsRef<OsStr> for CanonicalPath {
as_ref(&self) -> &OsStr242     fn as_ref(&self) -> &OsStr {
243         self.as_os_str()
244     }
245 }
246 
247 impl Eq for CanonicalPath {}
248 
249 impl PartialEq<path::PathBuf> for CanonicalPath {
eq(&self, other: &path::PathBuf) -> bool250     fn eq(&self, other: &path::PathBuf) -> bool {
251         self.inner == *other
252     }
253 }
254 
255 impl PartialEq<CanonicalPath> for path::PathBuf {
eq(&self, other: &CanonicalPath) -> bool256     fn eq(&self, other: &CanonicalPath) -> bool {
257         *self == other.inner
258     }
259 }
260