blob: 3369d826ecd7687e36f4dfe670f5b47aac73a15c [file] [log] [blame]
//! 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::fs;
use std::path::Path;
pub fn check(path: &Path, bad: &mut bool) {
if !super::filter_dirs(path) {
return
}
for entry in t!(path.read_dir(), path).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 toml = t!(fs::read_to_string(&tomlfile));
let librs = t!(fs::read_to_string(&libfile));
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,
};
for line in deps.lines() {
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. Cover cases
let whitelisted = krate.starts_with("panic");
if toml.contains("name = \"std\"") && whitelisted {
continue
}
if !librs.contains(&format!("extern crate {}", krate)) {
tidy_error!(bad, "{} doesn't have `extern crate {}`, but Cargo.toml \
depends on it", libfile.display(), krate);
}
}
}