use crate::package;
use crate::util;
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::process::{Command, Stdio};
use log::{info, warn};
use crate::package::*;
use crate::Result;
pub fn setup_mode(load_opts: PackageLoadOpts) -> Result<()> {
let source_install =
util::user_input_boolean("do you want to build packages from source?", false)?;
if source_install {
ensure_rust()?;
}
install_modules(load_opts, source_install)
}
fn ensure_rust() -> Result<()> {
match which::which("cargo") {
Ok(cargo_dir) => {
info!("cargo found at {:?}", cargo_dir);
Ok(())
}
Err(_) => {
warn!("cargo not found");
if !cfg!(windows)
&& util::user_input_boolean(
"do you want memflowup to install rust via rustup?",
true,
)?
{
info!("cargo not found, installing via rustup");
install_rust()
} else {
Err("rust/cargo not found. please install it manually.".into())
}
}
}
}
fn install_rust() -> Result<()> {
match which::which("rustup") {
Ok(rustup_path) => {
info!("rustup found at {:?}", rustup_path);
install_rust_toolchain(rustup_path)
}
Err(_) if !cfg!(unix) => {
warn!("rustup is not installed, trying to download");
install_rustup().and_then(|_| {
install_rust_toolchain(
which::which("rustup").expect("No rustup found after installing rustup!"),
)
})
}
_ => {
warn!("rustup is not installed, setup manually!");
Err("Please install rustup".into())
}
}
}
fn install_rust_toolchain<P: AsRef<OsStr>>(path: P) -> Result<()> {
Command::new(path)
.arg("toolchain")
.arg("install")
.arg("stable")
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.map_err(|_| "failed to install stable toolchain via rustup")?;
Ok(())
}
fn install_rustup() -> Result<()> {
let mut rustup_path = env::temp_dir();
rustup_path.push("rustup.sh");
let rustup_script = util::http_download_file("https://sh.rustup.rs")?;
fs::write(rustup_path.clone(), rustup_script)?;
Command::new("chmod")
.arg("+x")
.arg(rustup_path.clone())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
Command::new("sh")
.arg("-c")
.arg(rustup_path)
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
Ok(())
}
fn install_modules(load_opts: PackageLoadOpts, from_source: bool) -> Result<()> {
println!("Running in interactive mode. You can always re-run memflowup to install additional packages, or to different paths.");
let system_wide = util::user_input_boolean(
"do you want to install the initial packages system-wide?",
true,
)?;
if !load_opts.ignore_upstream {
update_index(system_wide)?;
}
let packages = load_packages(system_wide, load_opts)?;
let branch = util::user_input(
"which channel do you want to use?",
&["stable", "development"],
1,
)
.map(|r| r != 0)
.map(<_>::into)?;
package::list(system_wide, branch, from_source, load_opts)?;
println!();
println!("Type packages to install by number, name, or type * for all:");
let mut output = String::new();
std::io::stdin().read_line(&mut output).unwrap();
let trimmed = output.trim();
let install_all = trimmed == "*";
let (indices, names): (Vec<_>, Vec<_>) = trimmed
.split_whitespace()
.flat_map(|s| s.split(','))
.flat_map(|s| s.split(';'))
.partition(|s| s.chars().all(|c| c.is_numeric()));
let indices = indices
.into_iter()
.map(str::parse::<usize>)
.map(std::result::Result::unwrap)
.collect::<Vec<_>>();
for (_, p) in packages
.into_iter()
.filter(|p| p.supports_install_mode(branch, from_source))
.filter(Package::supported_by_platform)
.enumerate()
.filter(|(i, p)| install_all || indices.contains(i) || names.contains(&p.name.as_str()))
{
println!("Installing {}", p.name);
p.install(branch, &PackageOpts::base_opts(system_wide, from_source))?;
}
println!();
println!("Initial setup done!");
Ok(())
}