which-3.0.0/.gitignore010064400017500001737000000000221324120024500130150ustar0000000000000000target Cargo.lock which-3.0.0/.travis.yml010064400017500001737000000003221354160475300131600ustar0000000000000000language: rust os: - linux - osx rust: - stable cache: directories: - $HOME/.cargo script: - cargo build --all - cargo test - cargo test --no-default-features - cargo doc --all --no-depswhich-3.0.0/Cargo.toml.orig010064400017500001737000000012211354160731600137330ustar0000000000000000[package] name = "which" version = "3.0.0" authors = ["Harry Fei "] repository = "https://github.com/harryfei/which-rs.git" documentation = "https://docs.rs/which/" license = "MIT" description = "A Rust equivalent of Unix command \"which\". Locate installed executable in cross platforms." readme = "README.md" categories = ["os", "filesystem"] keywords = ["which", "which-rs", "unix", "command"] [dependencies] libc = "0.2.10" [dependencies.failure] version = "0.1.1" default-features = false features = ["std"] optional = true [dev-dependencies] tempdir = "0.3.4" [features] default = ["use_failure"] use_failure = ["failure"] which-3.0.0/Cargo.toml0000644000000022540000000000000101760ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "which" version = "3.0.0" authors = ["Harry Fei "] description = "A Rust equivalent of Unix command \"which\". Locate installed executable in cross platforms." documentation = "https://docs.rs/which/" readme = "README.md" keywords = ["which", "which-rs", "unix", "command"] categories = ["os", "filesystem"] license = "MIT" repository = "https://github.com/harryfei/which-rs.git" [dependencies.failure] version = "0.1.1" features = ["std"] optional = true default-features = false [dependencies.libc] version = "0.2.10" [dev-dependencies.tempdir] version = "0.3.4" [features] default = ["use_failure"] use_failure = ["failure"] which-3.0.0/LICENSE.txt010064400017500001737000000020401324120024500126520ustar0000000000000000Copyright (c) 2015 fangyuanziti Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. which-3.0.0/README.md010064400017500001737000000012741354160731600123330ustar0000000000000000[![Travis Build Status](https://travis-ci.org/harryfei/which-rs.svg?branch=master)](https://travis-ci.org/harryfei/which-rs) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/1y40b135iaixs9x6?svg=true)](https://ci.appveyor.com/project/HarryFei/which-rs) # which A Rust equivalent of Unix command "which". Locate installed executable in cross platforms. ## Support platforms * Linux * Windows * macOS ## Example To find which rustc exectable binary is using. ``` rust use which::which; let result = which::which("rustc").unwrap(); assert_eq!(result, PathBuf::from("/usr/bin/rustc")); ``` ## Documentation The documentation is [available online](https://docs.rs/which/). which-3.0.0/appveyor.yml010064400017500001737000000014211354160475300134400ustar0000000000000000os: Visual Studio 2015 environment: matrix: - channel: stable target: x86_64-pc-windows-msvc - channel: stable target: i686-pc-windows-msvc - channel: stable target: x86_64-pc-windows-gnu - channel: stable target: i686-pc-windows-gnu install: # Set PATH for MinGW toolset - if %target% == x86_64-pc-windows-gnu set PATH=%PATH%;C:\msys64\mingw64\bin - if %target% == i686-pc-windows-gnu set PATH=%PATH%;C:\msys64\mingw32\bin # Install Rust toolset - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain %channel% --default-host %target% - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - rustc -vV - cargo -vV build: false test_script: - cargo test - cargo test --no-default-features which-3.0.0/src/checker.rs010064400017500001737000000027031354160731600136130ustar0000000000000000use finder::Checker; #[cfg(unix)] use libc; #[cfg(unix)] use std::ffi::CString; use std::fs; #[cfg(unix)] use std::os::unix::ffi::OsStrExt; use std::path::Path; pub struct ExecutableChecker; impl ExecutableChecker { pub fn new() -> ExecutableChecker { ExecutableChecker } } impl Checker for ExecutableChecker { #[cfg(unix)] fn is_valid(&self, path: &Path) -> bool { CString::new(path.as_os_str().as_bytes()) .and_then(|c| Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 })) .unwrap_or(false) } #[cfg(windows)] fn is_valid(&self, _path: &Path) -> bool { true } } pub struct ExistedChecker; impl ExistedChecker { pub fn new() -> ExistedChecker { ExistedChecker } } impl Checker for ExistedChecker { fn is_valid(&self, path: &Path) -> bool { fs::metadata(path) .map(|metadata| metadata.is_file()) .unwrap_or(false) } } pub struct CompositeChecker { checkers: Vec>, } impl CompositeChecker { pub fn new() -> CompositeChecker { CompositeChecker { checkers: Vec::new(), } } pub fn add_checker(mut self, checker: Box) -> 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)) } } which-3.0.0/src/error.rs010064400017500001737000000043051354160731600133400ustar0000000000000000#[cfg(feature = "use_failure")] use failure::{Backtrace, Context, Fail}; use std; use std::fmt::{self, Display}; #[derive(Debug)] pub struct Error { #[cfg(feature = "use_failure")] inner: Context, #[cfg(not(feature = "use_failure"))] inner: ErrorKind, } // To suppress false positives from cargo-clippy #[cfg_attr(feature = "cargo-clippy", allow(empty_line_after_outer_attr))] #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum ErrorKind { BadAbsolutePath, BadRelativePath, CannotFindBinaryPath, CannotGetCurrentDir, CannotCanonicalize, } #[cfg(feature = "use_failure")] impl Fail for ErrorKind {} impl Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let display = match *self { ErrorKind::BadAbsolutePath => "Bad absolute path", ErrorKind::BadRelativePath => "Bad relative path", ErrorKind::CannotFindBinaryPath => "Cannot find binary path", ErrorKind::CannotGetCurrentDir => "Cannot get current directory", ErrorKind::CannotCanonicalize => "Cannot canonicalize path", }; f.write_str(display) } } #[cfg(feature = "use_failure")] impl Fail for Error { fn cause(&self) -> Option<&dyn Fail> { self.inner.cause() } fn backtrace(&self) -> Option<&Backtrace> { self.inner.backtrace() } } impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.inner, f) } } impl Error { pub fn kind(&self) -> ErrorKind { #[cfg(feature = "use_failure")] { *self.inner.get_context() } #[cfg(not(feature = "use_failure"))] { self.inner } } } impl From for Error { fn from(kind: ErrorKind) -> Error { Error { #[cfg(feature = "use_failure")] inner: Context::new(kind), #[cfg(not(feature = "use_failure"))] inner: kind, } } } #[cfg(feature = "use_failure")] impl From> for Error { fn from(inner: Context) -> Error { Error { inner } } } pub type Result = std::result::Result; which-3.0.0/src/finder.rs010064400017500001737000000103221354160731600134520ustar0000000000000000use error::*; #[cfg(windows)] use helper::has_executable_extension; use std::env; use std::ffi::OsStr; #[cfg(windows)] use std::ffi::OsString; use std::iter; use std::path::{Path, PathBuf}; pub trait Checker { fn is_valid(&self, path: &Path) -> bool; } trait PathExt { fn has_separator(&self) -> bool; fn to_absolute

(self, cwd: P) -> PathBuf where P: AsRef; } impl PathExt for PathBuf { fn has_separator(&self) -> bool { self.components().count() > 1 } fn to_absolute

(self, cwd: P) -> PathBuf where P: AsRef, { 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( &self, binary_name: T, paths: Option, cwd: V, binary_checker: &dyn Checker, ) -> Result where T: AsRef, U: AsRef, V: AsRef, { let path = PathBuf::from(&binary_name); let binary_path_candidates: Box> = if path.has_separator() { // Search binary in cwd if the path have a path separator. let candidates = Self::cwd_search_candidates(path, cwd).into_iter(); Box::new(candidates) } else { // Search binary in PATHs(defined in environment variable). let p = paths.ok_or(ErrorKind::CannotFindBinaryPath)?; let paths: Vec<_> = env::split_paths(&p).collect(); let candidates = Self::path_search_candidates(path, paths).into_iter(); Box::new(candidates) }; for p in binary_path_candidates { // find a valid binary if binary_checker.is_valid(&p) { return Ok(p); } } // can't find any binary return Err(ErrorKind::CannotFindBinaryPath.into()); } fn cwd_search_candidates(binary_name: PathBuf, cwd: C) -> impl IntoIterator where C: AsRef, { let path = binary_name.to_absolute(cwd); Self::append_extension(iter::once(path)) } fn path_search_candidates

( binary_name: PathBuf, paths: P, ) -> impl IntoIterator where P: IntoIterator, { let new_paths = paths.into_iter().map(move |p| p.join(binary_name.clone())); Self::append_extension(new_paths) } #[cfg(unix)] fn append_extension

(paths: P) -> impl IntoIterator where P: IntoIterator, { paths } #[cfg(windows)] fn append_extension

(paths: P) -> impl IntoIterator where P: IntoIterator, { // Read PATHEXT env variable and split it into vector of String let path_exts = env::var_os("PATHEXT").unwrap_or(OsString::from(env::consts::EXE_EXTENSION)); let exe_extension_vec = env::split_paths(&path_exts) .filter_map(|e| e.to_str().map(|e| e.to_owned())) .collect::>(); paths .into_iter() .flat_map(move |p| -> Box> { // Check if path already have executable extension if has_executable_extension(&p, &exe_extension_vec) { Box::new(iter::once(p)) } else { // Appended paths with windows executable extensions. // e.g. path `c:/windows/bin` will expend to: // c:/windows/bin.COM // c:/windows/bin.EXE // c:/windows/bin.CMD // ... let ps = exe_extension_vec.clone().into_iter().map(move |e| { // Append the extension. let mut p = p.clone().to_path_buf().into_os_string(); p.push(e); PathBuf::from(p) }); Box::new(ps) } }) } } which-3.0.0/src/helper.rs010064400017500001737000000020351334243044100134540ustar0000000000000000use std::path::Path; /// Check if given path has extension which in the given vector. pub fn has_executable_extension, S: AsRef>(path: T, exts_vec: &Vec) -> bool { let ext = path.as_ref().extension().and_then(|e| e.to_str()); match ext { Some(ext) => exts_vec .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"), &vec![".COM", ".EXE", ".CMD"] )); assert!(has_executable_extension( PathBuf::from("foo.CMD"), &vec![".COM", ".EXE", ".CMD"] )); } #[test] fn test_extension_not_in_extension_vector() { assert!(!has_executable_extension( PathBuf::from("foo.bar"), &vec![".COM", ".EXE", ".CMD"] )); } } which-3.0.0/src/lib.rs010064400017500001737000000172661354160475300127710ustar0000000000000000//! which //! //! A Rust equivalent of Unix command `which(1)`. //! # Example: //! //! To find which rustc executable binary is using: //! //! ``` norun //! use which::which; //! //! let result = which::which("rustc").unwrap(); //! assert_eq!(result, PathBuf::from("/usr/bin/rustc")); //! //! ``` #[cfg(feature = "use_failure")] extern crate failure; extern crate libc; #[cfg(feature = "use_failure")] use failure::ResultExt; mod checker; mod error; mod finder; #[cfg(windows)] mod helper; use std::env; use std::fmt; use std::path; use std::ffi::OsStr; use checker::CompositeChecker; use checker::ExecutableChecker; use checker::ExistedChecker; pub use error::*; use finder::Finder; /// Find a exectable 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 /// /// ``` norun /// use which::which; /// use std::path::PathBuf; /// /// let result = which::which("rustc").unwrap(); /// assert_eq!(result, PathBuf::from("/usr/bin/rustc")); /// /// ``` pub fn which>(binary_name: T) -> Result { #[cfg(feature = "use_failure")] let cwd = env::current_dir().context(ErrorKind::CannotGetCurrentDir)?; #[cfg(not(feature = "use_failure"))] let cwd = env::current_dir().map_err(|_| ErrorKind::CannotGetCurrentDir)?; which_in(binary_name, env::var_os("PATH"), &cwd) } /// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths. pub fn which_in(binary_name: T, paths: Option, cwd: V) -> Result where T: AsRef, U: AsRef, V: AsRef, { let binary_checker = CompositeChecker::new() .add_checker(Box::new(ExistedChecker::new())) .add_checker(Box::new(ExecutableChecker::new())); let finder = Finder::new(); finder.find(binary_name, paths, cwd, &binary_checker) } /// 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)] 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>(binary_name: T) -> Result { which(binary_name).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(binary_name: T, paths: Option, cwd: V) -> Result where T: AsRef, U: AsRef, V: AsRef, { which_in(binary_name, paths, cwd).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 for Path { fn as_ref(&self) -> &path::Path { self.as_path() } } impl AsRef for Path { fn as_ref(&self) -> &OsStr { self.as_os_str() } } impl Eq for Path {} impl PartialEq for Path { fn eq(&self, other: &path::PathBuf) -> bool { self.inner == *other } } impl PartialEq 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)] 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>(binary_name: T) -> Result { which(binary_name) .and_then(|p| { p.canonicalize() .map_err(|_| ErrorKind::CannotCanonicalize.into()) }) .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` and `Path::canonicalize` and maps the result into a `CanonicalPath`. pub fn new_in(binary_name: T, paths: Option, cwd: V) -> Result where T: AsRef, U: AsRef, V: AsRef, { which_in(binary_name, paths, cwd) .and_then(|p| { p.canonicalize() .map_err(|_| ErrorKind::CannotCanonicalize.into()) }) .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 for CanonicalPath { fn as_ref(&self) -> &path::Path { self.as_path() } } impl AsRef for CanonicalPath { fn as_ref(&self) -> &OsStr { self.as_os_str() } } impl Eq for CanonicalPath {} impl PartialEq for CanonicalPath { fn eq(&self, other: &path::PathBuf) -> bool { self.inner == *other } } impl PartialEq for path::PathBuf { fn eq(&self, other: &CanonicalPath) -> bool { *self == other.inner } } which-3.0.0/tests/basic.rs010064400017500001737000000173231354160475300136510ustar0000000000000000extern crate tempdir; extern crate which; use std::env; use std::ffi::{OsStr, OsString}; use std::fs; use std::io; use std::path::{Path, PathBuf}; use tempdir::TempDir; struct TestFixture { /// Temp directory. pub tempdir: TempDir, /// $PATH pub paths: OsString, /// Binaries created in $PATH pub bins: Vec, } const SUBDIRS: &'static [&'static str] = &["a", "b", "c"]; const BIN_NAME: &'static str = "bin"; #[cfg(unix)] fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result { use std::os::unix::fs::OpenOptionsExt; let bin = dir.join(path).with_extension(extension); fs::OpenOptions::new() .write(true) .create(true) .mode(0o666 | (libc::S_IXUSR as u32)) .open(&bin) .and_then(|_f| bin.canonicalize()) } fn touch(dir: &Path, path: &str, extension: &str) -> io::Result { let b = dir.join(path).with_extension(extension); fs::File::create(&b).and_then(|_f| b.canonicalize()) } #[cfg(windows)] fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result { touch(dir, path, extension) } impl TestFixture { // tmp/a/bin // tmp/a/bin.exe // tmp/a/bin.cmd // tmp/b/bin // tmp/b/bin.exe // tmp/b/bin.cmd // tmp/c/bin // tmp/c/bin.exe // tmp/c/bin.cmd pub fn new() -> TestFixture { let tempdir = TempDir::new("which_tests").unwrap(); let mut builder = fs::DirBuilder::new(); builder.recursive(true); let mut paths = vec![]; let mut bins = vec![]; for d in SUBDIRS.iter() { let p = tempdir.path().join(d); builder.create(&p).unwrap(); bins.push(mk_bin(&p, &BIN_NAME, "").unwrap()); bins.push(mk_bin(&p, &BIN_NAME, "exe").unwrap()); bins.push(mk_bin(&p, &BIN_NAME, "cmd").unwrap()); paths.push(p); } TestFixture { tempdir: tempdir, paths: env::join_paths(paths).unwrap(), bins: bins, } } #[allow(dead_code)] pub fn touch(&self, path: &str, extension: &str) -> io::Result { touch(self.tempdir.path(), &path, &extension) } pub fn mk_bin(&self, path: &str, extension: &str) -> io::Result { mk_bin(self.tempdir.path(), &path, &extension) } } fn _which>(f: &TestFixture, path: T) -> which::Result { which::CanonicalPath::new_in(path, Some(f.paths.clone()), f.tempdir.path()) } #[test] #[cfg(unix)] fn it_works() { use std::process::Command; let result = which::Path::new("rustc"); assert!(result.is_ok()); let which_result = Command::new("which").arg("rustc").output(); assert_eq!( String::from(result.unwrap().to_str().unwrap()), String::from_utf8(which_result.unwrap().stdout) .unwrap() .trim() ); } #[test] #[cfg(unix)] fn test_which() { let f = TestFixture::new(); assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[0]) } #[test] #[cfg(windows)] fn test_which() { let f = TestFixture::new(); assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[1]) } #[test] #[cfg(unix)] fn test_which_extension() { let f = TestFixture::new(); let b = Path::new(&BIN_NAME).with_extension(""); assert_eq!(_which(&f, &b).unwrap(), f.bins[0]) } #[test] #[cfg(windows)] fn test_which_extension() { let f = TestFixture::new(); let b = Path::new(&BIN_NAME).with_extension("cmd"); assert_eq!(_which(&f, &b).unwrap(), f.bins[2]) } #[test] fn test_which_not_found() { let f = TestFixture::new(); assert!(_which(&f, "a").is_err()); } #[test] fn test_which_second() { let f = TestFixture::new(); let b = f.mk_bin("b/another", env::consts::EXE_EXTENSION).unwrap(); assert_eq!(_which(&f, "another").unwrap(), b); } #[test] #[cfg(unix)] fn test_which_absolute() { let f = TestFixture::new(); assert_eq!( _which(&f, &f.bins[3]).unwrap(), f.bins[3].canonicalize().unwrap() ); } #[test] #[cfg(windows)] fn test_which_absolute() { let f = TestFixture::new(); assert_eq!( _which(&f, &f.bins[4]).unwrap(), f.bins[4].canonicalize().unwrap() ); } #[test] #[cfg(windows)] fn test_which_absolute_path_case() { // Test that an absolute path with an uppercase extension // is accepted. let f = TestFixture::new(); let p = &f.bins[4]; assert_eq!(_which(&f, &p).unwrap(), f.bins[4].canonicalize().unwrap()); } #[test] #[cfg(unix)] fn test_which_absolute_extension() { let f = TestFixture::new(); // Don't append EXE_EXTENSION here. let b = f.bins[3].parent().unwrap().join(&BIN_NAME); assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap()); } #[test] #[cfg(windows)] fn test_which_absolute_extension() { let f = TestFixture::new(); // Don't append EXE_EXTENSION here. let b = f.bins[4].parent().unwrap().join(&BIN_NAME); assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap()); } #[test] #[cfg(unix)] fn test_which_relative() { let f = TestFixture::new(); assert_eq!( _which(&f, "b/bin").unwrap(), f.bins[3].canonicalize().unwrap() ); } #[test] #[cfg(windows)] fn test_which_relative() { let f = TestFixture::new(); assert_eq!( _which(&f, "b/bin").unwrap(), f.bins[4].canonicalize().unwrap() ); } #[test] #[cfg(unix)] fn test_which_relative_extension() { // test_which_relative tests a relative path without an extension, // so test a relative path with an extension here. let f = TestFixture::new(); let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION); assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap()); } #[test] #[cfg(windows)] fn test_which_relative_extension() { // test_which_relative tests a relative path without an extension, // so test a relative path with an extension here. let f = TestFixture::new(); let b = Path::new("b/bin").with_extension("cmd"); assert_eq!(_which(&f, &b).unwrap(), f.bins[5].canonicalize().unwrap()); } #[test] #[cfg(windows)] fn test_which_relative_extension_case() { // Test that a relative path with an uppercase extension // is accepted. let f = TestFixture::new(); let b = Path::new("b/bin").with_extension("EXE"); assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap()); } #[test] #[cfg(unix)] fn test_which_relative_leading_dot() { let f = TestFixture::new(); assert_eq!( _which(&f, "./b/bin").unwrap(), f.bins[3].canonicalize().unwrap() ); } #[test] #[cfg(windows)] fn test_which_relative_leading_dot() { let f = TestFixture::new(); assert_eq!( _which(&f, "./b/bin").unwrap(), f.bins[4].canonicalize().unwrap() ); } #[test] #[cfg(unix)] fn test_which_non_executable() { // Shouldn't return non-executable files. let f = TestFixture::new(); f.touch("b/another", "").unwrap(); assert!(_which(&f, "another").is_err()); } #[test] #[cfg(unix)] fn test_which_absolute_non_executable() { // Shouldn't return non-executable files, even if given an absolute path. let f = TestFixture::new(); let b = f.touch("b/another", "").unwrap(); assert!(_which(&f, &b).is_err()); } #[test] #[cfg(unix)] fn test_which_relative_non_executable() { // Shouldn't return non-executable files. let f = TestFixture::new(); f.touch("b/another", "").unwrap(); assert!(_which(&f, "b/another").is_err()); } #[test] #[cfg(feature = "use_failure")] fn test_failure() { let f = TestFixture::new(); let run = || -> std::result::Result { // Test the conversion to failure let p = _which(&f, "./b/bin")?; Ok(p.into_path_buf()) }; let _ = run(); } which-3.0.0/.cargo_vcs_info.json0000644000000001120000000000000121670ustar00{ "git": { "sha1": "b4b622676b1f0d3b335726a89eb88662fa71fc88" } }