Skip to content
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

feat: allow version pinning & arbitrary downgrades via RUSTUP_VERSION #4259

Merged
merged 6 commits into from
Mar 19, 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
3 changes: 3 additions & 0 deletions doc/user-guide/src/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
- `RUSTUP_UPDATE_ROOT` (default `https://static.rust-lang.org/rustup`). Sets
the root URL for downloading self-update.

- `RUSTUP_VERSION` (default: none). Overrides the rustup version (e.g. `1.27.1`)
to be downloaded when executing `rustup-init.sh` or `rustup self update`.

- `RUSTUP_IO_THREADS` *unstable* (defaults to reported cpu count). Sets the
number of threads to perform close IO in. Set to `1` to force
single-threaded IO for troubleshooting, or an arbitrary number to override
Expand Down
10 changes: 9 additions & 1 deletion rustup-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,15 @@ main() {
;;
esac

local _url="${RUSTUP_UPDATE_ROOT}/dist/${_arch}/rustup-init${_ext}"
local _url
if [ "${RUSTUP_VERSION+set}" = 'set' ]; then
say "\`RUSTUP_VERSION\` has been set to \`${RUSTUP_VERSION}\`"
_url="${RUSTUP_UPDATE_ROOT}/archive/${RUSTUP_VERSION}"
else
_url="${RUSTUP_UPDATE_ROOT}/dist"
fi
_url="${_url}/${_arch}/rustup-init${_ext}"


local _dir
if ! _dir="$(ensure mktemp -d)"; then
Expand Down
9 changes: 7 additions & 2 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use crate::{
errors::*,
markdown::md,
},
config::Cfg,
config::{Cfg, non_empty_env_var},
dist::{self, PartialToolchainDesc, Profile, TargetTriple, ToolchainDesc},
errors::RustupError,
install::UpdateStatus,
Expand Down Expand Up @@ -1104,7 +1104,12 @@ pub(crate) async fn prepare_update(process: &Process) -> Result<Option<PathBuf>>

// Get available version
info!("checking for self-update");
let available_version = get_available_rustup_version(process).await?;
let available_version = if let Some(ver) = non_empty_env_var("RUSTUP_VERSION", process)? {
info!("`RUSTUP_VERSION` has been set to `{ver}`");
ver
} else {
get_available_rustup_version(process).await?
};

// If up-to-date
if available_version == current_version {
Expand Down
29 changes: 16 additions & 13 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1027,22 +1027,25 @@ impl<'a> Cfg<'a> {
}
}

/// The root path of the release server, without the `/dist` suffix.
/// By default, it points to [`dist::DEFAULT_DIST_SERVER`].
pub(crate) fn dist_root_server(process: &Process) -> Result<String> {
Ok(match non_empty_env_var("RUSTUP_DIST_SERVER", process)? {
Some(s) => {
Ok(
if let Some(s) = non_empty_env_var("RUSTUP_DIST_SERVER", process)? {
trace!("`RUSTUP_DIST_SERVER` has been set to `{s}`");
s
}
None => {
// For backward compatibility
non_empty_env_var("RUSTUP_DIST_ROOT", process)?
.inspect(|url| trace!("`RUSTUP_DIST_ROOT` has been set to `{url}`"))
.as_ref()
.map(|root| root.trim_end_matches("/dist"))
.unwrap_or(dist::DEFAULT_DIST_SERVER)
.to_owned()
}
})
// For backwards compatibility
else if let Some(mut root) = non_empty_env_var("RUSTUP_DIST_ROOT", process)? {
trace!("`RUSTUP_DIST_ROOT` has been set to `{root}`");
if let Some(stripped) = root.strip_suffix("/dist") {
root.truncate(stripped.len());
}
root
} else {
dist::DEFAULT_DIST_SERVER.to_owned()
},
)
}

impl Debug for Cfg<'_> {
Expand Down Expand Up @@ -1088,7 +1091,7 @@ fn get_default_host_triple(s: &Settings, process: &Process) -> TargetTriple {
.unwrap_or_else(|| TargetTriple::from_host_or_build(process))
}

fn non_empty_env_var(name: &str, process: &Process) -> anyhow::Result<Option<String>> {
pub(crate) fn non_empty_env_var(name: &str, process: &Process) -> anyhow::Result<Option<String>> {
match process.var(name) {
Ok(s) if !s.is_empty() => Ok(Some(s)),
Ok(_) => Ok(None),
Expand Down
14 changes: 13 additions & 1 deletion src/test/clitools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,19 @@ impl Config {

/// Expect an exact strings on stdout/stderr with an ok status code
pub async fn expect_ok_ex(&mut self, args: &[&str], stdout: &str, stderr: &str) {
let out = self.run(args[0], &args[1..], &[]).await;
self.expect_ok_ex_env(args, &[], stdout, stderr).await;
}

/// Expect an exact strings on stdout/stderr with an ok status code,
/// with extra environment variables
pub async fn expect_ok_ex_env(
&mut self,
args: &[&str],
env: &[(&str, &str)],
stdout: &str,
stderr: &str,
) {
let out = self.run(args[0], &args[1..], env).await;
if !out.ok || out.stdout != stdout || out.stderr != stderr {
print_command(args, &out);
println!("expected.ok: true");
Expand Down
24 changes: 24 additions & 0 deletions tests/suite/cli_self_upd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,30 @@ info: downloading self-update
.await;
}

#[tokio::test]
async fn update_precise() {
let version = env!("CARGO_PKG_VERSION");
let expected_output = format!(
"info: checking for self-update
info: `RUSTUP_VERSION` has been set to `{TEST_VERSION}`
info: downloading self-update
"
);

let mut cx = SelfUpdateTestContext::new(TEST_VERSION).await;
cx.config
.expect_ok(&["rustup-init", "-y", "--no-modify-path"])
.await;
cx.config
.expect_ok_ex_env(
&["rustup", "self", "update"],
&[("RUSTUP_VERSION", TEST_VERSION)],
&format!(" rustup updated - {version} (from {version})\n\n",),
&expected_output,
)
.await;
}

#[cfg(windows)]
#[tokio::test]
async fn update_overwrites_programs_display_version() {
Expand Down