1use std::path::PathBuf;
2
3use miette::{IntoDiagnostic, Result};
4
5pub async fn maybe_proxy() -> Result<()> {
8 let cwd = std::env::current_dir().into_diagnostic()?;
9
10 let config_path = match find_config(&cwd) {
11 Some(p) => p,
12 None => return Ok(()),
13 };
14
15 let config = nash_config::parse_file(&config_path).into_diagnostic()?;
16
17 let required = match config.compiler() {
18 Some(v) if v != crate::VERSION => v,
19 _ => return Ok(()),
20 };
21
22 let cache_dir = cached_binary_dir(required);
23 let binary = cached_binary_path(required);
24
25 if binary.exists() {
26 exec_cached_binary(&binary);
27 }
28
29 crate::download::download_version(required, &cache_dir).await?;
30 exec_cached_binary(&binary);
31}
32
33fn find_config(start: &std::path::Path) -> Option<PathBuf> {
35 let mut dir = start.to_path_buf();
36 loop {
37 let candidate = dir.join(nash_config::CONFIG_FILE_NAME);
38 if candidate.exists() {
39 return Some(candidate);
40 }
41 if !dir.pop() {
42 return None;
43 }
44 }
45}
46
47fn cached_binary_dir(version: &str) -> PathBuf {
48 let base = std::env::var("NASH_HOME")
49 .map(PathBuf::from)
50 .unwrap_or_else(|_| {
51 dirs::data_dir()
52 .unwrap_or_else(|| PathBuf::from("."))
53 .join("nash")
54 });
55 base.join("versions").join(version)
56}
57
58fn cached_binary_path(version: &str) -> PathBuf {
59 let dir = cached_binary_dir(version);
60 if cfg!(windows) {
61 dir.join("nash.exe")
62 } else {
63 dir.join("nash")
64 }
65}
66
67fn exec_cached_binary(binary: &std::path::Path) -> ! {
69 let args: Vec<String> = std::env::args().skip(1).collect();
70
71 #[cfg(unix)]
72 {
73 use std::os::unix::process::CommandExt;
74 let err = std::process::Command::new(binary).args(&args).exec();
75 eprintln!("Failed to exec cached nash binary: {err}");
76 std::process::exit(1);
77 }
78
79 #[cfg(not(unix))]
80 {
81 let status = std::process::Command::new(binary)
82 .args(&args)
83 .status()
84 .unwrap_or_else(|e| {
85 eprintln!("Failed to run cached nash binary: {e}");
86 std::process::exit(1);
87 });
88 std::process::exit(status.code().unwrap_or(1));
89 }
90}