diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bootstrap/builder.rs | 8 | ||||
| -rw-r--r-- | src/bootstrap/run.rs | 22 | ||||
| -rw-r--r-- | src/bootstrap/test.rs | 37 | ||||
| -rw-r--r-- | src/bootstrap/tool.rs | 1 | ||||
| -rw-r--r-- | src/tools/replace-version-placeholder/Cargo.toml | 10 | ||||
| -rw-r--r-- | src/tools/replace-version-placeholder/src/main.rs | 30 | ||||
| -rw-r--r-- | src/tools/tidy/src/features.rs | 38 | ||||
| -rw-r--r-- | src/tools/tidy/src/features/version.rs | 19 | ||||
| -rw-r--r-- | src/tools/tidy/src/lib.rs | 74 | ||||
| -rw-r--r-- | src/tools/tidy/src/walk.rs | 65 |
10 files changed, 236 insertions, 68 deletions
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ba732cd7742..c4710e8faec 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -647,6 +647,7 @@ impl<'a> Builder<'a> { test::CrateRustdocJsonTypes, test::Linkcheck, test::TierCheck, + test::ReplacePlaceholderTest, test::Cargotest, test::Cargo, test::Rls, @@ -746,7 +747,12 @@ impl<'a> Builder<'a> { install::Src, install::Rustc ), - Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0), + Kind::Run => describe!( + run::ExpandYamlAnchors, + run::BuildManifest, + run::BumpStage0, + run::ReplaceVersionPlaceholder, + ), // These commands either don't use paths, or they're special-cased in Build::build() Kind::Clean | Kind::Format | Kind::Setup => vec![], } diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 25abe7a72fd..511872903d1 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -103,3 +103,25 @@ impl Step for BumpStage0 { builder.run(&mut cmd); } } + +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct ReplaceVersionPlaceholder; + +impl Step for ReplaceVersionPlaceholder { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/replace-version-placeholder") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(ReplaceVersionPlaceholder); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder); + cmd.arg(&builder.src); + builder.run(&mut cmd); + } +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index c759d9b88e2..9cbdb3aca32 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2528,6 +2528,43 @@ impl Step for TierCheck { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct ReplacePlaceholderTest; + +impl Step for ReplacePlaceholderTest { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + /// Ensure the version placeholder replacement tool builds + fn run(self, builder: &Builder<'_>) { + builder.info("build check for version replacement placeholder"); + + // Test the version placeholder replacement tool itself. + let bootstrap_host = builder.config.build; + let compiler = builder.compiler(0, bootstrap_host); + let cargo = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolBootstrap, + bootstrap_host, + "test", + "src/tools/replace-version-placeholder", + SourceType::InTree, + &[], + ); + try_run(builder, &mut cargo.into()); + } + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/replace-version-placeholder") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Self); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct LintDocs { pub compiler: Compiler, pub target: TargetSelection, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 570da20e7d6..5bb40014eb9 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -378,6 +378,7 @@ bootstrap_tool!( JsonDocCk, "src/tools/jsondocck", "jsondocck"; HtmlChecker, "src/tools/html-checker", "html-checker"; BumpStage0, "src/tools/bump-stage0", "bump-stage0"; + ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] diff --git a/src/tools/replace-version-placeholder/Cargo.toml b/src/tools/replace-version-placeholder/Cargo.toml new file mode 100644 index 00000000000..346ce6bd1db --- /dev/null +++ b/src/tools/replace-version-placeholder/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "replace-version-placeholder" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tidy = { path = "../tidy" } +walkdir = "2" diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs new file mode 100644 index 00000000000..146e53f2e9a --- /dev/null +++ b/src/tools/replace-version-placeholder/src/main.rs @@ -0,0 +1,30 @@ +use std::path::PathBuf; +use tidy::{t, walk}; + +pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; + +fn main() { + let root_path: PathBuf = std::env::args_os().nth(1).expect("need path to root of repo").into(); + let version_path = root_path.join("src").join("version"); + let version_str = t!(std::fs::read_to_string(&version_path), version_path); + let version_str = version_str.trim(); + walk::walk( + &root_path, + &mut |path| { + walk::filter_dirs(path) + // We exempt these as they require the placeholder + // for their operation + || path.ends_with("compiler/rustc_passes/src/lib_features.rs") + || path.ends_with("src/tools/tidy/src/features/version.rs") + || path.ends_with("src/tools/replace-version-placeholder") + }, + &mut |entry, contents| { + if !contents.contains(VERSION_PLACEHOLDER) { + return; + } + let new_contents = contents.replace(VERSION_PLACEHOLDER, version_str); + let path = entry.path(); + t!(std::fs::write(&path, new_contents), path); + }, + ); +} diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 2f22c081a54..de292d3305d 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -175,6 +175,36 @@ pub fn check( tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len()); } + let (version, channel) = get_version_and_channel(src_path); + + let all_features_iter = features + .iter() + .map(|feat| (feat, "lang")) + .chain(lib_features.iter().map(|feat| (feat, "lib"))); + for ((feature_name, feature), kind) in all_features_iter { + let since = if let Some(since) = feature.since { since } else { continue }; + if since > version && since != Version::CurrentPlaceholder { + tidy_error!( + bad, + "The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}" + ); + } + if channel == "nightly" && since == version { + tidy_error!( + bad, + "The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}", + version::VERSION_PLACEHOLDER + ); + } + if channel != "nightly" && since == Version::CurrentPlaceholder { + tidy_error!( + bad, + "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {} channel", + version::VERSION_PLACEHOLDER + ); + } + } + if *bad { return CollectedFeatures { lib: lib_features, lang: features }; } @@ -195,6 +225,14 @@ pub fn check( CollectedFeatures { lib: lib_features, lang: features } } +fn get_version_and_channel(src_path: &Path) -> (Version, String) { + let version_str = t!(std::fs::read_to_string(src_path.join("version"))); + let version_str = version_str.trim(); + let version = t!(std::str::FromStr::from_str(&version_str).map_err(|e| format!("{e:?}"))); + let channel_str = t!(std::fs::read_to_string(src_path.join("ci").join("channel"))); + (version, channel_str.trim().to_owned()) +} + fn format_features<'a>( features: &'a Features, family: &'a str, diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs index 620be2f9852..0830c226caf 100644 --- a/src/tools/tidy/src/features/version.rs +++ b/src/tools/tidy/src/features/version.rs @@ -5,14 +5,22 @@ use std::str::FromStr; #[cfg(test)] mod tests; +pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Version { - parts: [u32; 3], +pub enum Version { + Explicit { parts: [u32; 3] }, + CurrentPlaceholder, } impl fmt::Display for Version { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad(&format!("{}.{}.{}", self.parts[0], self.parts[1], self.parts[2])) + match self { + Version::Explicit { parts } => { + f.pad(&format!("{}.{}.{}", parts[0], parts[1], parts[2])) + } + Version::CurrentPlaceholder => f.pad(&format!("CURRENT")), + } } } @@ -32,6 +40,9 @@ impl FromStr for Version { type Err = ParseVersionError; fn from_str(s: &str) -> Result<Self, Self::Err> { + if s == VERSION_PLACEHOLDER { + return Ok(Version::CurrentPlaceholder); + } let mut iter = s.split('.').map(|part| Ok(part.parse()?)); let mut part = || iter.next().unwrap_or(Err(ParseVersionError::WrongNumberOfParts)); @@ -43,6 +54,6 @@ impl FromStr for Version { return Err(ParseVersionError::WrongNumberOfParts); } - Ok(Self { parts }) + Ok(Version::Explicit { parts }) } } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 09848462ae2..12d3bdcd76f 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -3,12 +3,14 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. -use std::fs::File; -use std::io::Read; -use walkdir::{DirEntry, WalkDir}; - -use std::path::Path; - +use walk::{filter_dirs, walk, walk_many, walk_no_read}; + +/// A helper macro to `unwrap` a result except also print out details like: +/// +/// * The expression that failed +/// * The error itself +/// * (optionally) a path connected to the error (e.g. failure to open a file) +#[macro_export] macro_rules! t { ($e:expr, $p:expr) => { match $e { @@ -28,7 +30,8 @@ macro_rules! t { macro_rules! tidy_error { ($bad:expr, $fmt:expr) => ({ *$bad = true; - eprintln!("tidy error: {}", $fmt); + eprint!("tidy error: "); + eprintln!($fmt); }); ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ *$bad = true; @@ -52,59 +55,4 @@ pub mod target_specific_tests; pub mod ui_tests; pub mod unit_tests; pub mod unstable_book; - -fn filter_dirs(path: &Path) -> bool { - let skip = [ - "tidy-test-file", - "compiler/rustc_codegen_cranelift", - "compiler/rustc_codegen_gcc", - "src/llvm-project", - "library/backtrace", - "library/portable-simd", - "library/stdarch", - "src/tools/cargo", - "src/tools/clippy", - "src/tools/miri", - "src/tools/rls", - "src/tools/rust-analyzer", - "src/tools/rust-installer", - "src/tools/rustfmt", - "src/doc/book", - // Filter RLS output directories - "target/rls", - ]; - skip.iter().any(|p| path.ends_with(p)) -} - -fn walk_many( - paths: &[&Path], - skip: &mut dyn FnMut(&Path) -> bool, - f: &mut dyn FnMut(&DirEntry, &str), -) { - for path in paths { - walk(path, skip, f); - } -} - -fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) { - let mut contents = String::new(); - walk_no_read(path, skip, &mut |entry| { - contents.clear(); - if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() { - contents.clear(); - } - f(&entry, &contents); - }); -} - -fn walk_no_read(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry)) { - let walker = WalkDir::new(path).into_iter().filter_entry(|e| !skip(e.path())); - for entry in walker { - if let Ok(entry) = entry { - if entry.file_type().is_dir() { - continue; - } - f(&entry); - } - } -} +pub mod walk; diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs new file mode 100644 index 00000000000..6dca55dfa9f --- /dev/null +++ b/src/tools/tidy/src/walk.rs @@ -0,0 +1,65 @@ +use std::fs::File; +use std::io::Read; +use walkdir::{DirEntry, WalkDir}; + +use std::path::Path; + +pub fn filter_dirs(path: &Path) -> bool { + let skip = [ + "tidy-test-file", + "compiler/rustc_codegen_cranelift", + "compiler/rustc_codegen_gcc", + "src/llvm-project", + "library/backtrace", + "library/portable-simd", + "library/stdarch", + "src/tools/cargo", + "src/tools/clippy", + "src/tools/miri", + "src/tools/rls", + "src/tools/rust-analyzer", + "src/tools/rust-installer", + "src/tools/rustfmt", + "src/doc/book", + // Filter RLS output directories + "target/rls", + ]; + skip.iter().any(|p| path.ends_with(p)) +} + +pub fn walk_many( + paths: &[&Path], + skip: &mut dyn FnMut(&Path) -> bool, + f: &mut dyn FnMut(&DirEntry, &str), +) { + for path in paths { + walk(path, skip, f); + } +} + +pub fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) { + let mut contents = String::new(); + walk_no_read(path, skip, &mut |entry| { + contents.clear(); + if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() { + contents.clear(); + } + f(&entry, &contents); + }); +} + +pub(crate) fn walk_no_read( + path: &Path, + skip: &mut dyn FnMut(&Path) -> bool, + f: &mut dyn FnMut(&DirEntry), +) { + let walker = WalkDir::new(path).into_iter().filter_entry(|e| !skip(e.path())); + for entry in walker { + if let Ok(entry) = entry { + if entry.file_type().is_dir() { + continue; + } + f(&entry); + } + } +} |
