From f99e5991f8930242a1722dffd11c366116c28d53 Mon Sep 17 00:00:00 2001 From: aggarwalakshun Date: Sun, 2 Mar 2025 05:53:27 +0530 Subject: [PATCH] main program --- src/main.rs | 548 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 548 insertions(+) create mode 100644 src/main.rs diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5fdcd08 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,548 @@ +use std::{fs, env, vec, error::Error, process::Command, path::Path, collections::HashMap, io::{self, Write}}; +use serde::Deserialize; +use rust_embed::RustEmbed; +use tempfile::NamedTempFile; + +#[derive(Deserialize)] +struct Flatpak { + map: HashMap, +} + +#[derive(RustEmbed)] +#[folder = "data/"] +struct Asset; + +fn main() -> io::Result<()> { + + clear_terminal(); + + let binding = detect_distro(); + let distro: &str = binding.as_str(); + + let file_content = match distro { + "arch" => Asset::get("prompts/arch.txt").ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "File not found"))?, + "Debian" => Asset::get("prompts/debian.txt").ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "File not found"))?, + "fedora" => Asset::get("prompts/fedora.txt").ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "File not found"))?, + _ => return Err(io::Error::new(io::ErrorKind::NotFound, "Unsupported distro")), + }; + + let buffer = std::str::from_utf8(&file_content.data) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + + let first_choice: Vec = buffer.lines().map(|line| line.to_string()).collect(); + + for(index, element) in first_choice.iter().enumerate() { + eprint!("{}. {}\n", index+1, element) + } + eprint!("\nEnter 0 to exit\n"); + + let _ = match distro { + "arch" => arch_choices(), + "Debian" => debian_choices(), + "fedora" => fedora_choices(), + _ => return Err(io::Error::new(io::ErrorKind::NotFound, "Unsupported distro")), + }; + + Ok(()) +} + +fn arch_choices() -> io::Result<()> { + + let input: i32 = handle_int_input(); + + let _ = match input { + 1 => install_programs(), + 2 => install_flatpaks(), + 3 => update_system(), + 4 => aur(), + 5 => drivers(), + _ => return Err(io::Error::new(io::ErrorKind::NotFound, "Invalid input")), + }; + + Ok(()) +} + +fn debian_choices() -> io::Result<()> { + + let input: i32 = handle_int_input(); + + let _ = match input { + 1 => install_programs(), + 2 => install_flatpaks(), + 3 => update_system(), + 4 => third_party(), + 5 => drivers(), + _ => return Err(io::Error::new(io::ErrorKind::NotFound, "Invalid input")), + }; + + Ok(()) +} + +fn fedora_choices() -> io::Result<()> { + + let input: i32 = handle_int_input(); + + let _ = match input { + 1 => install_programs(), + 2 => install_flatpaks(), + 3 => update_system(), + 4 => third_party(), + 5 => Ok(rpm()), + 6 => drivers(), + _ => return Err(io::Error::new(io::ErrorKind::NotFound, "Invalid input")), + }; + + Ok(()) +} + +fn install_programs() -> Result<(), Box> { + + clear_terminal(); + + let file = Asset::get("prompts/programs.txt").ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "File not found"))?; + let buffer = std::str::from_utf8(&file.data) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let choice: Vec = buffer.lines().map(|line| line.to_string()).collect(); + + for(index, element) in choice.iter().enumerate() { + eprint!("{}. {}\n", index+1, element) + } + eprint!("\nEnter 0 to go back\n"); + + let input = handle_vec_input(); + let mut chosen: Vec = vec![]; + for &n in input.iter() { + if input.contains(&0) { + let _ = main(); + } else { + chosen.push(choice[(n-1) as usize].clone()); + } + } + + if which("apt").is_some() { + Command::new("sudo").arg("apt").arg("update"); + } + + for n in chosen.iter() { + if which("yay").is_some() { + Command::new("yay").arg("-S").arg(n).status()?; + } else if which("pacman").is_some() { + Command::new("sudo").arg("pacman").arg("-S").arg(n).status()?; + } else if which("dnf").is_some() { + Command::new("sudo").arg("dnf").arg("install").arg(n).status()?; + } else if which("apt").is_some() { + Command::new("sudo").arg("apt").arg("install").arg(n).status()?; + } + }; + + let _ = main(); + + Ok(()) +} + +fn flatpak_file() -> Result, Box> { + + let file_content = Asset::get("prompts/flatpaks.json") + .ok_or("Embedded file not found")?; + + let contents = std::str::from_utf8(file_content.data.as_ref())?; + + let data: Flatpak = serde_json::from_str(contents)?; + + Ok(data.map) +} + +fn install_flatpaks() -> Result<(), Box> { + + clear_terminal(); + + let binding = detect_distro(); + let distro = binding.as_str(); + + if which("flatpak").is_none() { + eprint!("\nInstall Flatpak first? Y/N (1/0)\n"); + let input = handle_int_input(); + if input == 0 { + let _ = main(); + } else { + match distro { + "arch" => { + Command::new("sudo").arg("pacman").arg("-S").arg("flatpak").status()?; + } + "Debian" => { + Command::new("sudo").arg("apt").arg("update").status()?; + Command::new("sudo").arg("apt").arg("install").arg("flatpak").status()?; + } + "fedora" => { + Command::new("sudo").arg("dnf").arg("install").arg("flatpak").status()?; + } + _ => eprint!("Unsupported distro") + }; + } + } + + match flatpak_file() { + Ok(hashmap) => { + for (i, (_key, value)) in hashmap.iter().enumerate() { + eprint!("{}. {}\n",i+1, value); + } + eprint!("\nEnter 0 to go back\n"); + let input = handle_vec_input(); + for &n in input.iter() { + if input.contains(&0) { + let _ = main(); + } else if let Some((key, _)) = hashmap.iter().nth((n-1) as usize) { + let status = Command::new("flatpak").arg("install").arg("-y").arg(key).status(); + match status { + Ok(s) if s.success() => eprint!("Successfully installed {}", key), + Ok(_) => eprintln!("Failed to install Flatpak: {}", key), + Err(e) => eprintln!("Error executing command: {}", e), + } + } else { + eprint!("Invalid selection"); + } + } + } + Err(e) => { + eprint!("Error reading file: {}", e); + } + } + let _ = main(); + Ok(()) + +} + +fn update_system() -> Result<(), Box> { + + clear_terminal(); + + let binding = detect_distro(); + let distro = binding.as_str(); + + match distro { + "arch" => { + if which("yay").is_some() { + Command::new("yay").status()?; + } else { + Command::new("sudo").arg("pacman").arg("-Syu").status()?; + } + } + "Debian" => { + Command::new("sudo").arg("apt").arg("update").status()?; + Command::new("sudo").arg("apt").arg("upgrade").status()?; + } + "fedora" => { + Command::new("sudo").arg("dnf").arg("up").status()?; + } + _ => eprint!("Unsupported distro") + }; + + let _ = main(); + Ok(()) +} + +fn aur() -> Result<(), Box> { + + clear_terminal(); + + let file = Asset::get("prompts/aur.txt").ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "File not found"))?; + let buffer = std::str::from_utf8(&file.data) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let choice: Vec = buffer.lines().map(|line| line.to_string()).collect(); + + if which("yay").is_none() { + eprint!("AUR helper not found. Install yay Y/N? (1/0)"); + let input = handle_int_input(); + if input == 1 { + Command::new("sudo").arg("pacman").arg("-S").arg("git").arg("base-devel").status()?; + Command::new("git").arg("clone").arg("https://aur.archlinux.org/yay.git").status()?; + std::env::set_current_dir("yay")?; + Command::new("makepkg").arg("-si").status()?; + } else { + let _ = main(); + } + } + + for (index, element) in choice.iter().enumerate() { + eprint!("{}. {}\n", index+1, element) + } + eprint!("\nEnter 0 to go back\n"); + + let input = handle_vec_input(); + let mut chosen: Vec = vec![]; + for &n in input.iter() { + if input.contains(&0) { + let _ = main(); + } else { + chosen.push(choice[(n-1) as usize].clone()); + } + } + for i in chosen.iter() { + Command::new("yay").arg("-S").arg(i).status()?; + } + + let _ = main(); + + Ok(()) +} + +fn third_party() -> Result<(), Box> { + + clear_terminal(); + + let file = Asset::get("prompts/third-party.txt") + .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "File not found"))?; + + let buffer = std::str::from_utf8(&file.data) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + + let choices: Vec = buffer.lines().map(|line| line.to_string()).collect(); + + for (index, element) in choices.iter().enumerate() { + eprintln!("{}. {}", index + 1, element); + } + eprintln!("\nEnter 0 to go back"); + + let mut chosen: Vec = vec![]; + let input = handle_vec_input(); + for &n in input.iter() { + if input.contains(&0) { + let _ = main(); + } else { + chosen.push(choices[(n-1) as usize].clone()); + } + } + + for j in chosen.iter() { + let script_name = format!("scripts/{}.sh", j); + if let Some(script) = Asset::get(&script_name) { + let mut temp_file = NamedTempFile::new()?; + temp_file.write_all(&script.data)?; + let temp_file_path = temp_file.path(); + let status = Command::new("bash") + .arg(temp_file_path) + .status()?; + if !status.success() { + eprintln!("Script failed: {}", script_name); + } + } else { + eprintln!("Script not found: {}", script_name); + } + } + let _ = main(); + Ok(()) +} + +fn drivers() -> Result<(), Box> { + + clear_terminal(); + + let distro = detect_distro(); + let choices = vec!["Intel", "AMD", "Nvidia"]; + + for (index, element) in choices.iter().enumerate() { + eprintln!("{}. {}", index + 1, element); + } + eprintln!("\nEnter 0 to go back"); + + let input: i32 = handle_int_input(); + if input == 0 { + let _ = main(); + } + + match input { + 1 => handle_intel_driver(&distro)?, + 2 => handle_amd_driver(&distro)?, + 3 => handle_nvidia_driver(&distro)?, + _ => eprintln!("Invalid choice"), + } + + Ok(()) +} + +fn handle_intel_driver(distro: &str) -> Result<(), Box> { + + clear_terminal(); + + match distro { + "arch" => { + let intel_models = vec!["intel-media-driver", "libva-intel-driver"]; + + for (index, element) in intel_models.iter().enumerate() { + eprintln!("{}. {}", index + 1, element); + } + eprintln!("\nEnter 0 to go back"); + + let input_2 = handle_int_input(); + if input_2 == 0 { + return drivers(); + } + match input_2 { + 1 => Command::new("sudo").arg("pacman").arg("-S").arg("intel-media-driver").status()?, + 2 => Command::new("sudo").arg("pacman").arg("-S").arg("libva-intel-driver").status()?, + _ => { + eprintln!("Invalid choice"); + return Ok(()); + }, + } + }, + "Debian" => { + Command::new("sudo").arg("apt").arg("update").status()?; + Command::new("sudo").arg("apt").arg("install").arg("intel-media-va-driver").status() + }?, + "fedora" => { + Command::new("sudo").arg("dnf").arg("install").arg("intel-media-driver").status()? + }, + _ => { + eprintln!("Invalid choice"); + return Ok(()); + }, + }; + + let _ = drivers(); + Ok(()) +} + +fn handle_amd_driver(distro: &str) -> Result<(), Box> { + + clear_terminal(); + + match distro { + "arch" => Command::new("sudo").arg("pacman").arg("-S").arg("mesa").status()?, + "Debian" => { + Command::new("sudo").arg("apt").arg("update").status()?; + Command::new("sudo").arg("apt").arg("install").arg("mesa-va-drivers").status() + }?, + "fedora" => Command::new("sudo").arg("dnf").arg("install").arg("mesa-va-drivers").status()?, + _ => { + eprintln!("Unsupported distro"); + return Ok(()) + }, + }; + + let _ = drivers(); + Ok(()) +} + +fn handle_nvidia_driver(distro: &str) -> Result<(), Box> { + + clear_terminal(); + + match distro { + "arch" => Command::new("sudo").arg("pacman").arg("-S").arg("nvidia").status()?, + "Debian" => { + Command::new("sudo").arg("apt").arg("update").status()?; + Command::new("sudo").arg("apt").arg("install").arg("nvidia-driver").status() + }?, + "fedora" => Command::new("sudo").arg("dnf").arg("install").arg("akmod-nvidia").status()?, + _ => { + eprintln!("Unsupported distro"); + return Ok(()) + }, + }; + + let _ = drivers(); + Ok(()) +} + +fn rpm() { + + clear_terminal(); + + let version = Command::new("rpm") + .arg("-E") + .arg("%fedora") + .output() + .expect("Failed to lookup fedora version"); + + if version.status.success() { + let stdout = String::from_utf8_lossy(&version.stdout); + let version_str = stdout.trim(); + println!("Fedora version: {}", version_str); + + let url1 = format!("https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-{}.noarch.rpm", version_str); + let url2 = format!("https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-{}.noarch.rpm", version_str); + + let status1 = Command::new("sudo").arg("dnf").arg("install").arg("-y").arg(&url1).status(); + let status2 = Command::new("sudo").arg("dnf").arg("install").arg("-y").arg(&url2).status(); + + if status1.is_ok() && status1.unwrap().success() { + println!("Successfully installed RPM Fusion free repository."); + } else { + eprintln!("Failed to install RPM Fusion free repository."); + } + + if status2.is_ok() && status2.unwrap().success() { + println!("Successfully installed RPM Fusion nonfree repository."); + } else { + eprintln!("Failed to install RPM Fusion nonfree repository."); + } + } else { + let stderr = String::from_utf8_lossy(&version.stderr); + eprintln!("Failed to get Fedora version with status: {}", version.status); + eprintln!("Error output:\n{}", stderr); + } + + let _ = main(); +} + +fn handle_vec_input() -> Vec { + let mut input = String::new(); + io::stdin() + .read_line(&mut input) + .expect("Error in reading."); + + input + .trim() + .split_whitespace() + .filter_map(|x| x.parse().ok()) + .collect() +} + +fn handle_int_input() -> i32 { + loop { + let mut input = String::new(); + io::stdin() + .read_line(&mut input) + .expect("Failed to read input"); + + match input.trim().parse::() { + Ok(num) => return num, + Err(_) => println!("Please enter a valid integer."), + } + } +} + +fn detect_distro() -> String { + let detected_distro = fs::read_to_string("/etc/os-release") + .expect("Could not find os-release file on system"); + + if detected_distro.contains("arch") { + "arch".to_string() + } else if detected_distro.contains("Debian") || detected_distro.contains("ubuntu") { + "Debian".to_string() + } else if detected_distro.contains("fedora") { + "fedora".to_string() + } else { + eprintln!("Distro Not Supported"); + "unsupported".to_string() + } +} + +fn which(program: &str) -> Option { + if let Ok(paths) = env::var("PATH") { + for path in paths.split(':') { + let full_path = Path::new(path).join(program); + if full_path.exists() && full_path.is_file() { + return Some(full_path.to_string_lossy().to_string()); + } + } + } + None +} + +fn clear_terminal() { + Command::new("clear") + .status() + .expect("Failed to clear the terminal"); +}