Skip to content

fix!(config): re-enable active toolchain installation in Cfg::find_active_toolchain() with optional opt-out #4214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cli/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ pub(super) fn list_items(
Ok(utils::ExitCode(0))
}

pub(crate) fn list_toolchains(
pub(crate) async fn list_toolchains(
cfg: &Cfg<'_>,
verbose: bool,
quiet: bool,
Expand All @@ -418,7 +418,7 @@ pub(crate) fn list_toolchains(
let default_toolchain_name = cfg.get_default()?;
let active_toolchain_name: Option<ToolchainName> =
if let Ok(Some((LocalToolchainName::Named(toolchain), _reason))) =
cfg.find_active_toolchain()
cfg.find_active_toolchain(None).await
{
Some(toolchain)
} else {
Expand Down
5 changes: 4 additions & 1 deletion src/cli/proxy_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub async fn main(arg0: &str, current_dir: PathBuf, process: &Process) -> Result
.collect();

let cfg = set_globals(current_dir, true, process)?;
let cmd = cfg.resolve_local_toolchain(toolchain)?.command(arg0)?;
let cmd = cfg
.resolve_local_toolchain(toolchain)
.await?
.command(arg0)?;
run_command_for_dir(cmd, arg0, &cmd_args)
}
51 changes: 29 additions & 22 deletions src/cli/rustup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ pub async fn main(
write!(process.stdout().lock(), "{err}")?;
info!("This is the version for the rustup toolchain manager, not the rustc compiler.");
let mut cfg = common::set_globals(current_dir, true, process)?;
match cfg.active_rustc_version() {
match cfg.active_rustc_version().await {
Ok(Some(version)) => info!("The currently active `rustc` version is `{version}`"),
Ok(None) => info!("No `rustc` is currently active"),
Err(err) => trace!("Failed to display the current `rustc` version: {err}"),
Expand Down Expand Up @@ -601,10 +601,12 @@ pub async fn main(
match subcmd {
RustupSubcmd::DumpTestament => common::dump_testament(process),
RustupSubcmd::Install { opts } => update(cfg, opts, true).await,
RustupSubcmd::Uninstall { opts } => toolchain_remove(cfg, opts),
RustupSubcmd::Uninstall { opts } => toolchain_remove(cfg, opts).await,
RustupSubcmd::Show { verbose, subcmd } => handle_epipe(match subcmd {
None => show(cfg, verbose),
Some(ShowSubcmd::ActiveToolchain { verbose }) => show_active_toolchain(cfg, verbose),
None => show(cfg, verbose).await,
Some(ShowSubcmd::ActiveToolchain { verbose }) => {
show_active_toolchain(cfg, verbose).await
}
Some(ShowSubcmd::Home) => show_rustup_home(cfg),
Some(ShowSubcmd::Profile) => {
writeln!(process.stdout().lock(), "{}", cfg.get_profile()?)?;
Expand Down Expand Up @@ -633,12 +635,12 @@ pub async fn main(
RustupSubcmd::Toolchain { subcmd } => match subcmd {
ToolchainSubcmd::Install { opts } => update(cfg, opts, true).await,
ToolchainSubcmd::List { verbose, quiet } => {
handle_epipe(common::list_toolchains(cfg, verbose, quiet))
handle_epipe(common::list_toolchains(cfg, verbose, quiet).await)
}
ToolchainSubcmd::Link { toolchain, path } => {
toolchain_link(cfg, &toolchain, &path).await
}
ToolchainSubcmd::Uninstall { opts } => toolchain_remove(cfg, opts),
ToolchainSubcmd::Uninstall { opts } => toolchain_remove(cfg, opts).await,
},
RustupSubcmd::Check => check_updates(cfg).await,
RustupSubcmd::Default {
Expand Down Expand Up @@ -751,7 +753,7 @@ async fn default_(
}
};

if let Some((toolchain, reason)) = cfg.find_active_toolchain()? {
if let Some((toolchain, reason)) = cfg.find_active_toolchain(None).await? {
if !matches!(reason, ActiveReason::Default) {
info!("note that the toolchain '{toolchain}' is currently in use ({reason})");
}
Expand Down Expand Up @@ -928,7 +930,7 @@ async fn which(
binary: &str,
toolchain: Option<ResolvableToolchainName>,
) -> Result<utils::ExitCode> {
let binary_path = cfg.resolve_toolchain(toolchain)?.binary_file(binary);
let binary_path = cfg.resolve_toolchain(toolchain).await?.binary_file(binary);

utils::assert_is_file(&binary_path)?;

Expand All @@ -937,7 +939,7 @@ async fn which(
}

#[tracing::instrument(level = "trace", skip_all)]
fn show(cfg: &Cfg<'_>, verbose: bool) -> Result<utils::ExitCode> {
async fn show(cfg: &Cfg<'_>, verbose: bool) -> Result<utils::ExitCode> {
common::warn_if_host_is_emulated(cfg.process);

// Print host triple
Expand All @@ -962,7 +964,7 @@ fn show(cfg: &Cfg<'_>, verbose: bool) -> Result<utils::ExitCode> {
let installed_toolchains = cfg.list_toolchains()?;
let active_toolchain_and_reason: Option<(ToolchainName, ActiveReason)> =
if let Ok(Some((LocalToolchainName::Named(toolchain_name), reason))) =
cfg.find_active_toolchain()
cfg.find_active_toolchain(None).await
{
Some((toolchain_name, reason))
} else {
Expand Down Expand Up @@ -1081,8 +1083,8 @@ fn show(cfg: &Cfg<'_>, verbose: bool) -> Result<utils::ExitCode> {
}

#[tracing::instrument(level = "trace", skip_all)]
fn show_active_toolchain(cfg: &Cfg<'_>, verbose: bool) -> Result<utils::ExitCode> {
match cfg.find_active_toolchain()? {
async fn show_active_toolchain(cfg: &Cfg<'_>, verbose: bool) -> Result<utils::ExitCode> {
match cfg.find_active_toolchain(None).await? {
Some((toolchain_name, reason)) => {
let toolchain = Toolchain::with_reason(cfg, toolchain_name.clone(), &reason)?;
writeln!(
Expand Down Expand Up @@ -1118,7 +1120,7 @@ async fn target_list(
quiet: bool,
) -> Result<utils::ExitCode> {
// downcasting required because the toolchain files can name any toolchain
let distributable = DistributableToolchain::from_partial(toolchain, cfg)?;
let distributable = DistributableToolchain::from_partial(toolchain, cfg).await?;
common::list_items(
distributable,
|c| {
Expand All @@ -1145,7 +1147,7 @@ async fn target_add(
// isn't a feature yet.
// list_components *and* add_component would both be inappropriate for
// custom toolchains.
let distributable = DistributableToolchain::from_partial(toolchain, cfg)?;
let distributable = DistributableToolchain::from_partial(toolchain, cfg).await?;
let components = distributable.components()?;

if targets.contains(&"all".to_string()) {
Expand Down Expand Up @@ -1189,7 +1191,7 @@ async fn target_remove(
targets: Vec<String>,
toolchain: Option<PartialToolchainDesc>,
) -> Result<utils::ExitCode> {
let distributable = DistributableToolchain::from_partial(toolchain, cfg)?;
let distributable = DistributableToolchain::from_partial(toolchain, cfg).await?;

for target in targets {
let target = TargetTriple::new(target);
Expand Down Expand Up @@ -1227,7 +1229,7 @@ async fn component_list(
quiet: bool,
) -> Result<utils::ExitCode> {
// downcasting required because the toolchain files can name any toolchain
let distributable = DistributableToolchain::from_partial(toolchain, cfg)?;
let distributable = DistributableToolchain::from_partial(toolchain, cfg).await?;
common::list_items(
distributable,
|c| Some(&c.name),
Expand All @@ -1243,7 +1245,7 @@ async fn component_add(
toolchain: Option<PartialToolchainDesc>,
target: Option<String>,
) -> Result<utils::ExitCode> {
let distributable = DistributableToolchain::from_partial(toolchain, cfg)?;
let distributable = DistributableToolchain::from_partial(toolchain, cfg).await?;
let target = get_target(target, &distributable);

for component in &components {
Expand All @@ -1269,7 +1271,7 @@ async fn component_remove(
toolchain: Option<PartialToolchainDesc>,
target: Option<String>,
) -> Result<utils::ExitCode> {
let distributable = DistributableToolchain::from_partial(toolchain, cfg)?;
let distributable = DistributableToolchain::from_partial(toolchain, cfg).await?;
let target = get_target(target, &distributable);

for component in &components {
Expand Down Expand Up @@ -1311,9 +1313,14 @@ async fn toolchain_link(
Ok(utils::ExitCode(0))
}

fn toolchain_remove(cfg: &mut Cfg<'_>, opts: UninstallOpts) -> Result<utils::ExitCode> {
async fn toolchain_remove(cfg: &mut Cfg<'_>, opts: UninstallOpts) -> Result<utils::ExitCode> {
let default_toolchain = cfg.get_default().ok().flatten();
let active_toolchain = cfg.find_active_toolchain().ok().flatten().map(|(it, _)| it);
let active_toolchain = cfg
.find_active_toolchain(Some(false))
.await
.ok()
.flatten()
.map(|(it, _)| it);

for toolchain_name in &opts.toolchain {
let toolchain_name = toolchain_name.resolve(&cfg.get_default_host_triple()?)?;
Expand Down Expand Up @@ -1556,7 +1563,7 @@ async fn doc(
mut topic: Option<&str>,
doc_page: &DocPage,
) -> Result<utils::ExitCode> {
let toolchain = cfg.toolchain_from_partial(toolchain)?;
let toolchain = cfg.toolchain_from_partial(toolchain).await?;

if let Ok(distributable) = DistributableToolchain::try_from(&toolchain) {
if let [_] = distributable
Expand Down Expand Up @@ -1625,7 +1632,7 @@ async fn man(
command: &str,
toolchain: Option<PartialToolchainDesc>,
) -> Result<utils::ExitCode> {
let toolchain = cfg.toolchain_from_partial(toolchain)?;
let toolchain = cfg.toolchain_from_partial(toolchain).await?;
let path = toolchain.man_path();
utils::assert_is_directory(&path)?;

Expand Down
87 changes: 68 additions & 19 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ impl<'a> Cfg<'a> {
.transpose()?)
}

pub(crate) fn toolchain_from_partial(
pub(crate) async fn toolchain_from_partial(
&self,
toolchain: Option<PartialToolchainDesc>,
) -> anyhow::Result<Toolchain<'_>> {
Expand All @@ -511,20 +511,68 @@ impl<'a> Cfg<'a> {
)))
})
.transpose()?;
self.local_toolchain(toolchain)
self.local_toolchain(toolchain).await
}

pub(crate) fn find_active_toolchain(
pub(crate) async fn find_active_toolchain(
&self,
force_install_active: Option<bool>,
) -> Result<Option<(LocalToolchainName, ActiveReason)>> {
Ok(
if let Some((override_config, reason)) = self.find_override_config()? {
Some((override_config.into_local_toolchain_name(), reason))
} else {
self.get_default()?
.map(|x| (x.into(), ActiveReason::Default))
},
)
let (components, targets, profile, toolchain, reason) = match self.find_override_config()? {
Some((
OverrideCfg::Official {
components,
targets,
profile,
toolchain,
},
reason,
)) => (components, targets, profile, toolchain, reason),
Some((override_config, reason)) => {
return Ok(Some((override_config.into_local_toolchain_name(), reason)));
}
None => {
return Ok(self
.get_default()?
.map(|x| (x.into(), ActiveReason::Default)));
}
};

let should_install_active = force_install_active.unwrap_or_else(|| {
self.process
.var("RUSTUP_AUTO_INSTALL")
.map_or(true, |it| it != "0")
});

if !should_install_active {
return Ok(Some(((&toolchain).into(), reason)));
}

let components = components.iter().map(AsRef::as_ref).collect::<Vec<_>>();
let targets = targets.iter().map(AsRef::as_ref).collect::<Vec<_>>();
match DistributableToolchain::new(self, toolchain.clone()) {
Err(RustupError::ToolchainNotInstalled { .. }) => {
DistributableToolchain::install(
self,
&toolchain,
&components,
&targets,
profile.unwrap_or_default(),
false,
)
.await?;
}
Ok(mut distributable) => {
if !distributable.components_exist(&components, &targets)? {
distributable
.update(&components, &targets, profile.unwrap_or_default())
.await?;
}
}
Err(e) => return Err(e.into()),
};

Ok(Some(((&toolchain).into(), reason)))
}

fn find_override_config(&self) -> Result<Option<(OverrideCfg, ActiveReason)>> {
Expand Down Expand Up @@ -703,43 +751,44 @@ impl<'a> Cfg<'a> {
}

#[tracing::instrument(level = "trace")]
pub(crate) fn active_rustc_version(&mut self) -> Result<Option<String>> {
pub(crate) async fn active_rustc_version(&mut self) -> Result<Option<String>> {
if let Some(t) = self.process.args().find(|x| x.starts_with('+')) {
trace!("Fetching rustc version from toolchain `{}`", t);
self.set_toolchain_override(&ResolvableToolchainName::try_from(&t[1..])?);
}

let Some((name, _)) = self.find_active_toolchain()? else {
let Some((name, _)) = self.find_active_toolchain(None).await? else {
return Ok(None);
};
Ok(Some(Toolchain::new(self, name)?.rustc_version()))
}

pub(crate) fn resolve_toolchain(
pub(crate) async fn resolve_toolchain(
&self,
name: Option<ResolvableToolchainName>,
) -> Result<Toolchain<'_>> {
let toolchain = name
.map(|name| anyhow::Ok(name.resolve(&self.get_default_host_triple()?)?.into()))
.transpose()?;
self.local_toolchain(toolchain)
self.local_toolchain(toolchain).await
}

pub(crate) fn resolve_local_toolchain(
pub(crate) async fn resolve_local_toolchain(
&self,
name: Option<ResolvableLocalToolchainName>,
) -> Result<Toolchain<'_>> {
let local = name
.map(|name| name.resolve(&self.get_default_host_triple()?))
.transpose()?;
self.local_toolchain(local)
self.local_toolchain(local).await
}

fn local_toolchain(&self, name: Option<LocalToolchainName>) -> Result<Toolchain<'_>> {
async fn local_toolchain(&self, name: Option<LocalToolchainName>) -> Result<Toolchain<'_>> {
let toolchain = match name {
Some(tc) => tc,
None => {
self.find_active_toolchain()?
self.find_active_toolchain(None)
.await?
.ok_or_else(|| no_toolchain_error(self.process))?
.0
}
Expand Down
6 changes: 4 additions & 2 deletions src/toolchain/distributable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ pub(crate) struct DistributableToolchain<'a> {
}

impl<'a> DistributableToolchain<'a> {
pub(crate) fn from_partial(
pub(crate) async fn from_partial(
toolchain: Option<PartialToolchainDesc>,
cfg: &'a Cfg<'a>,
) -> anyhow::Result<Self> {
Ok(Self::try_from(&cfg.toolchain_from_partial(toolchain)?)?)
Ok(Self::try_from(
&cfg.toolchain_from_partial(toolchain).await?,
)?)
}

pub(crate) fn new(cfg: &'a Cfg<'a>, desc: ToolchainDesc) -> Result<Self, RustupError> {
Expand Down
Loading