Upgrade rust/crates/which to 4.1.0

Test: make
Change-Id: I7f3f322721f4e003735ea1147bec93355b0a4b32
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
diff --git a/Android.bp b/Android.bp
index 1c867fe..141bf34 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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 @@
     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"
diff --git a/Cargo.toml b/Cargo.toml
index 0ba7115..f6e0a43 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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 @@
 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 @@
 keywords = ["which", "which-rs", "unix", "command"]
 
 [dependencies]
+either = "1.6"
 libc = "0.2.65"
-thiserror = "1.0"
 
 [dev-dependencies]
 tempdir = "0.3.7"
diff --git a/METADATA b/METADATA
index 7dbbc46..27de0e1 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   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
   }
 }
diff --git a/README.md b/README.md
index eb2a562..f20f929 100644
--- a/README.md
+++ b/README.md
@@ -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 @@
         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 @@
     {
         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>
diff --git a/src/lib.rs b/src/lib.rs
index 8ea0e7e..4aea3e6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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::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 @@
 ///
 /// # Example
 ///
-/// ``` norun
+/// ```no_run
 /// use which::which;
 /// use std::path::PathBuf;
 ///
@@ -56,9 +52,14 @@
 ///
 /// ```
 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 @@
     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 @@
         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 @@
         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 @@
             .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 @@
             .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 @@
     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 @@
 }
 
 #[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();