1
1
//! Checks the licenses of third-party dependencies.
2
2
3
- use cargo_metadata:: { Metadata , Package , PackageId } ;
3
+ use cargo_metadata:: { Metadata , Package , PackageId , Resolve } ;
4
4
use std:: collections:: { BTreeSet , HashSet } ;
5
5
use std:: path:: Path ;
6
6
@@ -50,6 +50,10 @@ const EXCEPTIONS: &[(&str, &str)] = &[
50
50
( "crossbeam-channel" , "MIT/Apache-2.0 AND BSD-2-Clause" ) , // cargo
51
51
] ;
52
52
53
+ /// These are the root crates that are part of the runtime. The licenses for
54
+ /// these and all their dependencies *must not* be in the exception list.
55
+ const RUNTIME_CRATES : & [ & str ] = & [ "std" , "core" , "alloc" , "panic_abort" , "panic_unwind" ] ;
56
+
53
57
/// Which crates to check against the whitelist?
54
58
const WHITELIST_CRATES : & [ & str ] = & [ "rustc" , "rustc_codegen_llvm" ] ;
55
59
@@ -227,14 +231,17 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
227
231
}
228
232
}
229
233
}
234
+
230
235
let exception_names: Vec < _ > = EXCEPTIONS . iter ( ) . map ( |( name, _license) | * name) . collect ( ) ;
236
+ let runtime_ids = compute_runtime_crates ( metadata) ;
237
+
231
238
// Check if any package does not have a valid license.
232
239
for pkg in & metadata. packages {
233
240
if pkg. source . is_none ( ) {
234
241
// No need to check local packages.
235
242
continue ;
236
243
}
237
- if exception_names. contains ( & pkg. name . as_str ( ) ) {
244
+ if !runtime_ids . contains ( & pkg . id ) && exception_names. contains ( & pkg. name . as_str ( ) ) {
238
245
continue ;
239
246
}
240
247
let license = match & pkg. license {
@@ -246,6 +253,13 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
246
253
}
247
254
} ;
248
255
if !LICENSES . contains ( & license. as_str ( ) ) {
256
+ if pkg. name == "fortanix-sgx-abi" {
257
+ // This is a specific exception because SGX is considered
258
+ // "third party". See
259
+ // https://github.com/rust-lang/rust/issues/62620 for more. In
260
+ // general, these should never be added.
261
+ continue ;
262
+ }
249
263
println ! ( "invalid license `{}` in `{}`" , license, pkg. id) ;
250
264
* bad = true ;
251
265
}
@@ -366,10 +380,8 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) {
366
380
367
381
/// Returns a list of dependencies for the given package.
368
382
fn deps_of < ' a > ( metadata : & ' a Metadata , pkg_id : & ' a PackageId ) -> Vec < & ' a Package > {
369
- let node = metadata
370
- . resolve
371
- . as_ref ( )
372
- . unwrap ( )
383
+ let resolve = metadata. resolve . as_ref ( ) . unwrap ( ) ;
384
+ let node = resolve
373
385
. nodes
374
386
. iter ( )
375
387
. find ( |n| & n. id == pkg_id)
@@ -392,3 +404,42 @@ fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package
392
404
assert ! ( i. next( ) . is_none( ) , "more than one package found for `{}`" , name) ;
393
405
result
394
406
}
407
+
408
+ /// Finds all the packages that are in the rust runtime.
409
+ fn compute_runtime_crates < ' a > ( metadata : & ' a Metadata ) -> HashSet < & ' a PackageId > {
410
+ let resolve = metadata. resolve . as_ref ( ) . unwrap ( ) ;
411
+ let mut result = HashSet :: new ( ) ;
412
+ for name in RUNTIME_CRATES {
413
+ let id = & pkg_from_name ( metadata, name) . id ;
414
+ normal_deps_of_r ( resolve, id, & mut result) ;
415
+ }
416
+ result
417
+ }
418
+
419
+ /// Recursively find all normal dependencies.
420
+ fn normal_deps_of_r < ' a > (
421
+ resolve : & ' a Resolve ,
422
+ pkg_id : & ' a PackageId ,
423
+ result : & mut HashSet < & ' a PackageId > ,
424
+ ) {
425
+ if !result. insert ( pkg_id) {
426
+ return ;
427
+ }
428
+ let node = resolve
429
+ . nodes
430
+ . iter ( )
431
+ . find ( |n| & n. id == pkg_id)
432
+ . unwrap_or_else ( || panic ! ( "could not find `{}` in resolve" , pkg_id) ) ;
433
+ // Don't care about dev-dependencies.
434
+ // Build dependencies *shouldn't* matter unless they do some kind of
435
+ // codegen. For now we'll assume they don't.
436
+ let deps = node. deps . iter ( ) . filter ( |node_dep| {
437
+ node_dep
438
+ . dep_kinds
439
+ . iter ( )
440
+ . any ( |kind_info| kind_info. kind == cargo_metadata:: DependencyKind :: Normal )
441
+ } ) ;
442
+ for dep in deps {
443
+ normal_deps_of_r ( resolve, & dep. pkg , result) ;
444
+ }
445
+ }
0 commit comments