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.
This commit is contained in:
parent
9dd3c54a2c
commit
7bfaeaaf9c
@ -242,13 +242,13 @@ cleantestlibs:
|
||||
|
||||
.PHONY: tidy
|
||||
tidy: $(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD))
|
||||
$< $(S)src
|
||||
$(TARGET_RPATH_VAR0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $< $(S)src
|
||||
|
||||
$(HBIN0_H_$(CFG_BUILD))/tidy$(X_$(CFG_BUILD)): \
|
||||
$(TSREQ0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) \
|
||||
$(TLIB0_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.std \
|
||||
$(call rwildcard,$(S)src/tools/tidy/src,*.rs)
|
||||
$(STAGE0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) src/tools/tidy/src/main.rs \
|
||||
$(STAGE0_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(S)src/tools/tidy/src/main.rs \
|
||||
--out-dir $(@D) --crate-name tidy
|
||||
|
||||
######################################################################
|
||||
|
@ -323,8 +323,7 @@ impl<'a> Step<'a> {
|
||||
}
|
||||
|
||||
Source::ToolLinkchecker { stage } |
|
||||
Source::ToolTidy { stage } |
|
||||
Source::ToolCargoTest { stage } => {
|
||||
Source::ToolTidy { stage } => {
|
||||
vec![self.libstd(self.compiler(stage))]
|
||||
}
|
||||
Source::ToolErrorIndex { stage } |
|
||||
|
@ -9,3 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
// See comments in Cargo.toml for why this exists
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
95
src/tools/tidy/src/cargo.rs
Normal file
95
src/tools/tidy/src/cargo.rs
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Tidy check to ensure that `[dependencies]` and `extern crate` are in sync.
|
||||
//!
|
||||
//! This tidy check ensures that all crates listed in the `[dependencies]`
|
||||
//! section of a `Cargo.toml` are present in the corresponding `lib.rs` as
|
||||
//! `extern crate` declarations. This should help us keep the DAG correctly
|
||||
//! structured through various refactorings to prune out unnecessary edges.
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
for entry in t!(path.read_dir()).map(|e| t!(e)) {
|
||||
// Look for `Cargo.toml` with a sibling `src/lib.rs` or `lib.rs`
|
||||
if entry.file_name().to_str() == Some("Cargo.toml") {
|
||||
if path.join("src/lib.rs").is_file() {
|
||||
verify(&entry.path(), &path.join("src/lib.rs"), bad)
|
||||
}
|
||||
if path.join("lib.rs").is_file() {
|
||||
verify(&entry.path(), &path.join("lib.rs"), bad)
|
||||
}
|
||||
} else if t!(entry.file_type()).is_dir() {
|
||||
check(&entry.path(), bad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the dependencies in Cargo.toml at `tomlfile` are sync'd with the
|
||||
// `extern crate` annotations in the lib.rs at `libfile`.
|
||||
fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) {
|
||||
let mut toml = String::new();
|
||||
let mut librs = String::new();
|
||||
t!(t!(File::open(tomlfile)).read_to_string(&mut toml));
|
||||
t!(t!(File::open(libfile)).read_to_string(&mut librs));
|
||||
|
||||
if toml.contains("name = \"bootstrap\"") {
|
||||
return
|
||||
}
|
||||
|
||||
// "Poor man's TOML parser", just assume we use one syntax for now
|
||||
//
|
||||
// We just look for:
|
||||
//
|
||||
// [dependencies]
|
||||
// name = ...
|
||||
// name2 = ...
|
||||
// name3 = ...
|
||||
//
|
||||
// If we encounter a line starting with `[` then we assume it's the end of
|
||||
// the dependency section and bail out.
|
||||
let deps = match toml.find("[dependencies]") {
|
||||
Some(i) => &toml[i+1..],
|
||||
None => return,
|
||||
};
|
||||
let mut lines = deps.lines().peekable();
|
||||
while let Some(line) = lines.next() {
|
||||
if line.starts_with("[") {
|
||||
break
|
||||
}
|
||||
|
||||
let mut parts = line.splitn(2, '=');
|
||||
let krate = parts.next().unwrap().trim();
|
||||
if parts.next().is_none() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Don't worry about depending on core/std but not saying `extern crate
|
||||
// core/std`, that's intentional.
|
||||
if krate == "core" || krate == "std" {
|
||||
continue
|
||||
}
|
||||
|
||||
// This is intentional, this dependency just makes the crate available
|
||||
// for others later on.
|
||||
if krate == "alloc_jemalloc" && toml.contains("name = \"std\"") {
|
||||
continue
|
||||
}
|
||||
|
||||
if !librs.contains(&format!("extern crate {}", krate)) {
|
||||
println!("{} doesn't have `extern crate {}`, but Cargo.toml \
|
||||
depends on it", libfile.display(), krate);
|
||||
*bad = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -71,8 +71,7 @@ pub fn check(path: &Path, bad: &mut bool) {
|
||||
});
|
||||
|
||||
let mut max = 0;
|
||||
println!("* {} error codes", map.len());
|
||||
for (code, entries) in map {
|
||||
for (&code, entries) in map.iter() {
|
||||
if code > max {
|
||||
max = code;
|
||||
}
|
||||
@ -81,10 +80,14 @@ pub fn check(path: &Path, bad: &mut bool) {
|
||||
}
|
||||
|
||||
println!("duplicate error code: {}", code);
|
||||
for (file, line_num, line) in entries {
|
||||
for &(ref file, line_num, ref line) in entries.iter() {
|
||||
println!("{}:{}: {}", file.display(), line_num, line);
|
||||
}
|
||||
*bad = true;
|
||||
}
|
||||
|
||||
if !*bad {
|
||||
println!("* {} error codes", map.len());
|
||||
println!("* highest error code: E{:04}", max);
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +100,10 @@ pub fn check(path: &Path, bad: &mut bool) {
|
||||
}
|
||||
});
|
||||
|
||||
if *bad {
|
||||
return
|
||||
}
|
||||
|
||||
let mut lines = Vec::new();
|
||||
for feature in features {
|
||||
lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
|
||||
|
@ -29,6 +29,7 @@ mod bins;
|
||||
mod style;
|
||||
mod errors;
|
||||
mod features;
|
||||
mod cargo;
|
||||
|
||||
fn main() {
|
||||
let path = env::args_os().skip(1).next().expect("need an argument");
|
||||
@ -38,6 +39,7 @@ fn main() {
|
||||
bins::check(&path, &mut bad);
|
||||
style::check(&path, &mut bad);
|
||||
errors::check(&path, &mut bad);
|
||||
cargo::check(&path, &mut bad);
|
||||
features::check(&path, &mut bad);
|
||||
|
||||
if bad {
|
||||
|
Loading…
Reference in New Issue
Block a user