Skip to content
129 changes: 54 additions & 75 deletions src/install.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Installation and upgrade of both distribution-managed and local
//! toolchains
use std::path::{Path, PathBuf};
use std::path::Path;

use tracing::debug;

use crate::{
config::Cfg,
dist::{DistOptions, manifest::ManifestWithHash, prefix::InstallPrefix},
errors::RustupError,
toolchain::{CustomToolchainName, LocalToolchainName, Toolchain},
toolchain::{CustomToolchainName, Toolchain},
utils,
};

Expand All @@ -35,98 +35,77 @@ impl InstallMethod<'_, '_> {
self,
manifest: Option<ManifestWithHash>,
) -> anyhow::Result<UpdateStatus> {
let cfg = match self {
Self::Link { cfg, .. } | Self::Dist(DistOptions { cfg, .. }) => cfg,
};

// Initialize rayon for use by the remove_dir_all crate limiting the number of threads.
// This will error if rayon is already initialized but it's fine to ignore that.
let _ = rayon::ThreadPoolBuilder::new()
.num_threads(self.cfg().process.io_thread_count()?.into())
.num_threads(cfg.process.io_thread_count()?.into())
.build_global();
let local_name = self.local_name();
match &self {
InstallMethod::Link { .. }
| InstallMethod::Dist(DistOptions {
old_date_version: None,
..
}) => debug!("installing toolchain {local_name}",),
_ => debug!("updating existing install for '{local_name}'"),
}

debug!("toolchain directory: {}", self.dest_path().display());
let updated = self.run(&self.dest_path(), manifest).await?;

let status = match updated {
false => {
debug!("toolchain is already up to date");
UpdateStatus::Unchanged
let local_name = match &self {
Self::Link { dest, .. } => {
let name = (*dest).clone().into();
debug!("linking toolchain {name}");
name
}
true => {
debug!("toolchain {local_name} installed");
match &self {
InstallMethod::Dist(DistOptions {
old_date_version: Some((_, v)),
..
}) => UpdateStatus::Updated(v.clone()),
InstallMethod::Link { .. } | InstallMethod::Dist { .. } => {
UpdateStatus::Installed
}
Self::Dist(DistOptions {
toolchain: desc,
old_date_version,
..
}) => {
let name = (*desc).clone().into();
if old_date_version.is_some() {
debug!("updating existing install for '{name}'");
} else {
debug!("installing toolchain {name}");
}
name
}
};

// Final check, to ensure we're installed
match Toolchain::exists(self.cfg(), &local_name)? {
true => Ok(status),
false => Err(RustupError::ToolchainNotInstallable(local_name.to_string()).into()),
}
}

async fn run(&self, path: &Path, manifest: Option<ManifestWithHash>) -> anyhow::Result<bool> {
if path.exists() {
// Don't uninstall first for Dist method
match self {
InstallMethod::Dist { .. } => {}
_ => {
uninstall(path)?;
}
}
let dest_path = &cfg.toolchain_path(&local_name);
debug!("toolchain directory: {}", dest_path.display());
if dest_path.exists() && !matches!(self, Self::Dist { .. }) {
uninstall(dest_path)?;
}

match self {
InstallMethod::Link { src, .. } => {
utils::symlink_dir(src, path)?;
Ok(true)
let status = match &self {
Self::Link { src, .. } => {
utils::symlink_dir(src, dest_path)?;
UpdateStatus::Installed
}
InstallMethod::Dist(opts) => {
let prefix = &InstallPrefix::from(path.to_owned());
let maybe_new_hash = opts.install_into(prefix, manifest).await?;

if let Some(hash) = maybe_new_hash {
Self::Dist(opts) => match opts
.install_into(&InstallPrefix::from(dest_path.clone()), manifest)
.await?
{
None => UpdateStatus::Unchanged,
Some(hash) => {
utils::write_file("update hash", &opts.update_hash, &hash)?;
Ok(true)
} else {
Ok(false)
match opts {
DistOptions {
old_date_version: Some((_, v)),
..
} => UpdateStatus::Updated(v.clone()),
_ => UpdateStatus::Installed,
}
}
}
}
}
},
};

fn cfg(&self) -> &Cfg<'_> {
match self {
InstallMethod::Link { cfg, .. } => cfg,
InstallMethod::Dist(DistOptions { cfg, .. }) => cfg,
// Final check, to ensure we're installed
if !Toolchain::exists(cfg, &local_name)? {
return Err(RustupError::ToolchainNotInstallable(local_name.to_string()).into());
}
}

fn local_name(&self) -> LocalToolchainName {
match self {
InstallMethod::Link { dest, .. } => (*dest).clone().into(),
InstallMethod::Dist(DistOptions {
toolchain: desc, ..
}) => (*desc).clone().into(),
}
}
match &status {
UpdateStatus::Unchanged => debug!("toolchain is already up to date"),
_ => debug!("toolchain {local_name} installed"),
};

fn dest_path(&self) -> PathBuf {
self.cfg().toolchain_path(&self.local_name())
Ok(status)
}
}

Expand Down
Loading