cargo-binstall/crates/detect-targets/src/detect.rs
Jiahao XU 62f9450d2d
Refactor: Extract new crate detect-targets and improve code quality (#307)
* Refactor: Extract new crate `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Refactor: Extract new mod `detect` for `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Refactor: Extract `desired_targets` in crate `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Refactor: Extract `detect::linux` in crate `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Refactor: Extract `detect::macos` in crate `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Refactor: Extract `detect::windows` in crate `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Add new dep cfg-if v1.0.0 for `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Refactor: Simplify mod declaration in `detect` using `cfg_if!`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Refactor: Simplify `detect_targets` using `cfg_if!`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Add crate doc for `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Enable feature "macros" of tokio in `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Enable feature "io-util" of dep tokio

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Rm unused feature "io-util" & "macros" of dep tokio

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Set stdin & stderr to null in `get_target_from_rustc`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Improve doc of `get_desired_targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Improve `detect_targets_linux`: Run `ldd` with stdin set to null

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fix potential panic in `windows::detect_alternative_targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* FIx fmt of `detect_targets_linux`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Do not re-export dep `detect-targets` in `crates/lib`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Fix typo in crate doc for `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Enable feature "macros" of tokio in dev mode

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Add example to crate doc of `detect-targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

* Improve API `get_desired_targets`: Take `Option<&str>`

instead of `&Option<String>`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
2022-08-21 22:21:33 +10:00

88 lines
2.4 KiB
Rust

use std::{
io::{BufRead, Cursor},
process::{Output, Stdio},
};
use cfg_if::cfg_if;
use tokio::process::Command;
cfg_if! {
if #[cfg(target_os = "linux")] {
mod linux;
} else if #[cfg(target_os = "macos")] {
mod macos;
} else if #[cfg(target_os = "windows")] {
mod windows;
}
}
/// Detect the targets supported at runtime,
/// which might be different from `TARGET` which is detected
/// at compile-time.
///
/// Return targets supported in the order of preference.
/// If target_os is linux and it support gnu, then it is preferred
/// to musl.
///
/// If target_os is mac and it is aarch64, then aarch64 is preferred
/// to x86_64.
///
/// Check [this issue](https://github.com/ryankurte/cargo-binstall/issues/155)
/// for more information.
pub async fn detect_targets() -> Vec<String> {
if let Some(target) = get_target_from_rustc().await {
let mut v = vec![target];
cfg_if! {
if #[cfg(target_os = "linux")] {
if v[0].contains("gnu") {
v.push(v[0].replace("gnu", "musl"));
}
} else if #[cfg(target_os = "macos")] {
if &*v[0] == macos::AARCH64 {
v.push(macos::X86.into());
}
} else if #[cfg(target_os = "windows")] {
v.extend(windows::detect_alternative_targets(&v[0]));
}
}
v
} else {
cfg_if! {
if #[cfg(target_os = "linux")] {
linux::detect_targets_linux().await
} else if #[cfg(target_os = "macos")] {
macos::detect_targets_macos()
} else if #[cfg(target_os = "windows")] {
windows::detect_targets_windows()
} else {
vec![TARGET.into()]
}
}
}
}
/// Figure out what the host target is using `rustc`.
/// If `rustc` is absent, then it would return `None`.
async fn get_target_from_rustc() -> Option<String> {
let Output { status, stdout, .. } = Command::new("rustc")
.arg("-vV")
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()
.ok()?
.wait_with_output()
.await
.ok()?;
if !status.success() {
return None;
}
Cursor::new(stdout)
.lines()
.filter_map(|line| line.ok())
.find_map(|line| line.strip_prefix("host: ").map(|host| host.to_owned()))
}