Skip to content

Add config builder for bootstrap tests #142629

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
52 changes: 35 additions & 17 deletions src/bootstrap/src/core/builder/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::Flags;
use crate::core::build_steps::doc::DocumentationFormat;
use crate::core::config::Config;
use crate::utils::cache::ExecutedStep;
use crate::utils::helpers::get_host_target;
use crate::utils::tests::git::{GitCtx, git_test};

static TEST_TRIPLE_1: &str = "i686-unknown-haiku";
Expand Down Expand Up @@ -1236,29 +1237,47 @@ fn any_debug() {
/// The staging tests use insta for snapshot testing.
/// See bootstrap's README on how to bless the snapshots.
mod staging {
use crate::Build;
use crate::core::builder::Builder;
use crate::core::builder::tests::{
TEST_TRIPLE_1, configure, configure_with_args, render_steps, run_build,
};
use crate::utils::tests::ConfigBuilder;

#[test]
fn build_compiler_stage_1() {
let mut cache = run_build(
&["compiler".into()],
configure_with_args(&["build", "--stage", "1"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]),
);
let steps = cache.into_executed_steps();
insta::assert_snapshot!(render_steps(&steps), @r"
[build] rustc 0 <target1> -> std 0 <target1>
[build] llvm <target1>
[build] rustc 0 <target1> -> rustc 1 <target1>
[build] rustc 0 <target1> -> rustc 1 <target1>
insta::assert_snapshot!(
ConfigBuilder::build()
.path("compiler")
.stage(1)
.get_steps(), @r"
[build] rustc 0 <host> -> std 0 <host>
[build] llvm <host>
[build] rustc 0 <host> -> rustc 1 <host>
[build] rustc 0 <host> -> rustc 1 <host>
");
}

impl ConfigBuilder {
fn get_steps(self) -> String {
let config = self.create_config();

let kind = config.cmd.kind();
let build = Build::new(config);
let builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(kind), &builder.paths);
render_steps(&builder.cache.into_executed_steps())
}
}
}

/// Renders the executed bootstrap steps for usage in snapshot tests with insta.
/// Only renders certain important steps.
/// Each value in `steps` should be a tuple of (Step, step output).
///
/// The arrow in the rendered output (`X -> Y`) means `X builds Y`.
/// This is similar to the output printed by bootstrap to stdout, but here it is
/// generated purely for the purpose of tests.
fn render_steps(steps: &[ExecutedStep]) -> String {
steps
.iter()
Expand All @@ -1275,18 +1294,17 @@ fn render_steps(steps: &[ExecutedStep]) -> String {
}
let stage =
if let Some(stage) = metadata.stage { format!("{stage} ") } else { "".to_string() };
write!(record, "{} {stage}<{}>", metadata.name, metadata.target);
write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target));
Some(record)
})
.map(|line| {
line.replace(TEST_TRIPLE_1, "target1")
.replace(TEST_TRIPLE_2, "target2")
.replace(TEST_TRIPLE_3, "target3")
})
.collect::<Vec<_>>()
.join("\n")
}

fn normalize_target(target: TargetSelection) -> String {
target.to_string().replace(&get_host_target().to_string(), "host")
}

fn render_compiler(compiler: Compiler) -> String {
format!("rustc {} <{}>", compiler.stage, compiler.host)
format!("rustc {} <{}>", compiler.stage, normalize_target(compiler.host))
}
4 changes: 2 additions & 2 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use crate::core::download::is_download_ci_available;
use crate::utils::channel;
use crate::utils::exec::command;
use crate::utils::execution_context::ExecutionContext;
use crate::utils::helpers::exe;
use crate::utils::helpers::{exe, get_host_target};
use crate::{GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, t};

/// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic.
Expand Down Expand Up @@ -349,7 +349,7 @@ impl Config {
stderr_is_tty: std::io::stderr().is_terminal(),

// set by build.rs
host_target: TargetSelection::from_user(env!("BUILD_TRIPLE")),
host_target: get_host_target(),

src: {
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
Expand Down
5 changes: 5 additions & 0 deletions src/bootstrap/src/utils/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<
}
}

/// Return the host target on which we are currently running.
pub fn get_host_target() -> TargetSelection {
TargetSelection::from_user(env!("BUILD_TRIPLE"))
}

/// Rename a file if from and to are in the same filesystem or
/// copy and remove the file otherwise
pub fn move_file<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
Expand Down
43 changes: 43 additions & 0 deletions src/bootstrap/src/utils/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
//! This module contains shared utilities for bootstrap tests.

use crate::core::builder::Builder;
use crate::core::config::DryRun;
use crate::{Build, Config, Flags};

pub mod git;

/// Used to configure an invocation of bootstrap.
/// Currently runs in the rustc checkout, long-term it should be switched
/// to run in a (cache-primed) temporary directory instead.
pub struct ConfigBuilder {
args: Vec<String>,
}

impl ConfigBuilder {
pub fn from_args(args: &[&str]) -> Self {
Self::new(args)
}

pub fn build() -> Self {
Self::new(&["build"])
}

pub fn path(mut self, path: &str) -> Self {
self.args.push(path.to_string());
self
}

pub fn stage(mut self, stage: u32) -> Self {
self.args.push("--stage".to_string());
self.args.push(stage.to_string());
self
}

fn new(args: &[&str]) -> Self {
Self { args: args.iter().copied().map(String::from).collect() }
}

pub fn create_config(mut self) -> Config {
let mut config = Config::parse(Flags::parse(&self.args));
// Run in dry-check, otherwise the test would be too slow
config.set_dry_run(DryRun::SelfCheck);
config
}
}
Loading