Skip to content

rustup default no longer exits with 1 with no default toolchain is set #4140

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

Closed
2 tasks done
weihanglo opened this issue Jan 3, 2025 · 20 comments · Fixed by #4141
Closed
2 tasks done

rustup default no longer exits with 1 with no default toolchain is set #4140

weihanglo opened this issue Jan 3, 2025 · 20 comments · Fixed by #4141
Labels
Milestone

Comments

@weihanglo
Copy link
Member

weihanglo commented Jan 3, 2025

Verification

Problem

(Edited by @rami3l to better reflect the original issue)

Coming from https://internals.rust-lang.org/t/seeking-beta-testers-for-rustup-v1-28-0/22060.

With rustup v1.27.1, the following shell snippet can be used to force the installation of the default toolchain, or fall back on stable when none is present:

rustup default || rustup default stable

When testing out the upcoming 1.28 release, however, I found that rustup default is returning 0 even there's no such thing as the default toolchain, resulting in an unchanged default toolchain state.

I've noticed the suggestion provided in the post:

rustup show active-toolchain || rustup toolchain install

... but it doesn't really help with the use case above, since regardless in 1.27.1, the current stable branch (1.28-beta), it seems to always exit with code 0.

  • 1.27.1

    rustup/src/cli/rustup_mode.rs

    Lines 1227 to 1257 in 54dd3d0

    fn show_active_toolchain(cfg: &Cfg, m: &ArgMatches) -> Result<utils::ExitCode> {
    let verbose = m.get_flag("verbose");
    let cwd = utils::current_dir()?;
    match cfg.find_or_install_override_toolchain_or_default(&cwd) {
    Err(e) => {
    let root_cause = e.root_cause();
    if let Some(RustupError::ToolchainNotSelected) =
    root_cause.downcast_ref::<RustupError>()
    {
    } else {
    return Err(e);
    }
    }
    Ok((toolchain, reason)) => {
    if let Some(reason) = reason {
    writeln!(
    process().stdout().lock(),
    "{} ({})",
    toolchain.name(),
    reason
    )?;
    } else {
    writeln!(process().stdout().lock(), "{} (default)", toolchain.name())?;
    }
    if verbose {
    writeln!(process().stdout().lock(), "{}", toolchain.rustc_version())?;
    }
    }
    }
    Ok(utils::ExitCode(0))
    }
  • stable

    rustup/src/cli/rustup_mode.rs

    Lines 1100 to 1105 in 7ccf717

    None => writeln!(
    cfg.process.stdout().lock(),
    "There isn't an active toolchain"
    )?,
    }
    Ok(utils::ExitCode(0))

Steps

  1. rustup default none
  2. rustup default || rustup default stable

Possible Solution(s)

Should we find another workaround?

Notes

No response

Rustup version

* rustup 1.27.1 (1980-01-01)
* rustup 1.28.0 (7ccf717e6e1aee46f65cc6fea4132a3f0e37593b)

Installed toolchains

rustup 1.27.1

installed toolchains
--------------------

error: no default toolchain configured

rustup 1.28.0

installed toolchains
--------------------

active toolchain
----------------
no active toolchain

OS version

Both Darwin and Linux

@weihanglo weihanglo added the bug label Jan 3, 2025
@weihanglo
Copy link
Member Author

I figured out it is because I didn't have any default. Maybe we don't want to handle the missing default case?

@weihanglo weihanglo changed the title rustup show active-toolchain exit 0 even when there is no active toolchain rustup show active-toolchain exits 0 when no default and no active toolchain Jan 3, 2025
@ChrisDenton
Copy link
Member

I suspect this case had just never been considered. When can you end up with no default? Is it only after uninstalling all toolchains?

@ChrisDenton
Copy link
Member

Edit: ah you already said, sorry. rustup default none. Hmm.

@weihanglo
Copy link
Member Author

When can you end up with no default? Is it only after uninstalling all toolchains?

For normal users,

  • During sh.rustup.rs installation, select none for the default toolchain.
  • rustup default none

I believe this is rare, but some environments might have no default.

@ChrisDenton
Copy link
Member

I think it may make sense to change it to an error if there is no active toolchain but then that won't help with migration. Unless we also backport the change.

@ChrisDenton
Copy link
Member

Hm, rustup show does return an exit code of 1 on 1.27.1 but not on 1.28.

@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

@weihanglo @ChrisDenton I believe this is a bug on our side. Will fix.

@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

The only thing here is that we need to make sure that our command return 1 where it should.

This includes at least rustup show active-toolchain and rustup default.

@weihanglo
Copy link
Member Author

Hm, rustup show does return an exit code of 1 on 1.27.1 but not on 1.28.

rustup default has changed its exit code as well when no default.

Should we have a small "compatibility notes" section for these changes in our changelog, just like how rust release does?

Anyway, thanks people for your help!
For my own usage, I can definitely find workarounds. I am good with any approach we take, or doing nothing :)

@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

@ChrisDenton A lot of these compat changes come from #3225. Apparently I was new to the team when reviewing this at the time and didn't understand the implications underneath... I'll try to do follow-up fixes for this.

@ChrisDenton
Copy link
Member

I can definitely sympathize with being new! Do we need to add this as a release blocker somewhere?

@rami3l rami3l mentioned this issue Jan 4, 2025
3 tasks
@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

I can definitely sympathize with being new! Do we need to add this as a release blocker somewhere?

@ChrisDenton Added to #3998 (comment).

@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

Hm, rustup show does return an exit code of 1 on 1.27.1 but not on 1.28.

@ChrisDenton I just checked, it looks like rustup show or rustup show active-toolchain won't give anything (nor a non-zero exit code) if there's no active toolchain, but rustup default will do.

Tested on Alpine Linux ARM64 with rustup v1.27.1:

> rustup default none
info: default toolchain unset
> rustup show
Default host: aarch64-unknown-linux-musl
rustup home:  /usr/local/rustup

no active toolchain
> echo $?
0
> rustup default
error: no default toolchain configured
> echo $?
1
> rustup show active-toolchain
> echo $?
0

... or I was misunderstanding your reply?

Anyway, I still consider the inconsistency between the latter two a bug, and rustup show active-toolchain should really return 1 when there's no such thing as the active toolchain.

It's just that rustup show active-toolchain was used to install the active toolchain as well (for example, rustup +beta show active-toolchain used to install beta if it's not installed), and this is where the new and the old implementations SHOULD differ in behavior.

@ChrisDenton
Copy link
Member

ChrisDenton commented Jan 4, 2025

Hm, in powershell on Windows 11:

> rustup default none
info: default toolchain unset
> rustup --version
rustup 1.27.1 (54dd3d00f 2024-04-24)
> rustup show; echo $LastExitCode
Default host: x86_64-pc-windows-msvc
rustup home:  F:\Programs\rust-lang\Rustup

installed toolchains
--------------------

error: no default toolchain configured
1

@rami3l rami3l changed the title rustup show active-toolchain exits 0 when no default and no active toolchain rustup default no longer exits with 1 with no default toolchain is set Jan 4, 2025
@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

@ChrisDenton That's a bit terrifying! Are there some pre-existing platform differences unrelated to #4141?

I'd say I expect rustup show NOT to return 1 in this case...

@ChrisDenton
Copy link
Member

I'm not aware of any but then I wasn't aware of this difference.

I'm not sure even why it's different, which worries me. Shouldn't our tests detect this?

@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

@ChrisDenton Just tested this on a borrowed Windows machine with rustup v1.28.0 beta:

> rustup show
Default host: x86_64-pc-windows-gnu
rustup home:  C:\Users\me\.rustup

installed toolchains
--------------------
stable-x86_64-pc-windows-gnu
stable-x86_64-pc-windows-msvc
nightly-x86_64-pc-windows-gnu
nightly-x86_64-pc-windows-msvc
nightly-2021-01-07-x86_64-pc-windows-msvc
nightly-2021-02-08-x86_64-pc-windows-msvc

active toolchain
----------------
no active toolchain

... so this error seems gone. I guess the only thing left to do is to make a regression test about this. We have had such a test since ~8 years ago:

#[test]
fn with_no_toolchain() {
setup(&|config| {
let out = run_input(config, &["rustup-init", "--default-toolchain=none"], "\n\n");
assert!(out.ok);
expect_stdout_ok(config, &["rustup", "show"], "no active toolchain");
});
}

@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

@ChrisDenton Looks like your particular rustup setup has failed when running this function, however this error is somehow not present on my machine (regardless of the platform):

rustup/src/config.rs

Lines 719 to 737 in 54dd3d0

/// Get the configured default toolchain.
/// If none is configured, returns None
/// If a bad toolchain name is configured, errors.
pub(crate) fn get_default(&self) -> Result<Option<ToolchainName>> {
let user_opt = self.settings_file.with(|s| Ok(s.default_toolchain.clone()));
let toolchain_maybe_str = if let Some(fallback_settings) = &self.fallback_settings {
match user_opt {
Err(_) | Ok(None) => Ok(fallback_settings.default_toolchain.clone()),
o => o,
}
} else {
user_opt
}?;
toolchain_maybe_str
.map(ResolvableToolchainName::try_from)
.transpose()?
.map(|t| t.resolve(&self.get_default_host_triple()?))
.transpose()
}

... and the fallback-specific logic is disabled on Windows, that's what is directly causing this situation:

rustup/src/config.rs

Lines 272 to 283 in ef631dc

// Centralised file for multi-user systems to provide admin/distributor set initial values.
#[cfg(unix)]
let fallback_settings = FallbackSettings::new(
// If present, use the RUSTUP_OVERRIDE_UNIX_FALLBACK_SETTINGS environment
// variable as settings path, or UNIX_FALLBACK_SETTINGS otherwise
match process.var("RUSTUP_OVERRIDE_UNIX_FALLBACK_SETTINGS") {
Ok(s) => PathBuf::from(s),
Err(_) => PathBuf::from(UNIX_FALLBACK_SETTINGS),
},
)?;
#[cfg(windows)]
let fallback_settings = None;

Do you happen to have a clue about this? What does your $RUSTUP_HOME/settings.toml show as the default toolchain?

@ChrisDenton
Copy link
Member

What does your $RUSTUP_HOME/settings.toml show as the default toolchain?

With rustup default none it doesn't have any default toolchain set:

profile = "default"
version = "12"

[overrides]

Weirdly I couldn't reproduce the issue when running in Windows sandbox but it does reproduce on two of my machines. Maybe it's something to do with my non-standard setup. 1.28 is fine though so I'm not sure if it's particularly worth investigating if it was just a bug in 1.27.1?

@rami3l
Copy link
Member

rami3l commented Jan 4, 2025

@ChrisDenton A non-existent field for the default toolchain is perfectly expected.

If rustup v1.28.0 beta doesn't have this issue for you then, well, I guess we should do nothing in that regard until the problem has resurfaced.

For now, let's just focus on #4141.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants