1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#![deny(clippy::all)]
#![warn(missing_docs)]

//! # ichwh - an async implementation of `which`
//!
//! `ichwh` aims to be a fully-async clone of [GNU `which`][gnu], compatible with the three major
//! operating systems. Then main job of `which` is to search for executables on the current `PATH`.
//!
//! Specialized Error and Result types are provided (through [thiserror]), and are returned by this
//! crate's functions.
//!
//! ## Usage
//!
//! ```
//! use {ichwh::which, async_std::path::Path};
//!
//! async {
//!     let path_to_python = which("python").await.unwrap();
//!     assert_eq!(path_to_python.unwrap(), Path::new("/usr/bin/python"));
//! };
//! ```
//!
//! ## Paths
//!
//! When given a path, `ichwh` will look for an executable file at that path. For example, if there
//! is an executable file named `foo` in your current directory, `ichwh` will return the absolute
//! path to `foo` from `ichwh::which("./foo")` and `ichwh::which("/path/to/current/dir/foo")`.
//!
//! ## Note about Windows
//!
//! It's really simple to determine if a regular file or symlink is executable on Linux - you check
//! that it has the executable permission, regardless of its extension.
//!
//! On windows, it's a bit more complicated. In order to be executed, a file must have an
//! executable extension in its name, such as `.exe` or `.cmd`. The executable file formats are
//! listed in the `%PATHEXT%` environment variable. When searching for an executable in a
//! directory, `ichwh` will 'match' files in the order that their extension appears in `%PATHEXT%`.
//!
//! When invoking a command on windows, the extension is not required. If the given file doesn't
//! have an extension and does not exist in the directory being searched, `ichwh` will append each
//! extension in `%PATHEXT%` to the file's name until it finds a match in the directory. Therefore,
//! `ichwh::which("cargo")` is correct and returns the same path as `ichwh::which("cargo.exe")`.
//!
//! [gnu]: https://carlowood.github.io/which/
//! [thiserror]: https://crates.io/crates/thiserror

mod error;
mod which;

cfg_if::cfg_if! {
    if #[cfg(unix)] {
        mod unix;
        use unix as util;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as util;
    }
}

pub use crate::error::*;
pub use crate::util::is_executable;
pub use crate::which::*;

#[cfg(test)]
mod test;