Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
74
third-party/vendor/which/src/checker.rs
vendored
Normal file
74
third-party/vendor/which/src/checker.rs
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
use crate::finder::Checker;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct ExecutableChecker;
|
||||
|
||||
impl ExecutableChecker {
|
||||
pub fn new() -> ExecutableChecker {
|
||||
ExecutableChecker
|
||||
}
|
||||
}
|
||||
|
||||
impl Checker for ExecutableChecker {
|
||||
#[cfg(any(unix, target_os = "wasi"))]
|
||||
fn is_valid(&self, path: &Path) -> bool {
|
||||
use rustix::fs as rfs;
|
||||
rfs::access(path, rfs::Access::EXEC_OK).is_ok()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn is_valid(&self, _path: &Path) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExistedChecker;
|
||||
|
||||
impl ExistedChecker {
|
||||
pub fn new() -> ExistedChecker {
|
||||
ExistedChecker
|
||||
}
|
||||
}
|
||||
|
||||
impl Checker for ExistedChecker {
|
||||
#[cfg(target_os = "windows")]
|
||||
fn is_valid(&self, path: &Path) -> bool {
|
||||
fs::symlink_metadata(path)
|
||||
.map(|metadata| {
|
||||
let file_type = metadata.file_type();
|
||||
file_type.is_file() || file_type.is_symlink()
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn is_valid(&self, path: &Path) -> bool {
|
||||
fs::metadata(path)
|
||||
.map(|metadata| metadata.is_file())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CompositeChecker {
|
||||
checkers: Vec<Box<dyn Checker>>,
|
||||
}
|
||||
|
||||
impl CompositeChecker {
|
||||
pub fn new() -> CompositeChecker {
|
||||
CompositeChecker {
|
||||
checkers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_checker(mut self, checker: Box<dyn Checker>) -> CompositeChecker {
|
||||
self.checkers.push(checker);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Checker for CompositeChecker {
|
||||
fn is_valid(&self, path: &Path) -> bool {
|
||||
self.checkers.iter().all(|checker| checker.is_valid(path))
|
||||
}
|
||||
}
|
||||
26
third-party/vendor/which/src/error.rs
vendored
Normal file
26
third-party/vendor/which/src/error.rs
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use std::fmt;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Error {
|
||||
BadAbsolutePath,
|
||||
BadRelativePath,
|
||||
CannotFindBinaryPath,
|
||||
CannotGetCurrentDir,
|
||||
CannotCanonicalize,
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::BadAbsolutePath => write!(f, "bad absolute path"),
|
||||
Error::BadRelativePath => write!(f, "bad relative path"),
|
||||
Error::CannotFindBinaryPath => write!(f, "cannot find binary path"),
|
||||
Error::CannotGetCurrentDir => write!(f, "cannot get current directory"),
|
||||
Error::CannotCanonicalize => write!(f, "cannot canonicalize path"),
|
||||
}
|
||||
}
|
||||
}
|
||||
259
third-party/vendor/which/src/finder.rs
vendored
Normal file
259
third-party/vendor/which/src/finder.rs
vendored
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
use crate::checker::CompositeChecker;
|
||||
use crate::error::*;
|
||||
#[cfg(windows)]
|
||||
use crate::helper::has_executable_extension;
|
||||
use either::Either;
|
||||
#[cfg(feature = "regex")]
|
||||
use regex::Regex;
|
||||
#[cfg(feature = "regex")]
|
||||
use std::borrow::Borrow;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
#[cfg(any(feature = "regex", target_os = "windows"))]
|
||||
use std::fs;
|
||||
use std::iter;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
// Home dir shim, use home crate when possible. Otherwise, return None
|
||||
#[cfg(any(windows, unix, target_os = "redox"))]
|
||||
use home::home_dir;
|
||||
|
||||
#[cfg(not(any(windows, unix, target_os = "redox")))]
|
||||
fn home_dir() -> Option<std::path::PathBuf> {
|
||||
None
|
||||
}
|
||||
|
||||
pub trait Checker {
|
||||
fn is_valid(&self, path: &Path) -> bool;
|
||||
}
|
||||
|
||||
trait PathExt {
|
||||
fn has_separator(&self) -> bool;
|
||||
|
||||
fn to_absolute<P>(self, cwd: P) -> PathBuf
|
||||
where
|
||||
P: AsRef<Path>;
|
||||
}
|
||||
|
||||
impl PathExt for PathBuf {
|
||||
fn has_separator(&self) -> bool {
|
||||
self.components().count() > 1
|
||||
}
|
||||
|
||||
fn to_absolute<P>(self, cwd: P) -> PathBuf
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
if self.is_absolute() {
|
||||
self
|
||||
} else {
|
||||
let mut new_path = PathBuf::from(cwd.as_ref());
|
||||
new_path.push(self);
|
||||
new_path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Finder;
|
||||
|
||||
impl Finder {
|
||||
pub fn new() -> Finder {
|
||||
Finder
|
||||
}
|
||||
|
||||
pub fn find<T, U, V>(
|
||||
&self,
|
||||
binary_name: T,
|
||||
paths: Option<U>,
|
||||
cwd: Option<V>,
|
||||
binary_checker: CompositeChecker,
|
||||
) -> Result<impl Iterator<Item = PathBuf>>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
U: AsRef<OsStr>,
|
||||
V: AsRef<Path>,
|
||||
{
|
||||
let path = PathBuf::from(&binary_name);
|
||||
|
||||
let binary_path_candidates = match cwd {
|
||||
Some(cwd) if path.has_separator() => {
|
||||
// Search binary in cwd if the path have a path separator.
|
||||
Either::Left(Self::cwd_search_candidates(path, cwd).into_iter())
|
||||
}
|
||||
_ => {
|
||||
// Search binary in PATHs(defined in environment variable).
|
||||
let p = paths.ok_or(Error::CannotFindBinaryPath)?;
|
||||
let paths: Vec<_> = env::split_paths(&p).collect();
|
||||
|
||||
Either::Right(Self::path_search_candidates(path, paths).into_iter())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(binary_path_candidates
|
||||
.filter(move |p| binary_checker.is_valid(p))
|
||||
.map(correct_casing))
|
||||
}
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
pub fn find_re<T>(
|
||||
&self,
|
||||
binary_regex: impl Borrow<Regex>,
|
||||
paths: Option<T>,
|
||||
binary_checker: CompositeChecker,
|
||||
) -> Result<impl Iterator<Item = PathBuf>>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
{
|
||||
let p = paths.ok_or(Error::CannotFindBinaryPath)?;
|
||||
// Collect needs to happen in order to not have to
|
||||
// change the API to borrow on `paths`.
|
||||
#[allow(clippy::needless_collect)]
|
||||
let paths: Vec<_> = env::split_paths(&p).collect();
|
||||
|
||||
let matching_re = paths
|
||||
.into_iter()
|
||||
.flat_map(fs::read_dir)
|
||||
.flatten()
|
||||
.flatten()
|
||||
.map(|e| e.path())
|
||||
.filter(move |p| {
|
||||
if let Some(unicode_file_name) = p.file_name().unwrap().to_str() {
|
||||
binary_regex.borrow().is_match(unicode_file_name)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.filter(move |p| binary_checker.is_valid(p));
|
||||
|
||||
Ok(matching_re)
|
||||
}
|
||||
|
||||
fn cwd_search_candidates<C>(binary_name: PathBuf, cwd: C) -> impl IntoIterator<Item = PathBuf>
|
||||
where
|
||||
C: AsRef<Path>,
|
||||
{
|
||||
let path = binary_name.to_absolute(cwd);
|
||||
|
||||
Self::append_extension(iter::once(path))
|
||||
}
|
||||
|
||||
fn path_search_candidates<P>(
|
||||
binary_name: PathBuf,
|
||||
paths: P,
|
||||
) -> impl IntoIterator<Item = PathBuf>
|
||||
where
|
||||
P: IntoIterator<Item = PathBuf>,
|
||||
{
|
||||
let new_paths = paths
|
||||
.into_iter()
|
||||
.map(move |p| tilde_expansion(&p).join(binary_name.clone()));
|
||||
|
||||
Self::append_extension(new_paths)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn append_extension<P>(paths: P) -> impl IntoIterator<Item = PathBuf>
|
||||
where
|
||||
P: IntoIterator<Item = PathBuf>,
|
||||
{
|
||||
paths
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn append_extension<P>(paths: P) -> impl IntoIterator<Item = PathBuf>
|
||||
where
|
||||
P: IntoIterator<Item = PathBuf>,
|
||||
{
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
// Sample %PATHEXT%: .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
|
||||
// PATH_EXTENSIONS is then [".COM", ".EXE", ".BAT", …].
|
||||
// (In one use of PATH_EXTENSIONS we skip the dot, but in the other we need it;
|
||||
// hence its retention.)
|
||||
static PATH_EXTENSIONS: Lazy<Vec<String>> = Lazy::new(|| {
|
||||
env::var("PATHEXT")
|
||||
.map(|pathext| {
|
||||
pathext
|
||||
.split(';')
|
||||
.filter_map(|s| {
|
||||
if s.as_bytes().first() == Some(&b'.') {
|
||||
Some(s.to_owned())
|
||||
} else {
|
||||
// Invalid segment; just ignore it.
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
// PATHEXT not being set or not being a proper Unicode string is exceedingly
|
||||
// improbable and would probably break Windows badly. Still, don't crash:
|
||||
.unwrap_or_default()
|
||||
});
|
||||
|
||||
paths
|
||||
.into_iter()
|
||||
.flat_map(move |p| -> Box<dyn Iterator<Item = _>> {
|
||||
// Check if path already have executable extension
|
||||
if has_executable_extension(&p, &PATH_EXTENSIONS) {
|
||||
Box::new(iter::once(p))
|
||||
} else {
|
||||
let bare_file = p.extension().map(|_| p.clone());
|
||||
// Appended paths with windows executable extensions.
|
||||
// e.g. path `c:/windows/bin[.ext]` will expand to:
|
||||
// [c:/windows/bin.ext]
|
||||
// c:/windows/bin[.ext].COM
|
||||
// c:/windows/bin[.ext].EXE
|
||||
// c:/windows/bin[.ext].CMD
|
||||
// ...
|
||||
Box::new(
|
||||
bare_file
|
||||
.into_iter()
|
||||
.chain(PATH_EXTENSIONS.iter().map(move |e| {
|
||||
// Append the extension.
|
||||
let mut p = p.clone().into_os_string();
|
||||
p.push(e);
|
||||
|
||||
PathBuf::from(p)
|
||||
})),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn tilde_expansion(p: &PathBuf) -> Cow<'_, PathBuf> {
|
||||
let mut component_iter = p.components();
|
||||
if let Some(Component::Normal(o)) = component_iter.next() {
|
||||
if o == "~" {
|
||||
let mut new_path = home_dir().unwrap_or_default();
|
||||
new_path.extend(component_iter);
|
||||
Cow::Owned(new_path)
|
||||
} else {
|
||||
Cow::Borrowed(p)
|
||||
}
|
||||
} else {
|
||||
Cow::Borrowed(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn correct_casing(mut p: PathBuf) -> PathBuf {
|
||||
if let (Some(parent), Some(file_name)) = (p.parent(), p.file_name()) {
|
||||
if let Ok(iter) = fs::read_dir(parent) {
|
||||
for e in iter.filter_map(std::result::Result::ok) {
|
||||
if e.file_name().eq_ignore_ascii_case(file_name) {
|
||||
p.pop();
|
||||
p.push(e.file_name());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn correct_casing(p: PathBuf) -> PathBuf {
|
||||
p
|
||||
}
|
||||
40
third-party/vendor/which/src/helper.rs
vendored
Normal file
40
third-party/vendor/which/src/helper.rs
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use std::path::Path;
|
||||
|
||||
/// Check if given path has extension which in the given vector.
|
||||
pub fn has_executable_extension<T: AsRef<Path>, S: AsRef<str>>(path: T, pathext: &[S]) -> bool {
|
||||
let ext = path.as_ref().extension().and_then(|e| e.to_str());
|
||||
match ext {
|
||||
Some(ext) => pathext
|
||||
.iter()
|
||||
.any(|e| ext.eq_ignore_ascii_case(&e.as_ref()[1..])),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn test_extension_in_extension_vector() {
|
||||
// Case insensitive
|
||||
assert!(has_executable_extension(
|
||||
PathBuf::from("foo.exe"),
|
||||
&[".COM", ".EXE", ".CMD"]
|
||||
));
|
||||
|
||||
assert!(has_executable_extension(
|
||||
PathBuf::from("foo.CMD"),
|
||||
&[".COM", ".EXE", ".CMD"]
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extension_not_in_extension_vector() {
|
||||
assert!(!has_executable_extension(
|
||||
PathBuf::from("foo.bar"),
|
||||
&[".COM", ".EXE", ".CMD"]
|
||||
));
|
||||
}
|
||||
}
|
||||
634
third-party/vendor/which/src/lib.rs
vendored
Normal file
634
third-party/vendor/which/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,634 @@
|
|||
//! which
|
||||
//!
|
||||
//! A Rust equivalent of Unix command `which(1)`.
|
||||
//! # Example:
|
||||
//!
|
||||
//! To find which rustc executable binary is using:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use which::which;
|
||||
//! use std::path::PathBuf;
|
||||
//!
|
||||
//! let result = which("rustc").unwrap();
|
||||
//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
|
||||
//!
|
||||
//! ```
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
mod checker;
|
||||
mod error;
|
||||
mod finder;
|
||||
#[cfg(windows)]
|
||||
mod helper;
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
use std::borrow::Borrow;
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::path;
|
||||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
use crate::checker::{CompositeChecker, ExecutableChecker, ExistedChecker};
|
||||
pub use crate::error::*;
|
||||
use crate::finder::Finder;
|
||||
|
||||
/// Find an executable binary's path by name.
|
||||
///
|
||||
/// If given an absolute path, returns it if the file exists and is executable.
|
||||
///
|
||||
/// If given a relative path, returns an absolute path to the file if
|
||||
/// it exists and is executable.
|
||||
///
|
||||
/// If given a string without path separators, looks for a file named
|
||||
/// `binary_name` at each directory in `$PATH` and if it finds an executable
|
||||
/// file there, returns it.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use which::which;
|
||||
/// use std::path::PathBuf;
|
||||
///
|
||||
/// let result = which::which("rustc").unwrap();
|
||||
/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
|
||||
///
|
||||
/// ```
|
||||
pub fn which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> {
|
||||
which_all(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
|
||||
}
|
||||
|
||||
/// Find an executable binary's path by name, ignoring `cwd`.
|
||||
///
|
||||
/// If given an absolute path, returns it if the file exists and is executable.
|
||||
///
|
||||
/// Does not resolve relative paths.
|
||||
///
|
||||
/// If given a string without path separators, looks for a file named
|
||||
/// `binary_name` at each directory in `$PATH` and if it finds an executable
|
||||
/// file there, returns it.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use which::which;
|
||||
/// use std::path::PathBuf;
|
||||
///
|
||||
/// let result = which::which_global("rustc").unwrap();
|
||||
/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
|
||||
///
|
||||
/// ```
|
||||
pub fn which_global<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> {
|
||||
which_all_global(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
|
||||
}
|
||||
|
||||
/// Find all binaries with `binary_name` using `cwd` to resolve relative paths.
|
||||
pub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = path::PathBuf>> {
|
||||
let cwd = env::current_dir().ok();
|
||||
|
||||
let binary_checker = build_binary_checker();
|
||||
|
||||
let finder = Finder::new();
|
||||
|
||||
finder.find(binary_name, env::var_os("PATH"), cwd, binary_checker)
|
||||
}
|
||||
|
||||
/// Find all binaries with `binary_name` ignoring `cwd`.
|
||||
pub fn which_all_global<T: AsRef<OsStr>>(
|
||||
binary_name: T,
|
||||
) -> Result<impl Iterator<Item = path::PathBuf>> {
|
||||
let binary_checker = build_binary_checker();
|
||||
|
||||
let finder = Finder::new();
|
||||
|
||||
finder.find(
|
||||
binary_name,
|
||||
env::var_os("PATH"),
|
||||
Option::<&Path>::None,
|
||||
binary_checker,
|
||||
)
|
||||
}
|
||||
|
||||
/// Find all binaries matching a regular expression in a the system PATH.
|
||||
///
|
||||
/// Only available when feature `regex` is enabled.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `regex` - A regular expression to match binaries with
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Find Python executables:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use regex::Regex;
|
||||
/// use which::which;
|
||||
/// use std::path::PathBuf;
|
||||
///
|
||||
/// let re = Regex::new(r"python\d$").unwrap();
|
||||
/// let binaries: Vec<PathBuf> = which::which_re(re).unwrap().collect();
|
||||
/// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")];
|
||||
/// assert_eq!(binaries, python_paths);
|
||||
/// ```
|
||||
///
|
||||
/// Find all cargo subcommand executables on the path:
|
||||
///
|
||||
/// ```
|
||||
/// use which::which_re;
|
||||
/// use regex::Regex;
|
||||
///
|
||||
/// which_re(Regex::new("^cargo-.*").unwrap()).unwrap()
|
||||
/// .for_each(|pth| println!("{}", pth.to_string_lossy()));
|
||||
/// ```
|
||||
#[cfg(feature = "regex")]
|
||||
pub fn which_re(regex: impl Borrow<Regex>) -> Result<impl Iterator<Item = path::PathBuf>> {
|
||||
which_re_in(regex, env::var_os("PATH"))
|
||||
}
|
||||
|
||||
/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
|
||||
pub fn 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>,
|
||||
{
|
||||
which_in_all(binary_name, paths, cwd)
|
||||
.and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
|
||||
}
|
||||
|
||||
/// Find all binaries matching a regular expression in a list of paths.
|
||||
///
|
||||
/// Only available when feature `regex` is enabled.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `regex` - A regular expression to match binaries with
|
||||
/// * `paths` - A string containing the paths to search
|
||||
/// (separated in the same way as the PATH environment variable)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use regex::Regex;
|
||||
/// use which::which;
|
||||
/// use std::path::PathBuf;
|
||||
///
|
||||
/// let re = Regex::new(r"python\d$").unwrap();
|
||||
/// let paths = Some("/usr/bin:/usr/local/bin");
|
||||
/// let binaries: Vec<PathBuf> = which::which_re_in(re, paths).unwrap().collect();
|
||||
/// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")];
|
||||
/// assert_eq!(binaries, python_paths);
|
||||
/// ```
|
||||
#[cfg(feature = "regex")]
|
||||
pub fn which_re_in<T>(
|
||||
regex: impl Borrow<Regex>,
|
||||
paths: Option<T>,
|
||||
) -> Result<impl Iterator<Item = path::PathBuf>>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
{
|
||||
let binary_checker = build_binary_checker();
|
||||
|
||||
let finder = Finder::new();
|
||||
|
||||
finder.find_re(regex, paths, binary_checker)
|
||||
}
|
||||
|
||||
/// Find all binaries with `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
|
||||
pub fn 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>,
|
||||
{
|
||||
let binary_checker = build_binary_checker();
|
||||
|
||||
let finder = Finder::new();
|
||||
|
||||
finder.find(binary_name, paths, Some(cwd), binary_checker)
|
||||
}
|
||||
|
||||
/// Find all binaries with `binary_name` in the path list `paths`, ignoring `cwd`.
|
||||
pub fn which_in_global<T, U>(
|
||||
binary_name: T,
|
||||
paths: Option<U>,
|
||||
) -> Result<impl Iterator<Item = path::PathBuf>>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
U: AsRef<OsStr>,
|
||||
{
|
||||
let binary_checker = build_binary_checker();
|
||||
|
||||
let finder = Finder::new();
|
||||
|
||||
finder.find(binary_name, paths, Option::<&Path>::None, binary_checker)
|
||||
}
|
||||
|
||||
fn build_binary_checker() -> CompositeChecker {
|
||||
CompositeChecker::new()
|
||||
.add_checker(Box::new(ExistedChecker::new()))
|
||||
.add_checker(Box::new(ExecutableChecker::new()))
|
||||
}
|
||||
|
||||
/// A wrapper containing all functionality in this crate.
|
||||
pub struct WhichConfig {
|
||||
cwd: Option<either::Either<bool, path::PathBuf>>,
|
||||
custom_path_list: Option<OsString>,
|
||||
binary_name: Option<OsString>,
|
||||
#[cfg(feature = "regex")]
|
||||
regex: Option<Regex>,
|
||||
}
|
||||
|
||||
impl Default for WhichConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cwd: Some(either::Either::Left(true)),
|
||||
custom_path_list: None,
|
||||
binary_name: None,
|
||||
#[cfg(feature = "regex")]
|
||||
regex: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
type Regex = regex::Regex;
|
||||
|
||||
#[cfg(not(feature = "regex"))]
|
||||
type Regex = ();
|
||||
|
||||
impl WhichConfig {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Whether or not to use the current working directory. `true` by default.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If regex was set previously, and you've just passed in `use_cwd: true`, this will panic.
|
||||
pub fn system_cwd(mut self, use_cwd: bool) -> Self {
|
||||
#[cfg(feature = "regex")]
|
||||
if self.regex.is_some() && use_cwd {
|
||||
panic!("which can't use regex and cwd at the same time!")
|
||||
}
|
||||
self.cwd = Some(either::Either::Left(use_cwd));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a custom path for resolving relative paths.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If regex was set previously, this will panic.
|
||||
pub fn custom_cwd(mut self, cwd: path::PathBuf) -> Self {
|
||||
#[cfg(feature = "regex")]
|
||||
if self.regex.is_some() {
|
||||
panic!("which can't use regex and cwd at the same time!")
|
||||
}
|
||||
self.cwd = Some(either::Either::Right(cwd));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the path name regex to search for. You ***MUST*** call this, or [`Self::binary_name`] prior to searching.
|
||||
///
|
||||
/// When `Regex` is disabled this function takes the unit type as a stand in. The parameter will change when
|
||||
/// `Regex` is enabled.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the `regex` feature wasn't turned on for this crate this will always panic. Additionally if a
|
||||
/// `cwd` (aka current working directory) or `binary_name` was set previously, this will panic, as those options
|
||||
/// are incompatible with `regex`.
|
||||
#[allow(unused_variables)]
|
||||
#[allow(unused_mut)]
|
||||
pub fn regex(mut self, regex: Regex) -> Self {
|
||||
#[cfg(not(feature = "regex"))]
|
||||
{
|
||||
panic!("which's regex feature was not enabled in your Cargo.toml!")
|
||||
}
|
||||
#[cfg(feature = "regex")]
|
||||
{
|
||||
if self.cwd != Some(either::Either::Left(false)) && self.cwd.is_some() {
|
||||
panic!("which can't use regex and cwd at the same time!")
|
||||
}
|
||||
if self.binary_name.is_some() {
|
||||
panic!("which can't use `binary_name` and `regex` at the same time!");
|
||||
}
|
||||
self.regex = Some(regex);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the path name to search for. You ***MUST*** call this, or [`Self::regex`] prior to searching.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If a `regex` was set previously this will panic as this is not compatible with `regex`.
|
||||
pub fn binary_name(mut self, name: OsString) -> Self {
|
||||
#[cfg(feature = "regex")]
|
||||
if self.regex.is_some() {
|
||||
panic!("which can't use `binary_name` and `regex` at the same time!");
|
||||
}
|
||||
self.binary_name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
/// Uses the given string instead of the `PATH` env variable.
|
||||
pub fn custom_path_list(mut self, custom_path_list: OsString) -> Self {
|
||||
self.custom_path_list = Some(custom_path_list);
|
||||
self
|
||||
}
|
||||
|
||||
/// Uses the `PATH` env variable. Enabled by default.
|
||||
pub fn system_path_list(mut self) -> Self {
|
||||
self.custom_path_list = None;
|
||||
self
|
||||
}
|
||||
|
||||
/// Finishes configuring, runs the query and returns the first result.
|
||||
pub fn first_result(self) -> Result<path::PathBuf> {
|
||||
self.all_results()
|
||||
.and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
|
||||
}
|
||||
|
||||
/// Finishes configuring, runs the query and returns all results.
|
||||
pub fn all_results(self) -> Result<impl Iterator<Item = path::PathBuf>> {
|
||||
let binary_checker = build_binary_checker();
|
||||
|
||||
let finder = Finder::new();
|
||||
|
||||
let paths = self.custom_path_list.or_else(|| env::var_os("PATH"));
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
if let Some(regex) = self.regex {
|
||||
return finder
|
||||
.find_re(regex, paths, binary_checker)
|
||||
.map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf>>);
|
||||
}
|
||||
|
||||
let cwd = match self.cwd {
|
||||
Some(either::Either::Left(false)) => None,
|
||||
Some(either::Either::Right(custom)) => Some(custom),
|
||||
None | Some(either::Either::Left(true)) => env::current_dir().ok(),
|
||||
};
|
||||
|
||||
finder
|
||||
.find(
|
||||
self.binary_name.expect(
|
||||
"binary_name not set! You must set binary_name or regex before searching!",
|
||||
),
|
||||
paths,
|
||||
cwd,
|
||||
binary_checker,
|
||||
)
|
||||
.map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf>>)
|
||||
}
|
||||
}
|
||||
|
||||
/// An owned, immutable wrapper around a `PathBuf` containing the path of an executable.
|
||||
///
|
||||
/// The constructed `PathBuf` is the output of `which` or `which_in`, but `which::Path` has the
|
||||
/// advantage of being a type distinct from `std::path::Path` and `std::path::PathBuf`.
|
||||
///
|
||||
/// It can be beneficial to use `which::Path` instead of `std::path::Path` when you want the type
|
||||
/// system to enforce the need for a path that exists and points to a binary that is executable.
|
||||
///
|
||||
/// Since `which::Path` implements `Deref` for `std::path::Path`, all methods on `&std::path::Path`
|
||||
/// are also available to `&which::Path` values.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Path {
|
||||
inner: path::PathBuf,
|
||||
}
|
||||
|
||||
impl Path {
|
||||
/// Returns the path of an executable binary by name.
|
||||
///
|
||||
/// This calls `which` and maps the result into a `Path`.
|
||||
pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path> {
|
||||
which(binary_name).map(|inner| Path { inner })
|
||||
}
|
||||
|
||||
/// Returns the paths of all executable binaries by a name.
|
||||
///
|
||||
/// this calls `which_all` and maps the results into `Path`s.
|
||||
pub fn all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = Path>> {
|
||||
which_all(binary_name).map(|inner| inner.map(|inner| Path { inner }))
|
||||
}
|
||||
|
||||
/// Returns the path of an executable binary by name in the path list `paths` and using the
|
||||
/// current working directory `cwd` to resolve relative paths.
|
||||
///
|
||||
/// This calls `which_in` and maps the result into a `Path`.
|
||||
pub fn 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>,
|
||||
{
|
||||
which_in(binary_name, paths, cwd).map(|inner| Path { inner })
|
||||
}
|
||||
|
||||
/// Returns all paths of an executable binary by name in the path list `paths` and using the
|
||||
/// current working directory `cwd` to resolve relative paths.
|
||||
///
|
||||
/// This calls `which_in_all` and maps the results into a `Path`.
|
||||
pub fn 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>,
|
||||
{
|
||||
which_in_all(binary_name, paths, cwd).map(|inner| inner.map(|inner| Path { inner }))
|
||||
}
|
||||
|
||||
/// Returns a reference to a `std::path::Path`.
|
||||
pub fn as_path(&self) -> &path::Path {
|
||||
self.inner.as_path()
|
||||
}
|
||||
|
||||
/// Consumes the `which::Path`, yielding its underlying `std::path::PathBuf`.
|
||||
pub fn into_path_buf(self) -> path::PathBuf {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Path {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.inner, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Path {
|
||||
type Target = path::Path;
|
||||
|
||||
fn deref(&self) -> &path::Path {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<path::Path> for Path {
|
||||
fn as_ref(&self) -> &path::Path {
|
||||
self.as_path()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<OsStr> for Path {
|
||||
fn as_ref(&self) -> &OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<path::PathBuf> for Path {
|
||||
fn eq(&self, other: &path::PathBuf) -> bool {
|
||||
self.inner == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Path> for path::PathBuf {
|
||||
fn eq(&self, other: &Path) -> bool {
|
||||
*self == other.inner
|
||||
}
|
||||
}
|
||||
|
||||
/// An owned, immutable wrapper around a `PathBuf` containing the _canonical_ path of an
|
||||
/// executable.
|
||||
///
|
||||
/// The constructed `PathBuf` is the result of `which` or `which_in` followed by
|
||||
/// `Path::canonicalize`, but `CanonicalPath` has the advantage of being a type distinct from
|
||||
/// `std::path::Path` and `std::path::PathBuf`.
|
||||
///
|
||||
/// It can be beneficial to use `CanonicalPath` instead of `std::path::Path` when you want the type
|
||||
/// system to enforce the need for a path that exists, points to a binary that is executable, is
|
||||
/// absolute, has all components normalized, and has all symbolic links resolved
|
||||
///
|
||||
/// Since `CanonicalPath` implements `Deref` for `std::path::Path`, all methods on
|
||||
/// `&std::path::Path` are also available to `&CanonicalPath` values.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct CanonicalPath {
|
||||
inner: path::PathBuf,
|
||||
}
|
||||
|
||||
impl CanonicalPath {
|
||||
/// Returns the canonical path of an executable binary by name.
|
||||
///
|
||||
/// This calls `which` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
|
||||
pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath> {
|
||||
which(binary_name)
|
||||
.and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize))
|
||||
.map(|inner| CanonicalPath { inner })
|
||||
}
|
||||
|
||||
/// Returns the canonical paths of an executable binary by name.
|
||||
///
|
||||
/// This calls `which_all` and `Path::canonicalize` and maps the results into `CanonicalPath`s.
|
||||
pub fn all<T: AsRef<OsStr>>(
|
||||
binary_name: T,
|
||||
) -> Result<impl Iterator<Item = Result<CanonicalPath>>> {
|
||||
which_all(binary_name).map(|inner| {
|
||||
inner.map(|inner| {
|
||||
inner
|
||||
.canonicalize()
|
||||
.map_err(|_| Error::CannotCanonicalize)
|
||||
.map(|inner| CanonicalPath { inner })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the canonical path of an executable binary by name in the path list `paths` and
|
||||
/// using the current working directory `cwd` to resolve relative paths.
|
||||
///
|
||||
/// This calls `which_in` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
|
||||
pub fn 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>,
|
||||
{
|
||||
which_in(binary_name, paths, cwd)
|
||||
.and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize))
|
||||
.map(|inner| CanonicalPath { inner })
|
||||
}
|
||||
|
||||
/// Returns all of the canonical paths of an executable binary by name in the path list `paths` and
|
||||
/// using the current working directory `cwd` to resolve relative paths.
|
||||
///
|
||||
/// This calls `which_in_all` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
|
||||
pub fn 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>,
|
||||
{
|
||||
which_in_all(binary_name, paths, cwd).map(|inner| {
|
||||
inner.map(|inner| {
|
||||
inner
|
||||
.canonicalize()
|
||||
.map_err(|_| Error::CannotCanonicalize)
|
||||
.map(|inner| CanonicalPath { inner })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a reference to a `std::path::Path`.
|
||||
pub fn as_path(&self) -> &path::Path {
|
||||
self.inner.as_path()
|
||||
}
|
||||
|
||||
/// Consumes the `which::CanonicalPath`, yielding its underlying `std::path::PathBuf`.
|
||||
pub fn into_path_buf(self) -> path::PathBuf {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for CanonicalPath {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.inner, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for CanonicalPath {
|
||||
type Target = path::Path;
|
||||
|
||||
fn deref(&self) -> &path::Path {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<path::Path> for CanonicalPath {
|
||||
fn as_ref(&self) -> &path::Path {
|
||||
self.as_path()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<OsStr> for CanonicalPath {
|
||||
fn as_ref(&self) -> &OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<path::PathBuf> for CanonicalPath {
|
||||
fn eq(&self, other: &path::PathBuf) -> bool {
|
||||
self.inner == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<CanonicalPath> for path::PathBuf {
|
||||
fn eq(&self, other: &CanonicalPath) -> bool {
|
||||
*self == other.inner
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue