40 lines
1.3 KiB
Rust
40 lines
1.3 KiB
Rust
//! Resolve tool names through PATH, with the same .wasm fallback as the host.
|
|
use std::path::Path;
|
|
fn main() {
|
|
let mut args = std::env::args().skip(1).peekable();
|
|
let all = args.peek().is_some_and(|arg| arg == "-a");
|
|
if all {
|
|
args.next();
|
|
}
|
|
let names: Vec<_> = args.collect();
|
|
if names.is_empty() || names.iter().any(|name| name.starts_with('-')) {
|
|
eprintln!("usage: which [-a] <name>...");
|
|
std::process::exit(2);
|
|
}
|
|
let path = std::env::var("PATH").unwrap_or_else(|_| "/usr/local/bin:/bin".into());
|
|
let mut missing = false;
|
|
for name in names {
|
|
let paths: Vec<_> = if name.contains('/') {
|
|
vec![name.clone()]
|
|
} else {
|
|
path.split(':')
|
|
.map(|dir| Path::new(dir).join(&name).to_string_lossy().into_owned())
|
|
.collect()
|
|
};
|
|
let mut found = false;
|
|
'search: for path in paths {
|
|
for candidate in [path.clone(), format!("{path}.wasm")] {
|
|
if std::fs::metadata(&candidate).is_ok_and(|metadata| metadata.is_file()) {
|
|
println!("{candidate}");
|
|
found = true;
|
|
if !all {
|
|
break 'search;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
missing |= !found;
|
|
}
|
|
std::process::exit(i32::from(missing));
|
|
}
|