use crate::cmd::{Binary, Command, Runnable};
use crate::toolchain::MAIN_TOOLCHAIN_NAME;
use crate::tools::{RUSTUP, Tool};
use crate::workspace::Workspace;
use anyhow::Context as _;
use std::env::consts::EXE_SUFFIX;
use std::fs::{self, File};
use std::io;
use tempfile::tempdir;
static RUSTUP_BASE_URL: &str = "https://static.rust-lang.org/rustup/dist";
pub(crate) struct Rustup;
impl Runnable for Rustup {
fn name(&self) -> Binary {
Binary::ManagedByRustwide("rustup".into())
}
}
impl Tool for Rustup {
fn name(&self) -> &'static str {
"rustup"
}
fn is_installed(&self, workspace: &Workspace) -> anyhow::Result<bool> {
let path = self.binary_path(workspace);
if !path.is_file() {
return Ok(false);
}
crate::native::is_executable(path)
}
fn install(&self, workspace: &Workspace, _fast_install: bool) -> anyhow::Result<()> {
fs::create_dir_all(workspace.cargo_home())?;
fs::create_dir_all(workspace.rustup_home())?;
let url = format!(
"{}/{}/rustup-init{}",
RUSTUP_BASE_URL,
crate::HOST_TARGET,
EXE_SUFFIX
);
let mut resp = workspace
.http_client()
.get(url)
.send()?
.error_for_status()?;
let tempdir = tempdir()?;
let installer = &tempdir.path().join(format!("rustup-init{EXE_SUFFIX}"));
{
let mut file = File::create(installer)?;
io::copy(&mut resp, &mut file)?;
crate::native::make_executable(installer)?;
}
Command::new(workspace, installer.to_string_lossy().as_ref())
.args(&[
"-y",
"--no-modify-path",
"--default-toolchain",
MAIN_TOOLCHAIN_NAME,
"--profile",
workspace.rustup_profile(),
])
.env("RUSTUP_HOME", workspace.rustup_home())
.env("CARGO_HOME", workspace.cargo_home())
.run()
.context("unable to install rustup")?;
Ok(())
}
fn update(&self, workspace: &Workspace, _fast_install: bool) -> anyhow::Result<()> {
Command::new(workspace, &RUSTUP)
.args(&["self", "update"])
.run()
.context("failed to update rustup")?;
Command::new(workspace, &RUSTUP)
.args(&["update", MAIN_TOOLCHAIN_NAME])
.run()
.with_context(|| format!("failed to update main toolchain {MAIN_TOOLCHAIN_NAME}"))?;
Ok(())
}
}