Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 136 additions & 41 deletions src/tools/tidy/src/deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,40 +48,116 @@ const LICENSES: &[&str] = &[

type ExceptionList = &'static [(&'static str, &'static str)];

#[derive(Clone, Copy)]
pub(crate) struct WorkspaceInfo<'a> {
/// Path to the directory containing the workspace root Cargo.toml file.
pub(crate) path: &'a str,
/// The list of license exceptions.
pub(crate) exceptions: ExceptionList,
/// Optionally:
/// * A list of crates for which dependencies need to be explicitly allowed.
/// * The list of allowed dependencies.
/// * The source code location of the allowed dependencies list
crates_and_deps: Option<(&'a [&'a str], &'a [&'a str], ListLocation)>,
/// Submodules required for the workspace
pub(crate) submodules: &'a [&'a str],
}

/// The workspaces to check for licensing and optionally permitted dependencies.
///
/// Each entry consists of a tuple with the following elements:
///
/// * The path to the workspace root Cargo.toml file.
/// * The list of license exceptions.
/// * Optionally a tuple of:
/// * A list of crates for which dependencies need to be explicitly allowed.
/// * The list of allowed dependencies.
/// * Submodules required for the workspace.
// FIXME auto detect all cargo workspaces
pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, &[&str])] = &[
pub(crate) const WORKSPACES: &[WorkspaceInfo<'static>] = &[
// The root workspace has to be first for check_rustfix to work.
(".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES)), &[]),
("library", EXCEPTIONS_STDLIB, Some((&["sysroot"], PERMITTED_STDLIB_DEPENDENCIES)), &[]),
// Outside of the alphabetical section because rustfmt formats it using multiple lines.
(
"compiler/rustc_codegen_cranelift",
EXCEPTIONS_CRANELIFT,
Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)),
&[],
),
// tidy-alphabetical-start
("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None, &[]),
("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None, &[]),
("src/tools/cargo", EXCEPTIONS_CARGO, None, &["src/tools/cargo"]),
//("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored
//("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored
("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None, &[]),
("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]),
("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]),
("src/tools/test-float-parse", EXCEPTIONS, None, &[]),
("tests/run-make-cargo/uefi-qemu/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]),
// tidy-alphabetical-end
WorkspaceInfo {
path: ".",
exceptions: EXCEPTIONS,
crates_and_deps: Some((
&["rustc-main"],
PERMITTED_RUSTC_DEPENDENCIES,
PERMITTED_RUSTC_DEPS_LOCATION,
)),
submodules: &[],
},
WorkspaceInfo {
path: "library",
exceptions: EXCEPTIONS_STDLIB,
crates_and_deps: Some((
&["sysroot"],
PERMITTED_STDLIB_DEPENDENCIES,
PERMITTED_STDLIB_DEPS_LOCATION,
)),
submodules: &[],
},
{
WorkspaceInfo {
path: "compiler/rustc_codegen_cranelift",
exceptions: EXCEPTIONS_CRANELIFT,
crates_and_deps: Some((
&["rustc_codegen_cranelift"],
PERMITTED_CRANELIFT_DEPENDENCIES,
PERMITTED_CRANELIFT_DEPS_LOCATION,
)),
submodules: &[],
}
},
WorkspaceInfo {
path: "compiler/rustc_codegen_gcc",
exceptions: EXCEPTIONS_GCC,
crates_and_deps: None,
submodules: &[],
},
WorkspaceInfo {
path: "src/bootstrap",
exceptions: EXCEPTIONS_BOOTSTRAP,
crates_and_deps: None,
submodules: &[],
},
WorkspaceInfo {
path: "src/tools/cargo",
exceptions: EXCEPTIONS_CARGO,
crates_and_deps: None,
submodules: &["src/tools/cargo"],
},
// FIXME uncomment once all deps are vendored
// WorkspaceInfo {
// path: "src/tools/miri/test-cargo-miri",
// crates_and_deps: None
// submodules: &[],
// },
// WorkspaceInfo {
// path: "src/tools/miri/test_dependencies",
// crates_and_deps: None,
// submodules: &[],
// }
WorkspaceInfo {
path: "src/tools/rust-analyzer",
exceptions: EXCEPTIONS_RUST_ANALYZER,
crates_and_deps: None,
submodules: &[],
},
WorkspaceInfo {
path: "src/tools/rustbook",
exceptions: EXCEPTIONS_RUSTBOOK,
crates_and_deps: None,
submodules: &["src/doc/book", "src/doc/reference"],
},
WorkspaceInfo {
path: "src/tools/rustc-perf",
exceptions: EXCEPTIONS_RUSTC_PERF,
crates_and_deps: None,
submodules: &["src/tools/rustc-perf"],
},
WorkspaceInfo {
path: "src/tools/test-float-parse",
exceptions: EXCEPTIONS,
crates_and_deps: None,
submodules: &[],
},
WorkspaceInfo {
path: "tests/run-make-cargo/uefi-qemu/uefi_qemu_test",
exceptions: EXCEPTIONS_UEFI_QEMU_TEST,
crates_and_deps: None,
submodules: &[],
},
];

/// These are exceptions to Rust's permissive licensing policy, and
Expand Down Expand Up @@ -226,7 +302,20 @@ const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[
("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptable, but we use it under MIT OR Apache-2.0
];

const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
#[derive(Clone, Copy)]
struct ListLocation {
path: &'static str,
line: u32,
}

/// Creates a [`ListLocation`] for the current location (with an additional offset to the actual list start);
macro_rules! location {
(+ $offset:literal) => {
ListLocation { path: file!(), line: line!() + $offset }
};
}

const PERMITTED_RUSTC_DEPS_LOCATION: ListLocation = location!(+6);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: wow I didn't realize we even had these location hints... cheeky.


/// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
///
Expand Down Expand Up @@ -452,6 +541,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
// tidy-alphabetical-end
];

const PERMITTED_STDLIB_DEPS_LOCATION: ListLocation = location!(+2);

const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
// tidy-alphabetical-start
"addr2line",
Expand Down Expand Up @@ -493,6 +584,8 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
// tidy-alphabetical-end
];

const PERMITTED_CRANELIFT_DEPS_LOCATION: ListLocation = location!(+2);

const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
// tidy-alphabetical-start
"allocator-api2",
Expand Down Expand Up @@ -567,29 +660,30 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {

check_proc_macro_dep_list(root, cargo, bless, bad);

for &(workspace, exceptions, permitted_deps, submodules) in WORKSPACES {
for &WorkspaceInfo { path, exceptions, crates_and_deps, submodules } in WORKSPACES {
if has_missing_submodule(root, submodules) {
continue;
}

if !root.join(workspace).join("Cargo.lock").exists() {
tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock");
if !root.join(path).join("Cargo.lock").exists() {
tidy_error!(bad, "the `{path}` workspace doesn't have a Cargo.lock");
continue;
}

let mut cmd = cargo_metadata::MetadataCommand::new();
cmd.cargo_path(cargo)
.manifest_path(root.join(workspace).join("Cargo.toml"))
.manifest_path(root.join(path).join("Cargo.toml"))
.features(cargo_metadata::CargoOpt::AllFeatures)
.other_options(vec!["--locked".to_owned()]);
let metadata = t!(cmd.exec());

check_license_exceptions(&metadata, workspace, exceptions, bad);
if let Some((crates, permitted_deps)) = permitted_deps {
check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad);
check_license_exceptions(&metadata, path, exceptions, bad);
if let Some((crates, permitted_deps, location)) = crates_and_deps {
let descr = crates.get(0).unwrap_or(&path);
check_permitted_dependencies(&metadata, descr, permitted_deps, crates, location, bad);
}

if workspace == "library" {
if path == "library" {
check_runtime_license_exceptions(&metadata, bad);
check_runtime_no_duplicate_dependencies(&metadata, bad);
check_runtime_no_proc_macros(&metadata, bad);
Expand Down Expand Up @@ -834,6 +928,7 @@ fn check_permitted_dependencies(
descr: &str,
permitted_dependencies: &[&'static str],
restricted_dependency_crates: &[&'static str],
permitted_location: ListLocation,
bad: &mut bool,
) {
let mut has_permitted_dep_error = false;
Expand Down Expand Up @@ -894,7 +989,7 @@ fn check_permitted_dependencies(
}

if has_permitted_dep_error {
eprintln!("Go to `{PERMITTED_DEPS_LOCATION}` for the list.");
eprintln!("Go to `{}:{}` for the list.", permitted_location.path, permitted_location.line);
}
}

Expand Down
12 changes: 7 additions & 5 deletions src/tools/tidy/src/extdeps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
use std::fs;
use std::path::Path;

use crate::deps::WorkspaceInfo;

/// List of allowed sources for packages.
const ALLOWED_SOURCES: &[&str] = &[
r#""registry+https://github.com/rust-lang/crates.io-index""#,
Expand All @@ -13,22 +15,22 @@ const ALLOWED_SOURCES: &[&str] = &[
/// Checks for external package sources. `root` is the path to the directory that contains the
/// workspace `Cargo.toml`.
pub fn check(root: &Path, bad: &mut bool) {
for &(workspace, _, _, submodules) in crate::deps::WORKSPACES {
for &WorkspaceInfo { path, submodules, .. } in crate::deps::WORKSPACES {
if crate::deps::has_missing_submodule(root, submodules) {
continue;
}

// FIXME check other workspaces too
// `Cargo.lock` of rust.
let path = root.join(workspace).join("Cargo.lock");
let lockfile = root.join(path).join("Cargo.lock");

if !path.exists() {
tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock");
if !lockfile.exists() {
tidy_error!(bad, "the `{path}` workspace doesn't have a Cargo.lock");
continue;
}

// Open and read the whole file.
let cargo_lock = t!(fs::read_to_string(&path));
let cargo_lock = t!(fs::read_to_string(&lockfile));

// Process each line.
for line in cargo_lock.lines() {
Expand Down
Loading