Skip to content

Commit 7bfaeaa

Browse files
committed
tidy: Add a check to ensure Cargo.toml is in sync
This verifies that the crates listed in the `[dependencies]` section of `Cargo.toml` are a subset of the crates listed in `lib.rs` for our in-tree crates. This should help ensure that when we refactor crates over time we keep these dependency lists in sync.
1 parent 9dd3c54 commit 7bfaeaa

File tree

7 files changed

+115
-8
lines changed

7 files changed

+115
-8
lines changed

mk/tests.mk

+2-2
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,13 @@ cleantestlibs:
242242

243243
.PHONY: tidy
244244
tidy: $(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD))
245-
$< $(S)src
245+
$(TARGET_RPATH_VAR0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $< $(S)src
246246

247247
$(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD)): \
248248
$(TSREQ0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) \
249249
$(TLIB0_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.std \
250250
$(call rwildcard,$(S)src/tools/tidy/src,*.rs)
251-
$(STAGE0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) src/tools/tidy/src/main.rs \
251+
$(STAGE0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(S)src/tools/tidy/src/main.rs \
252252
--out-dir $(@D) --crate-name tidy
253253

254254
######################################################################

src/bootstrap/build/step.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,7 @@ impl<'a> Step<'a> {
323323
}
324324

325325
Source::ToolLinkchecker { stage } |
326-
Source::ToolTidy { stage } |
327-
Source::ToolCargoTest { stage } => {
326+
Source::ToolTidy { stage } => {
328327
vec![self.libstd(self.compiler(stage))]
329328
}
330329
Source::ToolErrorIndex { stage } |

src/rustc/test_shim/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@
99
// except according to those terms.
1010

1111
// See comments in Cargo.toml for why this exists
12+
13+
#![feature(test)]
14+
15+
extern crate test;

src/tools/tidy/src/cargo.rs

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Tidy check to ensure that `[dependencies]` and `extern crate` are in sync.
12+
//!
13+
//! This tidy check ensures that all crates listed in the `[dependencies]`
14+
//! section of a `Cargo.toml` are present in the corresponding `lib.rs` as
15+
//! `extern crate` declarations. This should help us keep the DAG correctly
16+
//! structured through various refactorings to prune out unnecessary edges.
17+
18+
use std::io::prelude::*;
19+
use std::fs::File;
20+
use std::path::Path;
21+
22+
pub fn check(path: &Path, bad: &mut bool) {
23+
for entry in t!(path.read_dir()).map(|e| t!(e)) {
24+
// Look for `Cargo.toml` with a sibling `src/lib.rs` or `lib.rs`
25+
if entry.file_name().to_str() == Some("Cargo.toml") {
26+
if path.join("src/lib.rs").is_file() {
27+
verify(&entry.path(), &path.join("src/lib.rs"), bad)
28+
}
29+
if path.join("lib.rs").is_file() {
30+
verify(&entry.path(), &path.join("lib.rs"), bad)
31+
}
32+
} else if t!(entry.file_type()).is_dir() {
33+
check(&entry.path(), bad);
34+
}
35+
}
36+
}
37+
38+
// Verify that the dependencies in Cargo.toml at `tomlfile` are sync'd with the
39+
// `extern crate` annotations in the lib.rs at `libfile`.
40+
fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) {
41+
let mut toml = String::new();
42+
let mut librs = String::new();
43+
t!(t!(File::open(tomlfile)).read_to_string(&mut toml));
44+
t!(t!(File::open(libfile)).read_to_string(&mut librs));
45+
46+
if toml.contains("name = \"bootstrap\"") {
47+
return
48+
}
49+
50+
// "Poor man's TOML parser", just assume we use one syntax for now
51+
//
52+
// We just look for:
53+
//
54+
// [dependencies]
55+
// name = ...
56+
// name2 = ...
57+
// name3 = ...
58+
//
59+
// If we encounter a line starting with `[` then we assume it's the end of
60+
// the dependency section and bail out.
61+
let deps = match toml.find("[dependencies]") {
62+
Some(i) => &toml[i+1..],
63+
None => return,
64+
};
65+
let mut lines = deps.lines().peekable();
66+
while let Some(line) = lines.next() {
67+
if line.starts_with("[") {
68+
break
69+
}
70+
71+
let mut parts = line.splitn(2, '=');
72+
let krate = parts.next().unwrap().trim();
73+
if parts.next().is_none() {
74+
continue
75+
}
76+
77+
// Don't worry about depending on core/std but not saying `extern crate
78+
// core/std`, that's intentional.
79+
if krate == "core" || krate == "std" {
80+
continue
81+
}
82+
83+
// This is intentional, this dependency just makes the crate available
84+
// for others later on.
85+
if krate == "alloc_jemalloc" && toml.contains("name = \"std\"") {
86+
continue
87+
}
88+
89+
if !librs.contains(&format!("extern crate {}", krate)) {
90+
println!("{} doesn't have `extern crate {}`, but Cargo.toml \
91+
depends on it", libfile.display(), krate);
92+
*bad = true;
93+
}
94+
}
95+
}

src/tools/tidy/src/errors.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ pub fn check(path: &Path, bad: &mut bool) {
7171
});
7272

7373
let mut max = 0;
74-
println!("* {} error codes", map.len());
75-
for (code, entries) in map {
74+
for (&code, entries) in map.iter() {
7675
if code > max {
7776
max = code;
7877
}
@@ -81,10 +80,14 @@ pub fn check(path: &Path, bad: &mut bool) {
8180
}
8281

8382
println!("duplicate error code: {}", code);
84-
for (file, line_num, line) in entries {
83+
for &(ref file, line_num, ref line) in entries.iter() {
8584
println!("{}:{}: {}", file.display(), line_num, line);
8685
}
8786
*bad = true;
8887
}
89-
println!("* highest error code: E{:04}", max);
88+
89+
if !*bad {
90+
println!("* {} error codes", map.len());
91+
println!("* highest error code: E{:04}", max);
92+
}
9093
}

src/tools/tidy/src/features.rs

+4
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ pub fn check(path: &Path, bad: &mut bool) {
100100
}
101101
});
102102

103+
if *bad {
104+
return
105+
}
106+
103107
let mut lines = Vec::new();
104108
for feature in features {
105109
lines.push(format!("{:<32} {:<8} {:<12} {:<8}",

src/tools/tidy/src/main.rs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ mod bins;
2929
mod style;
3030
mod errors;
3131
mod features;
32+
mod cargo;
3233

3334
fn main() {
3435
let path = env::args_os().skip(1).next().expect("need an argument");
@@ -38,6 +39,7 @@ fn main() {
3839
bins::check(&path, &mut bad);
3940
style::check(&path, &mut bad);
4041
errors::check(&path, &mut bad);
42+
cargo::check(&path, &mut bad);
4143
features::check(&path, &mut bad);
4244

4345
if bad {

0 commit comments

Comments
 (0)