1#![forbid(unsafe_code)]
2
3use std::env;
4use std::path::PathBuf;
5
6pub fn resolve(binary: &str) -> Option<PathBuf> {
7 if let Some(override_bin) = override_binary(binary)
8 && override_bin.exists()
9 {
10 return Some(override_bin);
11 }
12 if let Some(path_bin) = resolve_from_path(binary) {
13 return Some(path_bin);
14 }
15 if let Some(current_exe) = std::env::current_exe().ok()
16 && let Some(exe_dir) = current_exe.parent()
17 {
18 let local_bin = exe_dir.join(binary);
19 if local_bin.exists() {
20 return Some(local_bin);
21 }
22 }
23 None
24}
25
26fn override_binary(binary: &str) -> Option<PathBuf> {
27 let keys: &[&str] = match binary {
28 "greentic-flow" => &["GREENTIC_FLOW_BIN", "GREENTIC_FLOW_DEV_BIN"],
29 "greentic-component" => &["GREENTIC_COMPONENT_BIN", "GREENTIC_COMPONENT_DEV_BIN"],
30 "greentic-i18n-translator" => &[
31 "GREENTIC_I18N_TRANSLATOR_BIN",
32 "GREENTIC_I18N_TRANSLATOR_DEV_BIN",
33 ],
34 _ => return None,
35 };
36 keys.iter()
37 .find_map(|key| env::var_os(key).map(PathBuf::from))
38}
39
40fn resolve_from_path(binary: &str) -> Option<PathBuf> {
41 let path_var = env::var_os("PATH")?;
42 for dir in env::split_paths(&path_var) {
43 let candidate = dir.join(binary);
44 if candidate.exists() {
45 return Some(candidate);
46 }
47 }
48 None
49}