Skip to main content

scud/commands/
install.rs

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    // Check if cargo is available
12    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    // Build the release binary
27    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    // Find and install the binary
46    let current_exe = env::current_exe()?;
47    let binary_name = if cfg!(windows) { "scud.exe" } else { "scud" };
48
49    // The binary should be in target/release/ relative to the repo root
50    let repo_root = current_exe
51        .parent() // scud-cli/target/release/
52        .and_then(|p| p.parent()) // scud-cli/target/
53        .and_then(|p| p.parent()) // scud-cli/
54        .and_then(|p| p.parent()) // repo root
55        .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    // Install to ~/.cargo/bin/ (standard Rust bin location)
74    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    // Remove existing binary if it exists
82    if dest_path.exists() {
83        fs::remove_file(&dest_path)?;
84    }
85
86    // Copy the binary
87    fs::copy(&source_path, &dest_path)?;
88
89    // Make executable on Unix
90    #[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    // Verify installation
105    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}