use crate::{config::Config, package::Package, repo::Repo};
use anyhow::{anyhow, Context, Result};
use dialoguer::MultiSelect;
use log::{debug, error};
use std::{path::Path, process::Command};
pub fn install<P>(config_path: P, install_all: bool) -> Result<()>
where
P: AsRef<Path>,
{
let config = Config::from_path_or_new(&config_path)?;
let repo = Repo::new(config, true).context("opening repository")?;
let packages = repo.read().context("reading packages to install")?;
println!("Checking which packages haven't been installed yet..");
let packages_to_install: Vec<&Package> = packages
.iter()
.filter(|package| package.is_available())
.filter(|package| !package.is_installed().expect("Could not perform command"))
.collect::<_>();
let package_names = packages_to_install
.iter()
.map(|package| package.color_full_name())
.collect::<Vec<String>>();
let package_names = package_names
.iter()
.map(|name| name.as_str())
.collect::<Vec<&str>>();
if package_names.is_empty() {
println!("Nothing to install.");
} else {
let selections = if install_all {
(0..package_names.len()).collect()
} else {
MultiSelect::new()
.with_prompt("Select the packages you want to install (space to add)")
.items(&package_names[..])
.interact()
.context("failed constructing checkboxes")?
};
for selection in selections {
let package = packages_to_install[selection];
println!("Installing: {}.", package.color_full_name());
let install_command = package.install_command();
debug!("Installing: {}.", install_command);
match call(install_command.split_ascii_whitespace().collect()) {
Ok(_) => println!("{} installed successfully.", package.color_full_name()),
Err(err) => error!("\"{}\": {:?}", package.install_command(), err),
};
}
}
Ok(())
}
fn call(command: Vec<&str>) -> Result<()> {
let mut iter = command.iter();
let cmd_name = iter.next().unwrap();
let mut cmd = Command::new(cmd_name);
for arg in iter {
if !arg.is_empty() {
cmd.arg(arg);
}
}
let result = cmd.output()?;
if result.status.success() {
Ok(())
} else {
let stderr = String::from_utf8(result.stderr)?;
Err(anyhow!("{}", stderr))
}
}