about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEric Huss <eric@huss.org>2020-02-24 13:47:49 -0800
committerEric Huss <eric@huss.org>2020-03-12 19:19:18 -0700
commitbc738f239348dd62f18d40fdc001757ec00cfea5 (patch)
tree84b84b784c3562e7b63112b7ee12ee1d2761f0bf /src
parentbe10f14329c63710ca1b47e3ebebffed59a175f4 (diff)
downloadrust-bc738f239348dd62f18d40fdc001757ec00cfea5.tar.gz
rust-bc738f239348dd62f18d40fdc001757ec00cfea5.zip
tidy: Verify the runtime crates don't have license exceptions.
Diffstat (limited to 'src')
-rw-r--r--src/tools/tidy/src/deps.rs63
1 files changed, 57 insertions, 6 deletions
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index f6ad58a6011..aa4d86e2a84 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -1,6 +1,6 @@
 //! Checks the licenses of third-party dependencies.
 
-use cargo_metadata::{Metadata, Package, PackageId};
+use cargo_metadata::{Metadata, Package, PackageId, Resolve};
 use std::collections::{BTreeSet, HashSet};
 use std::path::Path;
 
@@ -50,6 +50,10 @@ const EXCEPTIONS: &[(&str, &str)] = &[
     ("crossbeam-channel", "MIT/Apache-2.0 AND BSD-2-Clause"), // cargo
 ];
 
+/// These are the root crates that are part of the runtime. The licenses for
+/// these and all their dependencies *must not* be in the exception list.
+const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "panic_abort", "panic_unwind"];
+
 /// Which crates to check against the whitelist?
 const WHITELIST_CRATES: &[&str] = &["rustc", "rustc_codegen_llvm"];
 
@@ -227,14 +231,17 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
             }
         }
     }
+
     let exception_names: Vec<_> = EXCEPTIONS.iter().map(|(name, _license)| *name).collect();
+    let runtime_ids = compute_runtime_crates(metadata);
+
     // Check if any package does not have a valid license.
     for pkg in &metadata.packages {
         if pkg.source.is_none() {
             // No need to check local packages.
             continue;
         }
-        if exception_names.contains(&pkg.name.as_str()) {
+        if !runtime_ids.contains(&pkg.id) && exception_names.contains(&pkg.name.as_str()) {
             continue;
         }
         let license = match &pkg.license {
@@ -246,6 +253,13 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
             }
         };
         if !LICENSES.contains(&license.as_str()) {
+            if pkg.name == "fortanix-sgx-abi" {
+                // This is a specific exception because SGX is considered
+                // "third party". See
+                // https://github.com/rust-lang/rust/issues/62620 for more. In
+                // general, these should never be added.
+                continue;
+            }
             println!("invalid license `{}` in `{}`", license, pkg.id);
             *bad = true;
         }
@@ -366,10 +380,8 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) {
 
 /// Returns a list of dependencies for the given package.
 fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
-    let node = metadata
-        .resolve
-        .as_ref()
-        .unwrap()
+    let resolve = metadata.resolve.as_ref().unwrap();
+    let node = resolve
         .nodes
         .iter()
         .find(|n| &n.id == pkg_id)
@@ -392,3 +404,42 @@ fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package
     assert!(i.next().is_none(), "more than one package found for `{}`", name);
     result
 }
+
+/// Finds all the packages that are in the rust runtime.
+fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> {
+    let resolve = metadata.resolve.as_ref().unwrap();
+    let mut result = HashSet::new();
+    for name in RUNTIME_CRATES {
+        let id = &pkg_from_name(metadata, name).id;
+        normal_deps_of_r(resolve, id, &mut result);
+    }
+    result
+}
+
+/// Recursively find all normal dependencies.
+fn normal_deps_of_r<'a>(
+    resolve: &'a Resolve,
+    pkg_id: &'a PackageId,
+    result: &mut HashSet<&'a PackageId>,
+) {
+    if !result.insert(pkg_id) {
+        return;
+    }
+    let node = resolve
+        .nodes
+        .iter()
+        .find(|n| &n.id == pkg_id)
+        .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
+    // Don't care about dev-dependencies.
+    // Build dependencies *shouldn't* matter unless they do some kind of
+    // codegen. For now we'll assume they don't.
+    let deps = node.deps.iter().filter(|node_dep| {
+        node_dep
+            .dep_kinds
+            .iter()
+            .any(|kind_info| kind_info.kind == cargo_metadata::DependencyKind::Normal)
+    });
+    for dep in deps {
+        normal_deps_of_r(resolve, &dep.pkg, result);
+    }
+}