1use std::process::{Command, Stdio};
13
14const INSTALL_SCRIPT_URL: &str =
16 "https://raw.githubusercontent.com/zenitheditor/zenith/main/scripts/install.sh";
17
18pub fn run(pre: bool, version: Option<&str>) -> Result<(), String> {
24 let mut sh_args: Vec<String> = vec!["-s".to_string(), "--".to_string()];
25 if pre {
26 sh_args.push("--pre".to_string());
27 }
28 if let Some(v) = version {
29 let tag = if v.starts_with('v') {
30 v.to_string()
31 } else {
32 format!("v{v}")
33 };
34 sh_args.push("--version".to_string());
35 sh_args.push(tag);
36 }
37
38 let (dl_cmd, dl_args): (&str, &[&str]) = if which("curl") {
39 ("curl", &["-fsSL", INSTALL_SCRIPT_URL])
40 } else if which("wget") {
41 ("wget", &["-qO-", INSTALL_SCRIPT_URL])
42 } else {
43 return Err("curl or wget is required for self-update".to_string());
44 };
45
46 let mut downloader = Command::new(dl_cmd)
47 .args(dl_args)
48 .stdout(Stdio::piped())
49 .spawn()
50 .map_err(|e| format!("failed to start {dl_cmd}: {e}"))?;
51
52 let pipe = downloader
53 .stdout
54 .take()
55 .ok_or_else(|| "failed to capture the download stream".to_string())?;
56
57 let status = Command::new("sh")
58 .args(&sh_args)
59 .stdin(pipe)
60 .status()
61 .map_err(|e| format!("failed to run the install script: {e}"))?;
62
63 let _ = downloader.wait();
65
66 if status.success() {
67 Ok(())
68 } else {
69 Err("the install script failed".to_string())
70 }
71}
72
73fn which(cmd: &str) -> bool {
75 Command::new("sh")
76 .arg("-c")
77 .arg(format!("command -v {cmd}"))
78 .stdout(Stdio::null())
79 .stderr(Stdio::null())
80 .status()
81 .map(|s| s.success())
82 .unwrap_or(false)
83}