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