diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md index 32fccfcfb1696..91c06402ca10a 100644 --- a/.github/ISSUE_TEMPLATE/library_tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md @@ -50,7 +50,7 @@ If the feature is changed later, please add those PRs here as well. --> - [ ] Implementation: #... -- [ ] Final comment period (FCP) +- [ ] Final comment period (FCP)[^1] - [ ] Stabilization PR - None yet. + +[^1]: https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 755c532ab3260..fa2a530d9db68 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -694,6 +694,7 @@ impl<'a> Builder<'a> { doc::RustcBook, doc::CargoBook, doc::Clippy, + doc::Miri, doc::EmbeddedBook, doc::EditionGuide, ), diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 2fc18c9e79e32..e73500dba5198 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -1128,11 +1128,7 @@ impl Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use); config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate); - config.download_rustc_commit = download_ci_rustc_commit( - &config.stage0_metadata, - rust.download_rustc, - config.verbose > 0, - ); + config.download_rustc_commit = download_ci_rustc_commit(&config, rust.download_rustc); } else { config.rust_profile_use = flags.rust_profile_use; config.rust_profile_generate = flags.rust_profile_generate; @@ -1304,6 +1300,15 @@ impl Config { config } + /// A git invocation which runs inside the source directory. + /// + /// Use this rather than `Command::new("git")` in order to support out-of-tree builds. + pub(crate) fn git(&self) -> Command { + let mut git = Command::new("git"); + git.current_dir(&self.src); + git + } + /// Try to find the relative path of `bindir`, otherwise return it in full. pub fn bindir_relative(&self) -> &Path { let bindir = &self.bindir; @@ -1453,9 +1458,8 @@ fn threads_from_config(v: u32) -> u32 { /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. fn download_ci_rustc_commit( - stage0_metadata: &Stage0Metadata, + config: &Config, download_rustc: Option, - verbose: bool, ) -> Option { // If `download-rustc` is not set, default to rebuilding. let if_unchanged = match download_rustc { @@ -1468,7 +1472,7 @@ fn download_ci_rustc_commit( }; // Handle running from a directory other than the top level - let top_level = output(Command::new("git").args(&["rev-parse", "--show-toplevel"])); + let top_level = output(config.git().args(&["rev-parse", "--show-toplevel"])); let top_level = top_level.trim_end(); let compiler = format!("{top_level}/compiler/"); let library = format!("{top_level}/library/"); @@ -1476,9 +1480,10 @@ fn download_ci_rustc_commit( // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - Command::new("git") + config + .git() .arg("rev-list") - .arg(format!("--author={}", stage0_metadata.config.git_merge_commit_email)) + .arg(format!("--author={}", config.stage0_metadata.config.git_merge_commit_email)) .args(&["-n1", "--first-parent", "HEAD"]), ); let commit = merge_base.trim_end(); @@ -1491,13 +1496,14 @@ fn download_ci_rustc_commit( } // Warn if there were changes to the compiler or standard library since the ancestor commit. - let has_changes = !t!(Command::new("git") + let has_changes = !t!(config + .git() .args(&["diff-index", "--quiet", &commit, "--", &compiler, &library]) .status()) .success(); if has_changes { if if_unchanged { - if verbose { + if config.verbose > 0 { println!( "warning: saw changes to compiler/ or library/ since {commit}; \ ignoring `download-rustc`" diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index be6655ddb61d0..3cf0f9b9f9927 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -643,7 +643,7 @@ impl Step for Rustc { } macro_rules! tool_doc { - ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?] $(,)?) => { + ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?], in_tree = $in_tree:expr $(,)?) => { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct $tool { target: TargetSelection, @@ -699,6 +699,12 @@ macro_rules! tool_doc { t!(fs::create_dir_all(&out_dir)); t!(symlink_dir_force(&builder.config, &out, &out_dir)); + let source_type = if $in_tree == true { + SourceType::InTree + } else { + SourceType::Submodule + }; + // Build cargo command. let mut cargo = prepare_tool_cargo( builder, @@ -707,7 +713,7 @@ macro_rules! tool_doc { target, "doc", $path, - SourceType::InTree, + source_type, &[], ); @@ -723,20 +729,38 @@ macro_rules! tool_doc { cargo.rustdocflag("--show-type-layout"); cargo.rustdocflag("--generate-link-to-definition"); cargo.rustdocflag("-Zunstable-options"); - builder.run(&mut cargo.into()); + if $in_tree == true { + builder.run(&mut cargo.into()); + } else { + // Allow out-of-tree docs to fail (since the tool might be in a broken state). + if !builder.try_run(&mut cargo.into()) { + builder.info(&format!( + "WARNING: tool {} failed to document; ignoring failure because it is an out-of-tree tool", + stringify!($tool).to_lowercase(), + )); + } + } } } } } -tool_doc!(Rustdoc, "rustdoc-tool", "src/tools/rustdoc", ["rustdoc", "rustdoc-json-types"]); +tool_doc!( + Rustdoc, + "rustdoc-tool", + "src/tools/rustdoc", + ["rustdoc", "rustdoc-json-types"], + in_tree = true +); tool_doc!( Rustfmt, "rustfmt-nightly", "src/tools/rustfmt", ["rustfmt-nightly", "rustfmt-config_proc_macro"], + in_tree = true ); -tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]); +tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"], in_tree = true); +tool_doc!(Miri, "miri", "src/tools/miri", ["miri"], in_tree = false); #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 60a53c28686b0..4923ddc225437 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -72,7 +72,9 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { Err(_) => false, }; if git_available { - let in_working_tree = match Command::new("git") + let in_working_tree = match build + .config + .git() .arg("rev-parse") .arg("--is-inside-work-tree") .stdout(Stdio::null()) @@ -84,10 +86,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { }; if in_working_tree { let untracked_paths_output = output( - Command::new("git") - .arg("status") - .arg("--porcelain") - .arg("--untracked-files=normal"), + build.config.git().arg("status").arg("--porcelain").arg("--untracked-files=normal"), ); let untracked_paths = untracked_paths_output .lines() diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 40ff0381c8bc1..845ee84a9a66d 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -644,7 +644,8 @@ impl Build { return; } let output = output( - Command::new("git") + self.config + .git() .args(&["config", "--file"]) .arg(&self.config.src.join(".gitmodules")) .args(&["--get-regexp", "path"]), @@ -1281,12 +1282,12 @@ impl Build { // That's our beta number! // (Note that we use a `..` range, not the `...` symmetric difference.) let count = output( - Command::new("git") + self.config + .git() .arg("rev-list") .arg("--count") .arg("--merges") - .arg("refs/remotes/origin/master..HEAD") - .current_dir(&self.src), + .arg("refs/remotes/origin/master..HEAD"), ); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 8395be40f9b52..7829dde719073 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -118,7 +118,7 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) { if !config.llvm_from_ci { return; } - let mut rev_list = Command::new("git"); + let mut rev_list = config.git(); rev_list.args(&[ PathBuf::from("rev-list"), format!("--author={}", builder.config.stage0_metadata.config.git_merge_commit_email).into(), diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 82f55440ce50c..e6f6460729af6 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -136,7 +136,7 @@ pub fn setup(config: &Config, profile: Profile) { println!(); - t!(install_git_hook_maybe(&config.src)); + t!(install_git_hook_maybe(&config)); println!(); @@ -302,7 +302,7 @@ pub fn interactive_path() -> io::Result { } // install a git hook to automatically run tidy --bless, if they want -fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> { +fn install_git_hook_maybe(config: &Config) -> io::Result<()> { let mut input = String::new(); println!( "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality. @@ -328,13 +328,12 @@ undesirable, simply delete the `pre-push` file from .git/hooks." }; if should_install { - let src = src_path.join("src").join("etc").join("pre-push.sh"); - let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map( - |output| { + let src = config.src.join("src").join("etc").join("pre-push.sh"); + let git = + t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| { assert!(output.status.success(), "failed to run `git`"); PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) - } - )); + })); let dst = git.join("hooks").join("pre-push"); match fs::hard_link(src, &dst) { Err(e) => eprintln!( diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 3ee6a42d987a0..328a0bf11c2af 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -1,5 +1,6 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::util::t; +use crate::Config; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::env; @@ -96,14 +97,9 @@ fn print_error(tool: &str, submodule: &str) { std::process::exit(3); } -fn check_changed_files(toolstates: &HashMap, ToolState>) { +fn check_changed_files(toolstates: &HashMap, ToolState>, config: &Config) { // Changed files - let output = std::process::Command::new("git") - .arg("diff") - .arg("--name-status") - .arg("HEAD") - .arg("HEAD^") - .output(); + let output = config.git().arg("diff").arg("--name-status").arg("HEAD").arg("HEAD^").output(); let output = match output { Ok(o) => o, Err(e) => { @@ -182,8 +178,8 @@ impl Step for ToolStateCheck { std::process::exit(1); } - check_changed_files(&toolstates); - checkout_toolstate_repo(); + check_changed_files(&toolstates, &builder.config); + checkout_toolstate_repo(&builder.config); let old_toolstate = read_old_toolstate(); for (tool, _) in STABLE_TOOLS.iter() { @@ -229,7 +225,7 @@ impl Step for ToolStateCheck { } if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() { - commit_toolstate_change(&toolstates); + commit_toolstate_change(&toolstates, &builder.config); } } @@ -302,16 +298,17 @@ fn toolstate_repo() -> String { const TOOLSTATE_DIR: &str = "rust-toolstate"; /// Checks out the toolstate repo into `TOOLSTATE_DIR`. -fn checkout_toolstate_repo() { +fn checkout_toolstate_repo(config: &Config) { if let Ok(token) = env::var("TOOLSTATE_REPO_ACCESS_TOKEN") { - prepare_toolstate_config(&token); + prepare_toolstate_config(&token, config); } if Path::new(TOOLSTATE_DIR).exists() { eprintln!("Cleaning old toolstate directory..."); t!(fs::remove_dir_all(TOOLSTATE_DIR)); } - let status = Command::new("git") + let status = config + .git() .arg("clone") .arg("--depth=1") .arg(toolstate_repo()) @@ -327,9 +324,9 @@ fn checkout_toolstate_repo() { } /// Sets up config and authentication for modifying the toolstate repo. -fn prepare_toolstate_config(token: &str) { - fn git_config(key: &str, value: &str) { - let status = Command::new("git").arg("config").arg("--global").arg(key).arg(value).status(); +fn prepare_toolstate_config(token: &str, config: &Config) { + let git_config = |key: &str, value: &str| { + let status = config.git().arg("config").arg("--global").arg(key).arg(value).status(); let success = match status { Ok(s) => s.success(), Err(_) => false, @@ -337,7 +334,7 @@ fn prepare_toolstate_config(token: &str) { if !success { panic!("git config key={} value={} failed (status: {:?})", key, value, status); } - } + }; // If changing anything here, then please check that `src/ci/publish_toolstate.sh` is up to date // as well. @@ -383,14 +380,14 @@ fn read_old_toolstate() -> Vec { /// /// * See /// if a private email by GitHub is wanted. -fn commit_toolstate_change(current_toolstate: &ToolstateData) { +fn commit_toolstate_change(current_toolstate: &ToolstateData, config: &Config) { let message = format!("({} CI update)", OS.expect("linux/windows only")); let mut success = false; for _ in 1..=5 { // Upload the test results (the new commit-to-toolstate mapping) to the toolstate repo. // This does *not* change the "current toolstate"; that only happens post-landing // via `src/ci/docker/publish_toolstate.sh`. - publish_test_results(¤t_toolstate); + publish_test_results(¤t_toolstate, config); // `git commit` failing means nothing to commit. let status = t!(Command::new("git") @@ -444,8 +441,8 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { /// These results will later be promoted to `latest.json` by the /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. -fn publish_test_results(current_toolstate: &ToolstateData) { - let commit = t!(std::process::Command::new("git").arg("rev-parse").arg("HEAD").output()); +fn publish_test_results(current_toolstate: &ToolstateData, config: &Config) { + let commit = t!(config.git().arg("rev-parse").arg("HEAD").output()); let commit = t!(String::from_utf8(commit.stdout)); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate));