1use anyhow::Result;
2use colored::Colorize;
3use std::env;
4use std::fs;
5use std::path::Path;
6use std::process::Command;
7
8pub fn run() -> Result<()> {
9 println!("{}", "Installing SCUD...".blue().bold());
10
11 println!("Checking for Rust toolchain...");
13 let cargo_check = Command::new("cargo").arg("--version").output();
14 match cargo_check {
15 Ok(output) if output.status.success() => {
16 let version = String::from_utf8_lossy(&output.stdout);
17 println!(" {} {}", "✓".green(), version.trim());
18 }
19 _ => {
20 println!(" {} Rust toolchain not found", "✗".red());
21 println!(" Please install Rust from https://rustup.rs/");
22 anyhow::bail!("Rust toolchain required");
23 }
24 }
25
26 println!("Building SCUD binary...");
28 let current_dir = env::current_dir()?;
29 let build_dir = current_dir.parent().unwrap_or_else(|| Path::new("."));
30 let build_result = Command::new("cargo")
31 .args(["build", "--release"])
32 .current_dir(build_dir)
33 .status();
34
35 match build_result {
36 Ok(status) if status.success() => {
37 println!(" {} Binary built successfully", "✓".green());
38 }
39 _ => {
40 println!(" {} Failed to build binary", "✗".red());
41 anyhow::bail!("Build failed");
42 }
43 }
44
45 let current_exe = env::current_exe()?;
47 let binary_name = if cfg!(windows) { "scud.exe" } else { "scud" };
48
49 let repo_root = current_exe
51 .parent() .and_then(|p| p.parent()) .and_then(|p| p.parent()) .and_then(|p| p.parent()) .unwrap_or_else(|| Path::new("."))
56 .to_path_buf();
57
58 let source_path = repo_root
59 .join("scud-cli")
60 .join("target")
61 .join("release")
62 .join(binary_name);
63
64 if !source_path.exists() {
65 println!(
66 " {} Binary not found at: {}",
67 "✗".red(),
68 source_path.display()
69 );
70 anyhow::bail!("Binary not found after build");
71 }
72
73 let home_dir =
75 dirs::home_dir().ok_or_else(|| anyhow::anyhow!("Could not find home directory"))?;
76 let cargo_bin_dir = home_dir.join(".cargo").join("bin");
77 fs::create_dir_all(&cargo_bin_dir)?;
78
79 let dest_path = cargo_bin_dir.join(binary_name);
80
81 if dest_path.exists() {
83 fs::remove_file(&dest_path)?;
84 }
85
86 fs::copy(&source_path, &dest_path)?;
88
89 #[cfg(unix)]
91 {
92 use std::os::unix::fs::PermissionsExt;
93 let mut perms = fs::metadata(&dest_path)?.permissions();
94 perms.set_mode(0o755);
95 fs::set_permissions(&dest_path, perms)?;
96 }
97
98 println!(
99 " {} Binary installed to: {}",
100 "✓".green(),
101 dest_path.display()
102 );
103
104 let verify_result = Command::new(&dest_path).arg("--version").output();
106 match verify_result {
107 Ok(output) if output.status.success() => {
108 let version = String::from_utf8_lossy(&output.stdout);
109 println!(
110 " {} Installation verified: {}",
111 "✓".green(),
112 version.trim()
113 );
114 }
115 _ => {
116 println!(" {} Installation verification failed", "✗".red());
117 }
118 }
119
120 println!();
121 println!("{}", "✅ SCUD installed successfully!".green().bold());
122 println!();
123 println!("Next steps:");
124 println!(" 1. Run: scud init");
125 println!(" 2. Set required environment variables");
126 println!(" 3. Start using SCUD!");
127
128 Ok(())
129}