Skip to content

Commit 652f116

Browse files
committed
impl watcher
1 parent d61f55d commit 652f116

File tree

6 files changed

+232
-0
lines changed

6 files changed

+232
-0
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5367,6 +5367,7 @@ dependencies = [
53675367
"cargo_metadata 0.19.1",
53685368
"fluent-syntax",
53695369
"ignore",
5370+
"md-5",
53705371
"miropt-test-tools",
53715372
"regex",
53725373
"rustc-hash 2.1.0",

src/tools/tidy/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ termcolor = "1.1.3"
1616
rustc-hash = "2.0.0"
1717
fluent-syntax = "0.11.1"
1818
similar = "2.5.0"
19+
md-5 = "0.10"
1920

2021
[[bin]]
2122
name = "rust-tidy"

src/tools/tidy/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,5 @@ pub mod unit_tests;
9393
pub mod unknown_revision;
9494
pub mod unstable_book;
9595
pub mod walk;
96+
pub mod watcher;
9697
pub mod x_version;

src/tools/tidy/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ fn main() {
146146

147147
check!(x_version, &root_path, &cargo);
148148

149+
check!(watcher, &root_path);
150+
149151
let collected = {
150152
drain_handles(&mut handles);
151153

src/tools/tidy/src/watcher.rs

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
//! Checks that text between tags unchanged, emitting warning otherwise,
2+
//! allowing asserting that code in different places over codebase is in sync.
3+
//!
4+
//! This works via hashing text between tags and saving hash in tidy.
5+
//!
6+
//! Usage:
7+
//!
8+
//! some.rs:
9+
//! // tidy-ticket-foo
10+
//! const FOO: usize = 42;
11+
//! // tidy-ticket-foo
12+
//!
13+
//! some.sh:
14+
//! # tidy-ticket-foo
15+
//! export FOO=42
16+
//! # tidy-ticket-foo
17+
use md5::{Digest, Md5};
18+
use std::fs;
19+
use std::path::Path;
20+
21+
#[cfg(test)]
22+
mod tests;
23+
24+
/// Return hash for source text between 2 tag occurrence,
25+
/// ignoring lines where tag written
26+
///
27+
/// Expecting:
28+
/// tag is not multiline
29+
/// source always have at least 2 occurrence of tag (>2 ignored)
30+
fn span_hash(source: &str, tag: &str, bad: &mut bool) -> Result<String, ()> {
31+
let start_idx = match source.find(tag) {
32+
Some(idx) => idx,
33+
None => return Err(tidy_error!(bad, "tag {} should exist in provided text", tag)),
34+
};
35+
let end_idx = {
36+
let end = match source[start_idx + tag.len()..].find(tag) {
37+
// index from source start
38+
Some(idx) => start_idx + tag.len() + idx,
39+
None => return Err(tidy_error!(bad, "tag end {} should exist in provided text", tag)),
40+
};
41+
// second line with tag can contain some other text before tag, ignore it
42+
// by finding position of previous line ending
43+
//
44+
// FIXME: what if line ending is \r\n? In that case \r will be hashed too
45+
let offset = source[start_idx..end].rfind('\n').unwrap();
46+
start_idx + offset
47+
};
48+
49+
let mut hasher = Md5::new();
50+
51+
source[start_idx..end_idx]
52+
.lines()
53+
// skip first line with tag
54+
.skip(1)
55+
// hash next lines, ignoring end trailing whitespaces
56+
.for_each(|line| {
57+
let trimmed = line.trim_end();
58+
hasher.update(trimmed);
59+
});
60+
Ok(format!("{:x}", hasher.finalize()))
61+
}
62+
63+
fn check_entry(entry: &ListEntry<'_>, group_idx: usize, bad: &mut bool, root_path: &Path) {
64+
let file = fs::read_to_string(root_path.join(Path::new(entry.0)))
65+
.unwrap_or_else(|e| panic!("{:?}, path: {}", e, entry.0));
66+
let actual_hash = span_hash(&file, entry.2, bad).unwrap();
67+
if actual_hash != entry.1 {
68+
// Write tidy error description for wather only once.
69+
// Will not work if there was previous errors of other types.
70+
if *bad == false {
71+
tidy_error!(
72+
bad,
73+
"The code blocks tagged with tidy watcher has changed.\n\
74+
It's likely that code blocks with the following tags need to be changed too. Check src/tools/tidy/src/watcher.rs, find tag/hash in TIDY_WATCH_LIST list \
75+
and verify that sources for provided group of tags in sync. Once that done, run tidy again and update hashes in TIDY_WATCH_LIST with provided actual hashes."
76+
)
77+
}
78+
tidy_error!(
79+
bad,
80+
"hash for tag `{}` in path `{}` mismatch:\n actual: `{}`, expected: `{}`\n \
81+
Verify that tags `{:?}` in sync.",
82+
entry.2,
83+
entry.0,
84+
actual_hash,
85+
entry.1,
86+
TIDY_WATCH_LIST[group_idx].iter().map(|e| e.2).collect::<Vec<&str>>()
87+
);
88+
}
89+
}
90+
91+
macro_rules! add_group {
92+
($($entry:expr),*) => {
93+
&[$($entry),*]
94+
};
95+
}
96+
97+
/// (path, hash, tag)
98+
type ListEntry<'a> = (&'a str, &'a str, &'a str);
99+
100+
/// List of tags to watch, along with paths and hashes
101+
#[rustfmt::skip]
102+
const TIDY_WATCH_LIST: &[&[ListEntry<'_>]] = &[
103+
// sync perf commit across dockerfile and opt-dist
104+
add_group!(
105+
("src/tools/opt-dist/src/main.rs", "f99844fda86216628167cd3391844ed1", "tidy-ticket-perf-commit"),
106+
("src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile", "fa9a88e552735e9f93934501e9c8d87a", "tidy-ticket-perf-commit")
107+
),
108+
109+
add_group!(
110+
("compiler/rustc_ast/src/token.rs", "0f6ba78f1007a398f01cc6217838cadc", "tidy-ticket-ast-from_token"),
111+
("compiler/rustc_ast/src/token.rs", "9a78008a2377486eadf19d67ee4fdce2", "tidy-ticket-ast-can_begin_literal_maybe_minus"),
112+
("compiler/rustc_parse/src/parser/expr.rs", "500240cdc80690209060fdce10ce065a", "tidy-ticket-rustc_parse-can_begin_literal_maybe_minus")
113+
),
114+
115+
add_group!(
116+
("compiler/rustc_builtin_macros/src/assert/context.rs", "de6cc928308947a05a373a355e036f68", "tidy-ticket-all-expr-kinds"),
117+
("tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs", "78ce54cc25baeac3ae07c876db25180c", "tidy-ticket-all-expr-kinds")
118+
),
119+
120+
add_group!(
121+
("compiler/rustc_const_eval/src/interpret/validity.rs", "91c69e391741f64b7624e1bda4b31bc3", "tidy-ticket-try_visit_primitive"),
122+
("compiler/rustc_const_eval/src/interpret/validity.rs", "763a70aa04279a7b1cd184b75f79751d", "tidy-ticket-visit_value")
123+
),
124+
125+
// sync self-profile-events help mesage with actual list of events
126+
add_group!(
127+
("compiler/rustc_data_structures/src/profiling.rs", "881e7899c7d6904af1bc000594ee0418", "tidy-ticket-self-profile-events"),
128+
("compiler/rustc_session/src/options.rs", "012ee5a3b61ee1377744e5c6913fa00a", "tidy-ticket-self-profile-events")
129+
),
130+
131+
add_group!(
132+
("compiler/rustc_errors/src/json.rs", "5907da5c0476785fe2aae4d0d62f7171", "tidy-ticket-UnusedExterns"),
133+
("src/librustdoc/doctest.rs", "b5bb5128abb4a2dbb47bb1a1a083ba9b", "tidy-ticket-UnusedExterns")
134+
),
135+
136+
add_group!(
137+
("compiler/rustc_middle/src/ty/util.rs", "cae64b1bc854e7ee81894212facb5bfa", "tidy-ticket-static_ptr_ty"),
138+
("compiler/rustc_middle/src/ty/util.rs", "6f5ead08474b4d3e358db5d3c7aef970", "tidy-ticket-thread_local_ptr_ty")
139+
),
140+
141+
add_group!(
142+
("compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs", "c17706947fc814aa5648972a5b3dc143", "tidy-ticket-arity"),
143+
("compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs", "7ce77b84c142c22530b047703ef209f0", "tidy-ticket-wildcards")
144+
),
145+
146+
add_group!(
147+
("compiler/rustc_monomorphize/src/partitioning.rs", "f4f33e9c14f4e0c3a20b5240ae36a7c8", "tidy-ticket-short_description"),
148+
("compiler/rustc_codegen_ssa/src/back/write.rs", "5286f7f76fcf564c98d7a8eaeec39b18", "tidy-ticket-short_description")
149+
),
150+
151+
add_group!(
152+
("compiler/rustc_session/src/config/sigpipe.rs", "8d765a5c613d931852c0f59ed1997dcd", "tidy-ticket-sigpipe"),
153+
("library/std/src/sys/unix/mod.rs", "2cdc37081831cdcf44f3331efbe440af", "tidy-ticket-sigpipe")
154+
),
155+
156+
add_group!(
157+
("compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs", "6b4ce7c9aa0e799618d53926fb3e9684", "tidy-ticket-extract_tupled_inputs_and_output_from_callable"),
158+
("compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs", "f1085622f189fc5ec2786e4abff67915", "tidy-ticket-assemble_fn_pointer_candidates")
159+
),
160+
161+
add_group!(
162+
("compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs", "d0c807d90501f3f63dffc3e7ec046c20", "tidy-ticket-rematch_unsize"),
163+
("compiler/rustc_trait_selection/src/solve/trait_goals.rs", "f1b0ce28128b5d5a5b545af3f3cf55f4", "tidy-ticket-consider_builtin_unsize_candidate")
164+
),
165+
166+
add_group!(
167+
("compiler/rustc_trait_selection/src/traits/project.rs", "66585f93352fe56a5be6cc5a63bcc756", "tidy-ticket-assemble_candidates_from_impls-UserDefined"),
168+
("compiler/rustc_ty_utils/src/instance.rs", "5ad30b96493636ba3357448f0b0a4d76", "tidy-ticket-resolve_associated_item-UserDefined")
169+
),
170+
171+
add_group!(
172+
("compiler/rustc_hir_analysis/src/lib.rs", "842e23fb65caf3a96681686131093316", "tidy-ticket-sess-time-item_types_checking"),
173+
("src/librustdoc/core.rs", "85d9dd0cbb94fd521e2d15a8ed38a75f", "tidy-ticket-sess-time-item_types_checking")
174+
),
175+
176+
add_group!(
177+
("library/core/src/ptr/metadata.rs", "57fc0e05c177c042c9766cc1134ae240", "tidy-ticket-static_assert_expected_bounds_for_metadata"),
178+
("library/core/tests/ptr.rs", "13ecb32e2a0db0998ff94f33a30f5cfd", "tidy-ticket-static_assert_expected_bounds_for_metadata")
179+
),
180+
];
181+
182+
pub fn check(root_path: &Path, bad: &mut bool) {
183+
for (group_idx, group) in TIDY_WATCH_LIST.iter().enumerate() {
184+
for entry in group.iter() {
185+
check_entry(entry, group_idx, bad, root_path);
186+
}
187+
}
188+
}

src/tools/tidy/src/watcher/tests.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use super::*;
2+
3+
#[test]
4+
fn test_span_hash_one_line() {
5+
let source = "some text\ntidy-tag\ncheckme=42\ntidy-tag\n";
6+
let tag = "tidy-tag";
7+
assert_eq!("42258eba764c3f94a24de379e5715dc8", span_hash(source, tag, &mut true).unwrap());
8+
}
9+
10+
#[test]
11+
fn test_span_hash_multiple_lines() {
12+
let source = "some text\ntidy-tag\ncheckme=42\nother line\ntidy-tag\n";
13+
let tag = "tidy-tag";
14+
assert_eq!("49cb23dc2032ceea671ca48092750a1c", span_hash(source, tag, &mut true).unwrap());
15+
}
16+
17+
#[test]
18+
fn test_span_hash_has_some_text_in_line_with_tag() {
19+
let source = "some text\ntidy-tag ignore me\ncheckme=42\nother line\ntidy-tag\n";
20+
let tag = "tidy-tag";
21+
assert_eq!("49cb23dc2032ceea671ca48092750a1c", span_hash(source, tag, &mut true).unwrap());
22+
}
23+
24+
#[test]
25+
fn test_span_hash_has_some_text_in_line_before_second_tag() {
26+
let source = r#"
27+
RUN ./build-clang.sh
28+
ENV CC=clang CXX=clang++
29+
# tidy-ticket-perf-commit
30+
# rustc-perf version from 2023-05-30
31+
ENV PERF_COMMIT 8b2ac3042e1ff2c0074455a0a3618adef97156b1
32+
# tidy-ticket-perf-commit
33+
RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \
34+
unzip perf.zip && \
35+
mv rustc-perf-$PERF_COMMIT rustc-perf && \
36+
rm perf.zip"#;
37+
let tag = "tidy-ticket-perf-commit";
38+
assert_eq!("76c8d9783e38e25a461355f82fcd7955", span_hash(source, tag, &mut true).unwrap());
39+
}

0 commit comments

Comments
 (0)