Skip to content

Commit

Permalink
xtask: Fix channel of cargo operations
Browse files Browse the repository at this point in the history
Starting in rustup 1.25.0, the environment is modified during `cargo`
invocations in a way that breaks setting the channel arg
(e.g. "+nightly") in a subprocess.

Fix by unsetting those variables in the child cargo's env.

See rust-lang/rustup#3031
  • Loading branch information
nicholasbishop committed Jul 12, 2022
1 parent 35051a3 commit c171a4e
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 3 deletions.
41 changes: 41 additions & 0 deletions xtask/src/cargo.rs
@@ -1,5 +1,7 @@
use crate::arch::UefiArch;
use anyhow::{bail, Result};
use std::env;
use std::ffi::OsString;
use std::process::Command;

#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -86,6 +88,32 @@ pub enum CargoAction {
Test,
}

/// Get a modified PATH to remove entries added by rustup. This is
/// necessary on Windows, see
/// https://github.com/rust-lang/rustup/issues/3031.
fn sanitized_path(orig_path: OsString) -> OsString {
// Modify the PATH to remove entries added by rustup. This is
// necessary on Windows, see https://github.com/rust-lang/rustup/issues/3031.
let paths = env::split_paths(&orig_path);
let sanitized_paths = paths.filter(|path| {
!path
.components()
.any(|component| component.as_os_str() == ".rustup")
});

env::join_paths(sanitized_paths).expect("invalid PATH")
}

/// Cargo automatically sets some env vars that can prevent the
/// channel arg (e.g. "+nightly") from working. Unset them in the
/// child's environment.
pub fn fix_nested_cargo_env(cmd: &mut Command) {
cmd.env_remove("RUSTC");
cmd.env_remove("RUSTDOC");
let orig_path = env::var_os("PATH").unwrap_or_default();
cmd.env("PATH", sanitized_path(orig_path));
}

#[derive(Debug)]
pub struct Cargo {
pub action: CargoAction,
Expand All @@ -101,6 +129,8 @@ impl Cargo {
pub fn command(&self) -> Result<Command> {
let mut cmd = Command::new("cargo");

fix_nested_cargo_env(&mut cmd);

if let Some(toolchain) = &self.toolchain {
cmd.arg(&format!("+{}", toolchain));
}
Expand Down Expand Up @@ -193,6 +223,17 @@ mod tests {
);
}

#[test]
fn test_sanitize_path() {
let (input, expected) = match env::consts::FAMILY {
"unix" => ("Abc:/path/.rustup/cargo:Xyz", "Abc:Xyz"),
"windows" => ("Abc;/path/.rustup/cargo;Xyz", "Abc;Xyz"),
_ => unimplemented!(),
};

assert_eq!(sanitized_path(input.into()), expected);
}

#[test]
fn test_cargo_command() {
let cargo = Cargo {
Expand Down
3 changes: 2 additions & 1 deletion xtask/src/main.rs
Expand Up @@ -7,7 +7,7 @@ mod qemu;
mod util;

use anyhow::Result;
use cargo::{Cargo, CargoAction, Feature, Package};
use cargo::{fix_nested_cargo_env, Cargo, CargoAction, Feature, Package};
use cfg_if::cfg_if;
use clap::Parser;
use opt::{Action, BuildOpt, ClippyOpt, DocOpt, MiriOpt, Opt, QemuOpt};
Expand Down Expand Up @@ -172,6 +172,7 @@ fn test_latest_release() -> Result<()> {
// Create cargo build command, not using the `cargo` module to make
// it explicit that it matches the command in `BUILDING.md`.
let mut build_cmd = Command::new("cargo");
fix_nested_cargo_env(&mut build_cmd);
build_cmd
.args(&["+nightly", "build", "--target", "x86_64-unknown-uefi"])
.current_dir(tmp_dir.join("template"));
Expand Down
13 changes: 11 additions & 2 deletions xtask/src/util.rs
Expand Up @@ -6,8 +6,12 @@ use std::process::Command;
/// Example: "VAR=val program --arg1 arg2".
pub fn command_to_string(cmd: &Command) -> String {
// Format env vars as "name=val".
let ignore_var = ["PATH", "RUSTC", "RUSTDOC"];
let mut parts = cmd
.get_envs()
// Filter out some internally-set variables that would just
// clutter the output.
.filter(|(name, _)| !ignore_var.contains(&name.to_str().unwrap_or_default()))
.map(|(name, val)| {
format!(
"{}={}",
Expand Down Expand Up @@ -47,8 +51,13 @@ mod tests {
#[test]
fn test_command_to_string() {
let mut cmd = Command::new("MyCommand");
cmd.args(&["abc", "123"])
.envs([("VAR1", "val1"), ("VAR2", "val2")]);
cmd.args(&["abc", "123"]).envs([
("VAR1", "val1"),
("VAR2", "val2"),
("PATH", "pathval"),
("RUSTC", "rustcval"),
("RUSTDOC", "rustdocval"),
]);
assert_eq!(
command_to_string(&cmd),
"VAR1=val1 VAR2=val2 MyCommand abc 123"
Expand Down

0 comments on commit c171a4e

Please sign in to comment.