use crossterm::style::Colorize;
use std::io;
use std::process;
use crate::irust::options::Options;
struct Dep {
name: &'static str,
cmd: &'static str,
function: &'static str,
install: &'static dyn Fn() -> io::Result<Vec<process::ExitStatus>>,
}
impl Dep {
fn new(
name: &'static str,
cmd: &'static str,
function: &'static str,
install: &'static dyn Fn() -> io::Result<Vec<process::ExitStatus>>,
) -> Self {
Dep {
name,
cmd,
function,
install,
}
}
}
pub fn check_required_deps() -> bool {
const REQUIRED_DEPS: &[&str] = &["cargo"];
for dep in REQUIRED_DEPS {
if !dep_installed(&dep) {
eprintln!(
"{0} is not insalled!\n{0} is required for IRust to work.",
dep
);
return false;
}
}
true
}
pub fn warn_about_opt_deps(options: &mut Options) {
let opt_deps: [Dep; 4] = [
Dep::new("racer", "racer", "auto_completion", &|| {
let mut exit_status = vec![];
let mut run_cmd = |cmd: &[&str]| -> io::Result<()> {
println!("{}", format!("Running: {:?}", cmd).magenta());
exit_status.push(process::Command::new(cmd[0]).args(&cmd[1..]).status()?);
Ok(())
};
if !dep_installed("rustup") {
println!(
"{}",
"rustup is not installed.\nrustup is required to install and configure racer"
.red()
);
return Err(io::Error::new(
io::ErrorKind::Other,
"rustup is not installed",
));
}
let cmd = ["rustup", "install", "nightly"];
run_cmd(&cmd)?;
let cmd = ["cargo", "+nightly", "install", "racer"];
run_cmd(&cmd)?;
let cmd = ["rustup", "component", "add", "rust-src"];
run_cmd(&cmd)?;
Ok(exit_status)
}),
Dep::new("rustfmt", "rustfmt", "beautifying repl code", &|| {
if !dep_installed("rustup") {
println!(
"{}",
"rustup is not installed.\nrustup is required to install rustfmt".red()
);
return Err(io::Error::new(
io::ErrorKind::Other,
"rustup is not installed",
));
}
let cmd = ["rustup", "component", "add", "rustfmt"];
println!("{}", format!("Running: {:?}", cmd).magenta());
Ok(vec![process::Command::new(cmd[0])
.args(&cmd[1..])
.status()?])
}),
Dep::new("cargo-edit", "cargo-add", "adding depedencies", &|| {
let cmd = ["cargo", "install", "cargo-edit"];
println!("{}", format!("Running: {:?}", cmd).magenta());
Ok(vec![process::Command::new(cmd[0])
.args(&cmd[1..])
.status()?])
}),
Dep::new(
"cargo-asm",
"cargo-asm",
"viewing functions assembly",
&|| {
let cmd = ["cargo", "install", "cargo-asm"];
println!("{}", format!("Running: {:?}", cmd).magenta());
Ok(vec![process::Command::new(cmd[0])
.args(&cmd[1..])
.status()?])
},
),
];
if !options.first_irust_run {
return;
}
println!(
"{}",
"Hi and Welcome to IRust!\n\
This is a one time message\n\
IRust will check now for optional dependencies and offer to install them\n\
"
.dark_blue()
);
let mut installed_something = false;
for dep in &opt_deps {
if !dep_installed(dep.cmd) {
println!();
println!(
"{}",
format!(
"{} is not installed, it's required for {}\n\
Do you want IRust to install it? [Y/n]: ",
dep.name, dep.function
)
.yellow()
);
let answer = {
let mut a = String::new();
std::io::stdin()
.read_line(&mut a)
.expect("failed to read stdin");
a.trim().to_string()
};
if answer.is_empty() || answer == "y" || answer == "Y" {
match (dep.install)() {
Ok(status) if status.iter().all(process::ExitStatus::success) => {
println!(
"{}",
format!("{} sucessfully installed!\n", dep.name).green()
);
installed_something = true;
}
_ => println!("{}", format!("error while installing {}", dep.name).red()),
};
}
}
}
options.first_irust_run = false;
if installed_something {
println!(
"{}",
"You might need to reload the shell inorder to update $PATH".yellow()
);
}
println!("{}", "Everthing is set!".green());
}
fn dep_installed(d: &str) -> bool {
if let Err(e) = std::process::Command::new(d)
.arg("-h")
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn()
{
if e.kind() == std::io::ErrorKind::NotFound {
return false;
}
}
true
}