mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Auto merge of #100591 - est31:stabilization_placeholder, r=Mark-Simulacrum
Require stabilizations to use a placeholder instead of writing out stabilization version Implements the idea from [this](https://rust-lang.zulipchat.com/#narrow/stream/241545-t-release/topic/libs.20stabilization.20placeholder) zulip stream. It's a common phenomenon that feature stabilizations don't make it into a particular release, but the version is still inaccurate. Often this is caught in the PR, but it can also require subsequent changes to adjust/correct the version. A list with examples of such PRs is given in #100577, but it's far from complete. This PR requires stabilization PRs to use the placeholder `CURRENT_RUSTC_VERSION`, enforced via tidy tooling. The PR also adds a tool that replaces the placeholder with the version number. It can be invoked via `./x.py run src/tools/replace-version-placeholder` and is supposed to be ran upon beta branching as well as version bumping and any backports to the beta branch. I filed PRs to the dev guide and forge to document these changes in the release and stabilization workflows: * The [dev guide](https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#determining-the-stabilization-version) PR: https://github.com/rust-lang/rustc-dev-guide/pull/1443 * The [std dev guide](https://std-dev-guide.rust-lang.org/) PR: https://github.com/rust-lang/std-dev-guide/pull/43 * The [forge](https://github.com/rust-lang/rust-forge) PR: https://github.com/rust-lang/rust-forge/pull/643 Alternative to #100577 which added checking.
This commit is contained in:
commit
eaadb8947b
@ -3293,6 +3293,14 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "replace-version-placeholder"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"tidy",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rls"
|
||||
version = "1.41.0"
|
||||
|
@ -35,6 +35,7 @@ members = [
|
||||
"src/tools/jsondocck",
|
||||
"src/tools/html-checker",
|
||||
"src/tools/bump-stage0",
|
||||
"src/tools/replace-version-placeholder",
|
||||
"src/tools/lld-wrapper",
|
||||
]
|
||||
|
||||
|
@ -187,7 +187,7 @@ declare_features! (
|
||||
/// especially around globs and shadowing (RFC 1560).
|
||||
(accepted, item_like_imports, "1.15.0", Some(35120), None),
|
||||
/// Allows `'a: { break 'a; }`.
|
||||
(accepted, label_break_value, "1.65.0", Some(48594), None),
|
||||
(accepted, label_break_value, "CURRENT_RUSTC_VERSION", Some(48594), None),
|
||||
/// Allows `if/while p && let q = r && ...` chains.
|
||||
(accepted, let_chains, "1.64.0", Some(53667), None),
|
||||
/// Allows `break {expr}` with a value inside `loop`s.
|
||||
|
@ -54,6 +54,14 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
|
||||
|
||||
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
|
||||
let version = option_env!("CFG_VERSION").unwrap_or("<current>");
|
||||
let version = version.split(' ').next().unwrap();
|
||||
since = Some(Symbol::intern(&version));
|
||||
}
|
||||
|
||||
if let Some(feature) = feature {
|
||||
// This additional check for stability is to make sure we
|
||||
// don't emit additional, irrelevant errors for malformed
|
||||
|
@ -95,8 +95,8 @@ impl<T: ?Sized> *const T {
|
||||
///
|
||||
/// This is a bit safer than `as` because it wouldn't silently change the type if the code is
|
||||
/// refactored.
|
||||
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
|
||||
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
|
||||
#[stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub const fn cast_mut(self) -> *mut T {
|
||||
self as _
|
||||
}
|
||||
|
@ -100,8 +100,8 @@ impl<T: ?Sized> *mut T {
|
||||
/// coercion.
|
||||
///
|
||||
/// [`cast_mut`]: #method.cast_mut
|
||||
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
|
||||
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
|
||||
#[stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub const fn cast_const(self) -> *const T {
|
||||
self as _
|
||||
}
|
||||
|
@ -58,7 +58,7 @@
|
||||
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change
|
||||
//! how backtraces are captured.
|
||||
|
||||
#![stable(feature = "backtrace", since = "1.65.0")]
|
||||
#![stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@ -104,7 +104,7 @@ use crate::vec::Vec;
|
||||
/// previous point in time. In some instances the `Backtrace` type may
|
||||
/// internally be empty due to configuration. For more information see
|
||||
/// `Backtrace::capture`.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[must_use]
|
||||
pub struct Backtrace {
|
||||
inner: Inner,
|
||||
@ -112,21 +112,21 @@ pub struct Backtrace {
|
||||
|
||||
/// The current status of a backtrace, indicating whether it was captured or
|
||||
/// whether it is empty for some other reason.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum BacktraceStatus {
|
||||
/// Capturing a backtrace is not supported, likely because it's not
|
||||
/// implemented for the current platform.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
Unsupported,
|
||||
/// Capturing a backtrace has been disabled through either the
|
||||
/// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
Disabled,
|
||||
/// A backtrace has been captured and the `Backtrace` should print
|
||||
/// reasonable information when rendered.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
Captured,
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ enum BytesOrWide {
|
||||
Wide(Vec<u16>),
|
||||
}
|
||||
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl fmt::Debug for Backtrace {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let capture = match &self.inner {
|
||||
@ -289,7 +289,7 @@ impl Backtrace {
|
||||
///
|
||||
/// To forcibly capture a backtrace regardless of environment variables, use
|
||||
/// the `Backtrace::force_capture` function.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[inline(never)] // want to make sure there's a frame here to remove
|
||||
pub fn capture() -> Backtrace {
|
||||
if !Backtrace::enabled() {
|
||||
@ -308,7 +308,7 @@ impl Backtrace {
|
||||
/// Note that capturing a backtrace can be an expensive operation on some
|
||||
/// platforms, so this should be used with caution in performance-sensitive
|
||||
/// parts of code.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[inline(never)] // want to make sure there's a frame here to remove
|
||||
pub fn force_capture() -> Backtrace {
|
||||
Backtrace::create(Backtrace::force_capture as usize)
|
||||
@ -316,8 +316,8 @@ impl Backtrace {
|
||||
|
||||
/// Forcibly captures a disabled backtrace, regardless of environment
|
||||
/// variable configuration.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[rustc_const_stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub const fn disabled() -> Backtrace {
|
||||
Backtrace { inner: Inner::Disabled }
|
||||
}
|
||||
@ -361,7 +361,7 @@ impl Backtrace {
|
||||
/// Returns the status of this backtrace, indicating whether this backtrace
|
||||
/// request was unsupported, disabled, or a stack trace was actually
|
||||
/// captured.
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[must_use]
|
||||
pub fn status(&self) -> BacktraceStatus {
|
||||
match self.inner {
|
||||
@ -381,7 +381,7 @@ impl<'a> Backtrace {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
||||
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl fmt::Display for Backtrace {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let capture = match &self.inner {
|
||||
|
@ -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![],
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -2527,6 +2527,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,
|
||||
|
@ -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)]
|
||||
|
10
src/tools/replace-version-placeholder/Cargo.toml
Normal file
10
src/tools/replace-version-placeholder/Cargo.toml
Normal file
@ -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"
|
30
src/tools/replace-version-placeholder/src/main.rs
Normal file
30
src/tools/replace-version-placeholder/src/main.rs
Normal file
@ -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);
|
||||
},
|
||||
);
|
||||
}
|
@ -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,
|
||||
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
65
src/tools/tidy/src/walk.rs
Normal file
65
src/tools/tidy/src/walk.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user