diff options
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | .github/workflows/rust.yml | 28 | ||||
-rw-r--r-- | .travis.yml | 18 | ||||
-rw-r--r-- | Android.bp | 14 | ||||
-rw-r--r-- | Cargo.toml | 9 | ||||
-rw-r--r-- | Cargo.toml.orig | 5 | ||||
-rw-r--r-- | METADATA | 10 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | TEST_MAPPING | 8 | ||||
-rw-r--r-- | appveyor.yml | 29 | ||||
-rw-r--r-- | src/checker.rs | 2 | ||||
-rw-r--r-- | src/error.rs | 23 | ||||
-rw-r--r-- | src/finder.rs | 29 | ||||
-rw-r--r-- | src/lib.rs | 106 | ||||
-rw-r--r-- | tests/basic.rs | 30 |
15 files changed, 205 insertions, 111 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index a84fc42..fb1169d 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "b5ab0940278ff0e5a5f864a4138098f5fbd9d868" + "sha1": "2c54067bab846e96f07be60e78250f385825f09f" } } diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..288ccaf --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,28 @@ +name: Rust + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + CARGO_TERM_COLOR: always + +jobs: + + test: + name: Build and test + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + + steps: + - uses: actions/checkout@v2 + - run: cargo build --verbose + - run: cargo test --verbose diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0de7621..0000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: 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-deps
\ No newline at end of file @@ -1,4 +1,5 @@ // This file is generated by cargo2android.py --run --dependencies --device --features=. +// Do not modify this file as changes will be overridden on upgrade. package { default_applicable_licenses: ["external_rust_crates_which_license"], @@ -22,18 +23,13 @@ rust_library { host_supported: true, crate_name: "which", srcs: ["src/lib.rs"], - edition: "2015", + edition: "2018", rustlibs: [ + "libeither", "liblibc", - "libthiserror", ], } // dependent_library ["feature_list"] -// libc-0.2.72 "default,std" -// proc-macro2-1.0.18 "default,proc-macro" -// quote-1.0.7 "default,proc-macro" -// syn-1.0.34 "clone-impls,default,derive,parsing,printing,proc-macro,quote" -// thiserror-1.0.20 -// thiserror-impl-1.0.20 -// unicode-xid-0.2.1 "default" +// either-1.6.1 "default,use_std" +// libc-0.2.92 "default,std" @@ -11,8 +11,9 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "which" -version = "4.0.2" +version = "4.1.0" authors = ["Harry Fei <tiziyuanfang@gmail.com>"] description = "A Rust equivalent of Unix command \"which\". Locate installed executable in cross platforms." documentation = "https://docs.rs/which/" @@ -21,10 +22,10 @@ keywords = ["which", "which-rs", "unix", "command"] categories = ["os", "filesystem"] license = "MIT" repository = "https://github.com/harryfei/which-rs.git" +[dependencies.either] +version = "1.6" + [dependencies.libc] version = "0.2.65" - -[dependencies.thiserror] -version = "1.0" [dev-dependencies.tempdir] version = "0.3.7" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 20f06bf..c3c472e 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,7 @@ [package] name = "which" -version = "4.0.2" +version = "4.1.0" +edition = "2018" authors = ["Harry Fei <tiziyuanfang@gmail.com>"] repository = "https://github.com/harryfei/which-rs.git" documentation = "https://docs.rs/which/" @@ -11,8 +12,8 @@ categories = ["os", "filesystem"] keywords = ["which", "which-rs", "unix", "command"] [dependencies] +either = "1.6" libc = "0.2.65" -thiserror = "1.0" [dev-dependencies] tempdir = "0.3.7" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/which/which-4.0.2.crate" + value: "https://static.crates.io/crates/which/which-4.1.0.crate" } - version: "4.0.2" + version: "4.1.0" license_type: NOTICE last_upgrade_date { - year: 2020 - month: 8 - day: 4 + year: 2021 + month: 4 + day: 2 } } @@ -1,5 +1,4 @@ -[![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) +[![Build Status](https://github.com/harryfei/which-rs/actions/workflows/rust.yml/badge.svg)](https://github.com/harryfei/which-rs/actions/workflows/rust.yml) # which diff --git a/TEST_MAPPING b/TEST_MAPPING index 6716814..df48c8d 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,8 +1,14 @@ -// Generated by cargo2android.py for tests in Android.bp +// Generated by update_crate_tests.py for tests that depend on this crate. { "presubmit": [ { "name": "libsqlite3-sys_device_test_src_lib" + }, + { + "name": "keystore2_test" + }, + { + "name": "vpnprofilestore_test" } ] } diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index e8beb07..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,29 +0,0 @@ -os: 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 diff --git a/src/checker.rs b/src/checker.rs index 94ef31a..62b78a2 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -1,4 +1,4 @@ -use finder::Checker; +use crate::finder::Checker; #[cfg(unix)] use libc; #[cfg(unix)] diff --git a/src/error.rs b/src/error.rs index 708c884..6d800a6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,17 +1,26 @@ -use thiserror; +use std::fmt; pub type Result<T> = std::result::Result<T, Error>; -#[derive(thiserror::Error, Copy, Clone, Eq, PartialEq, Debug)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum Error { - #[error("bad absolute path")] BadAbsolutePath, - #[error("bad relative path")] BadRelativePath, - #[error("cannot find binary path")] CannotFindBinaryPath, - #[error("cannot get current directory")] CannotGetCurrentDir, - #[error("cannot canonicalize path")] 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"), + } + } +} diff --git a/src/finder.rs b/src/finder.rs index d23cbaa..91c6cab 100644 --- a/src/finder.rs +++ b/src/finder.rs @@ -1,6 +1,8 @@ -use error::*; +use crate::checker::CompositeChecker; +use crate::error::*; +use either::Either; #[cfg(windows)] -use helper::has_executable_extension; +use crate::helper::has_executable_extension; use std::env; use std::ffi::OsStr; #[cfg(windows)] @@ -51,8 +53,8 @@ impl Finder { binary_name: T, paths: Option<U>, cwd: V, - binary_checker: &dyn Checker, - ) -> Result<PathBuf> + binary_checker: CompositeChecker, + ) -> Result<impl Iterator<Item = PathBuf>> where T: AsRef<OsStr>, U: AsRef<OsStr>, @@ -60,29 +62,18 @@ impl Finder { { let path = PathBuf::from(&binary_name); - let binary_path_candidates: Box<dyn Iterator<Item = _>> = if path.has_separator() { + let binary_path_candidates = 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) + Either::Left(Self::cwd_search_candidates(path, cwd).into_iter()) } else { // Search binary in PATHs(defined in environment variable). let p = paths.ok_or(Error::CannotFindBinaryPath)?; let paths: Vec<_> = env::split_paths(&p).collect(); - let candidates = Self::path_search_candidates(path, paths).into_iter(); - - Box::new(candidates) + Either::Right(Self::path_search_candidates(path, paths).into_iter()) }; - for p in binary_path_candidates { - // find a valid binary - if binary_checker.is_valid(&p) { - return Ok(p); - } - } - - // can't find any binary - Err(Error::CannotFindBinaryPath) + Ok(binary_path_candidates.filter(move |p| binary_checker.is_valid(p))) } fn cwd_search_candidates<C>(binary_name: PathBuf, cwd: C) -> impl IntoIterator<Item = PathBuf> @@ -5,17 +5,15 @@ //! //! To find which rustc executable binary is using: //! -//! ``` norun +//! ```no_run //! use which::which; +//! use std::path::PathBuf; //! //! let result = which::which("rustc").unwrap(); //! assert_eq!(result, PathBuf::from("/usr/bin/rustc")); //! //! ``` -extern crate libc; -extern crate thiserror; - mod checker; mod error; mod finder; @@ -28,11 +26,9 @@ use std::path; use std::ffi::OsStr; -use checker::CompositeChecker; -use checker::ExecutableChecker; -use checker::ExistedChecker; -pub use error::*; -use finder::Finder; +use crate::checker::{CompositeChecker, ExecutableChecker, ExistedChecker}; +pub use crate::error::*; +use crate::finder::Finder; /// Find a exectable binary's path by name. /// @@ -47,7 +43,7 @@ use finder::Finder; /// /// # Example /// -/// ``` norun +/// ```no_run /// use which::which; /// use std::path::PathBuf; /// @@ -56,9 +52,14 @@ use finder::Finder; /// /// ``` 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 all binaries with `binary_name` in the path list `paths`, 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().map_err(|_| Error::CannotGetCurrentDir)?; - which_in(binary_name, env::var_os("PATH"), &cwd) + which_in_all(binary_name, env::var_os("PATH"), cwd) } /// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths. @@ -68,13 +69,28 @@ where 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 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 = 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) + finder.find(binary_name, paths, cwd, binary_checker) } /// An owned, immutable wrapper around a `PathBuf` containing the path of an executable. @@ -100,6 +116,13 @@ impl 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. /// @@ -113,6 +136,23 @@ impl 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() @@ -192,10 +232,26 @@ impl CanonicalPath { .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` and `Path::canonicalize` and maps the result into a `CanonicalPath`. + /// 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>, @@ -207,6 +263,30 @@ impl CanonicalPath { .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() diff --git a/tests/basic.rs b/tests/basic.rs index 24a700d..7cb7a08 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -87,6 +87,13 @@ fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> which::Result<which::Can which::CanonicalPath::new_in(path, Some(f.paths.clone()), f.tempdir.path()) } +fn _which_all<T: AsRef<OsStr>>( + f: &TestFixture, + path: T, +) -> which::Result<impl Iterator<Item = which::Result<which::CanonicalPath>>> { + which::CanonicalPath::all_in(path, Some(f.paths.clone()), f.tempdir.path().to_path_buf()) +} + #[test] #[cfg(unix)] fn it_works() { @@ -148,6 +155,29 @@ fn test_which_second() { } #[test] +fn test_which_all() { + let f = TestFixture::new(); + let actual = _which_all(&f, BIN_NAME) + .unwrap() + .map(|c| c.unwrap()) + .collect::<Vec<_>>(); + let mut expected = f + .bins + .iter() + .map(|p| p.canonicalize().unwrap()) + .collect::<Vec<_>>(); + #[cfg(windows)] + { + expected.retain(|p| p.extension().map(|ext| ext == "exe" || ext == "cmd") == Some(true)); + } + #[cfg(not(windows))] + { + expected.retain(|p| p.file_name().unwrap() == BIN_NAME); + } + assert_eq!(actual, expected); +} + +#[test] #[cfg(unix)] fn test_which_absolute() { let f = TestFixture::new(); |