]> git.proxmox.com Git - rustc.git/blame - src/tools/tidy/src/deps.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / tidy / src / deps.rs
CommitLineData
ba9703b0 1//! Checks the licenses of third-party dependencies.
476ff2be 2
9c376795
FG
3use cargo_metadata::{DepKindInfo, Metadata, Package, PackageId};
4use std::collections::HashSet;
476ff2be
SL
5use std::path::Path;
6
ba9703b0
XL
7/// These are licenses that are allowed for all crates, including the runtime,
8/// rustc, tools, etc.
b7449926 9const LICENSES: &[&str] = &[
8bb4bdeb
XL
10 "MIT/Apache-2.0",
11 "MIT / Apache-2.0",
12 "Apache-2.0/MIT",
3b2f2976 13 "Apache-2.0 / MIT",
8bb4bdeb 14 "MIT OR Apache-2.0",
416331ca 15 "Apache-2.0 OR MIT",
e1599b0c 16 "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
8bb4bdeb 17 "MIT",
a2a8927a 18 "ISC",
8bb4bdeb 19 "Unlicense/MIT",
8faf50e0 20 "Unlicense OR MIT",
2b03887a
FG
21 "0BSD OR MIT OR Apache-2.0", // adler license
22 "Zlib OR Apache-2.0 OR MIT", // tinyvec
23 "MIT OR Apache-2.0 OR Zlib", // tinyvec_macros
24 "MIT OR Zlib OR Apache-2.0", // miniz_oxide
25 "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident
487cf647 26 "Unicode-DFS-2016", // tinystr and icu4x
8bb4bdeb
XL
27];
28
0531ce1d
XL
29/// These are exceptions to Rust's permissive licensing policy, and
30/// should be considered bugs. Exceptions are only allowed in Rust
31/// tooling. It is _crucial_ that no exception crates be dependencies
9fa01778 32/// of the Rust runtime (std/test).
ba9703b0 33const EXCEPTIONS: &[(&str, &str)] = &[
487cf647
FG
34 ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
35 ("mdbook", "MPL-2.0"), // mdbook
36 ("openssl", "Apache-2.0"), // cargo, mdbook
37 ("colored", "MPL-2.0"), // rustfmt
38 ("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde)
39 ("bytesize", "Apache-2.0"), // cargo
40 ("im-rc", "MPL-2.0+"), // cargo
41 ("sized-chunks", "MPL-2.0+"), // cargo via im-rc
42 ("bitmaps", "MPL-2.0+"), // cargo via im-rc
9c376795
FG
43 ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), // cargo via pasetors
44 ("subtle", "BSD-3-Clause"), // cargo via pasetors
487cf647
FG
45 ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
46 ("snap", "BSD-3-Clause"), // rustc
04454e1e 47 ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations)
487cf647 48 ("self_cell", "Apache-2.0"), // rustc (fluent translations)
416331ca 49 // FIXME: this dependency violates the documentation comment above:
ba9703b0 50 ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
04454e1e
FG
51 ("dunce", "CC0-1.0"), // cargo (dev dependency)
52 ("similar", "Apache-2.0"), // cargo (dev dependency)
53 ("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency)
487cf647 54 ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
0531ce1d
XL
55];
56
17df50a5
XL
57const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
58 ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
59 ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
60 ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
61 ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
9c376795 62 ("cranelift-egraph", "Apache-2.0 WITH LLVM-exception"),
17df50a5
XL
63 ("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
64 ("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
064997fb 65 ("cranelift-isle", "Apache-2.0 WITH LLVM-exception"),
17df50a5
XL
66 ("cranelift-jit", "Apache-2.0 WITH LLVM-exception"),
67 ("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
68 ("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
69 ("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
17df50a5 70 ("mach", "BSD-2-Clause"),
064997fb 71 ("regalloc2", "Apache-2.0 WITH LLVM-exception"),
17df50a5 72 ("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
9c376795 73 ("wasmtime-jit-icache-coherence", "Apache-2.0 WITH LLVM-exception"),
17df50a5
XL
74];
75
064997fb
FG
76const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[
77 ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde
78];
79
ba9703b0
XL
80/// These are the root crates that are part of the runtime. The licenses for
81/// these and all their dependencies *must not* be in the exception list.
82const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"];
83
f035d41b 84/// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
ba9703b0
XL
85///
86/// This list is here to provide a speed-bump to adding a new dependency to
87/// rustc. Please check with the compiler team before adding an entry.
2b03887a 88const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
3dfed10e
XL
89 "addr2line",
90 "adler",
5099ac24 91 "ahash",
ba9703b0
XL
92 "aho-corasick",
93 "annotate-snippets",
94 "ansi_term",
487cf647 95 "ar_archive_writer",
ba9703b0
XL
96 "arrayvec",
97 "atty",
98 "autocfg",
ba9703b0
XL
99 "bitflags",
100 "block-buffer",
ba9703b0
XL
101 "cc",
102 "cfg-if",
f9f354fc 103 "chalk-derive",
17df50a5 104 "chalk-engine",
f9f354fc 105 "chalk-ir",
17df50a5 106 "chalk-solve",
487cf647 107 "convert_case", // dependency of derive_more
ba9703b0 108 "compiler_builtins",
5099ac24 109 "cpufeatures",
ba9703b0 110 "crc32fast",
923072b8 111 "crossbeam-channel",
ba9703b0
XL
112 "crossbeam-deque",
113 "crossbeam-epoch",
ba9703b0 114 "crossbeam-utils",
5099ac24 115 "crypto-common",
6a06907d 116 "cstr",
ba9703b0 117 "datafrog",
487cf647 118 "derive_more",
ba9703b0 119 "digest",
487cf647
FG
120 "displaydoc",
121 "dissimilar",
ba9703b0
XL
122 "dlmalloc",
123 "either",
124 "ena",
3dfed10e 125 "expect-test",
a2a8927a 126 "fallible-iterator", // dependency of `thorin`
487cf647 127 "fastrand",
17df50a5 128 "fixedbitset",
ba9703b0 129 "flate2",
04454e1e
FG
130 "fluent-bundle",
131 "fluent-langneg",
132 "fluent-syntax",
ba9703b0 133 "fortanix-sgx-abi",
ba9703b0
XL
134 "generic-array",
135 "getopts",
136 "getrandom",
3dfed10e 137 "gimli",
fc512014 138 "gsgdt",
ba9703b0
XL
139 "hashbrown",
140 "hermit-abi",
487cf647
FG
141 "icu_list",
142 "icu_locid",
143 "icu_provider",
144 "icu_provider_adapters",
145 "icu_provider_macros",
ba9703b0 146 "indexmap",
3dfed10e 147 "instant",
04454e1e
FG
148 "intl-memoizer",
149 "intl_pluralrules",
ba9703b0 150 "itertools",
17df50a5 151 "itoa",
ba9703b0 152 "jobserver",
ba9703b0
XL
153 "lazy_static",
154 "libc",
a2a8927a 155 "libloading",
ba9703b0 156 "libz-sys",
487cf647 157 "litemap",
ba9703b0
XL
158 "lock_api",
159 "log",
17df50a5 160 "matchers",
ba9703b0
XL
161 "md-5",
162 "measureme",
163 "memchr",
6a06907d 164 "memmap2",
ba9703b0
XL
165 "memoffset",
166 "miniz_oxide",
3c0e092e 167 "num_cpus",
3dfed10e 168 "object",
c295e0f8 169 "odht",
f9f354fc 170 "once_cell",
ba9703b0
XL
171 "parking_lot",
172 "parking_lot_core",
3dfed10e 173 "pathdiff",
6a06907d 174 "perf-event-open-sys",
17df50a5 175 "petgraph",
6a06907d 176 "pin-project-lite",
ba9703b0
XL
177 "pkg-config",
178 "polonius-engine",
179 "ppv-lite86",
04454e1e 180 "proc-macro-hack",
ba9703b0 181 "proc-macro2",
f9f354fc 182 "psm",
ba9703b0 183 "punycode",
ba9703b0
XL
184 "quote",
185 "rand",
186 "rand_chacha",
187 "rand_core",
ba9703b0 188 "rand_xorshift",
c295e0f8 189 "rand_xoshiro",
ba9703b0 190 "redox_syscall",
ba9703b0 191 "regex",
17df50a5 192 "regex-automata",
ba9703b0
XL
193 "regex-syntax",
194 "remove_dir_all",
17df50a5
XL
195 "rls-data",
196 "rls-span",
ba9703b0
XL
197 "rustc-demangle",
198 "rustc-hash",
199 "rustc-rayon",
200 "rustc-rayon-core",
201 "rustc_version",
17df50a5 202 "ryu",
ba9703b0
XL
203 "scoped-tls",
204 "scopeguard",
04454e1e 205 "self_cell",
ba9703b0 206 "semver",
ba9703b0
XL
207 "serde",
208 "serde_derive",
17df50a5 209 "serde_json",
9c376795 210 "sha1",
29967ef6 211 "sha2",
17df50a5 212 "sharded-slab",
3c0e092e 213 "smallvec",
1b1a35ee 214 "snap",
ba9703b0 215 "stable_deref_trait",
f9f354fc 216 "stacker",
9c376795
FG
217 "static_assertions",
218 "subtle", // dependency of cargo (via pasetors)
ba9703b0
XL
219 "syn",
220 "synstructure",
221 "tempfile",
222 "termcolor",
ba9703b0 223 "termize",
04454e1e
FG
224 "thiserror",
225 "thiserror-impl",
a2a8927a 226 "thorin-dwp",
ba9703b0 227 "thread_local",
04454e1e 228 "tinystr",
17df50a5 229 "tinyvec",
2b03887a 230 "tinyvec_macros",
f2b60f7d 231 "thin-vec",
3dfed10e
XL
232 "tracing",
233 "tracing-attributes",
234 "tracing-core",
17df50a5 235 "tracing-log",
17df50a5
XL
236 "tracing-subscriber",
237 "tracing-tree",
9c376795 238 "twox-hash",
04454e1e 239 "type-map",
ba9703b0 240 "typenum",
3c0e092e
XL
241 "unic-char-property",
242 "unic-char-range",
243 "unic-common",
244 "unic-emoji-char",
04454e1e
FG
245 "unic-langid",
246 "unic-langid-impl",
247 "unic-langid-macros",
248 "unic-langid-macros-impl",
3c0e092e 249 "unic-ucd-version",
2b03887a 250 "unicode-ident",
ba9703b0
XL
251 "unicode-normalization",
252 "unicode-script",
253 "unicode-security",
254 "unicode-width",
255 "unicode-xid",
ba9703b0 256 "vcpkg",
f2b60f7d 257 "valuable",
ba9703b0
XL
258 "version_check",
259 "wasi",
260 "winapi",
ba9703b0
XL
261 "winapi-i686-pc-windows-gnu",
262 "winapi-util",
263 "winapi-x86_64-pc-windows-gnu",
487cf647 264 "writeable",
04454e1e
FG
265 // this is a false-positive: it's only used by rustfmt, but because it's enabled through a
266 // feature, tidy thinks it's used by rustc as well.
cdc7bbd5 267 "yansi-term",
487cf647
FG
268 "yoke",
269 "yoke-derive",
270 "zerofrom",
271 "zerofrom-derive",
272 "zerovec",
273 "zerovec-derive",
0531ce1d
XL
274];
275
17df50a5 276const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
064997fb 277 "ahash",
17df50a5 278 "anyhow",
2b03887a 279 "arrayvec",
17df50a5 280 "autocfg",
2b03887a 281 "bumpalo",
17df50a5 282 "bitflags",
064997fb 283 "byteorder",
17df50a5
XL
284 "cfg-if",
285 "cranelift-bforest",
286 "cranelift-codegen",
287 "cranelift-codegen-meta",
288 "cranelift-codegen-shared",
9c376795 289 "cranelift-egraph",
17df50a5
XL
290 "cranelift-entity",
291 "cranelift-frontend",
064997fb 292 "cranelift-isle",
17df50a5
XL
293 "cranelift-jit",
294 "cranelift-module",
295 "cranelift-native",
296 "cranelift-object",
297 "crc32fast",
9c376795 298 "fallible-iterator",
064997fb
FG
299 "fxhash",
300 "getrandom",
17df50a5
XL
301 "gimli",
302 "hashbrown",
303 "indexmap",
304 "libc",
305 "libloading",
306 "log",
307 "mach",
136023e0 308 "memchr",
17df50a5 309 "object",
5e7ed085 310 "once_cell",
064997fb 311 "regalloc2",
17df50a5 312 "region",
064997fb 313 "slice-group-by",
17df50a5 314 "smallvec",
9c376795 315 "stable_deref_trait",
17df50a5 316 "target-lexicon",
064997fb
FG
317 "version_check",
318 "wasi",
9c376795 319 "wasmtime-jit-icache-coherence",
17df50a5
XL
320 "winapi",
321 "winapi-i686-pc-windows-gnu",
322 "winapi-x86_64-pc-windows-gnu",
f2b60f7d
FG
323 "windows-sys",
324 "windows_aarch64_msvc",
325 "windows_i686_gnu",
326 "windows_i686_msvc",
327 "windows_x86_64_gnu",
328 "windows_x86_64_msvc",
17df50a5
XL
329];
330
331const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
2b03887a 332 // This crate takes quite a long time to build, so don't allow two versions of them
17df50a5
XL
333 // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
334 // under control.
335 "cargo",
17df50a5
XL
336];
337
ba9703b0
XL
338/// Dependency checks.
339///
3dfed10e
XL
340/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
341/// to the cargo executable.
342pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
ba9703b0
XL
343 let mut cmd = cargo_metadata::MetadataCommand::new();
344 cmd.cargo_path(cargo)
3dfed10e 345 .manifest_path(root.join("Cargo.toml"))
ba9703b0
XL
346 .features(cargo_metadata::CargoOpt::AllFeatures);
347 let metadata = t!(cmd.exec());
17df50a5 348 let runtime_ids = compute_runtime_crates(&metadata);
2b03887a
FG
349 check_license_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad);
350 check_permitted_dependencies(
064997fb 351 &metadata,
2b03887a
FG
352 "rustc",
353 PERMITTED_RUSTC_DEPENDENCIES,
354 &["rustc_driver", "rustc_codegen_llvm"],
064997fb
FG
355 bad,
356 );
17df50a5 357 check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad);
136023e0 358 check_rustfix(&metadata, bad);
17df50a5
XL
359
360 // Check rustc_codegen_cranelift independently as it has it's own workspace.
361 let mut cmd = cargo_metadata::MetadataCommand::new();
362 cmd.cargo_path(cargo)
363 .manifest_path(root.join("compiler/rustc_codegen_cranelift/Cargo.toml"))
364 .features(cargo_metadata::CargoOpt::AllFeatures);
365 let metadata = t!(cmd.exec());
366 let runtime_ids = HashSet::new();
2b03887a
FG
367 check_license_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad);
368 check_permitted_dependencies(
17df50a5 369 &metadata,
064997fb 370 "cranelift",
17df50a5
XL
371 PERMITTED_CRANELIFT_DEPENDENCIES,
372 &["rustc_codegen_cranelift"],
373 bad,
374 );
375 check_crate_duplicate(&metadata, &[], bad);
064997fb
FG
376
377 let mut cmd = cargo_metadata::MetadataCommand::new();
378 cmd.cargo_path(cargo)
379 .manifest_path(root.join("src/bootstrap/Cargo.toml"))
380 .features(cargo_metadata::CargoOpt::AllFeatures);
381 let metadata = t!(cmd.exec());
382 let runtime_ids = HashSet::new();
2b03887a 383 check_license_exceptions(&metadata, EXCEPTIONS_BOOTSTRAP, runtime_ids, bad);
0531ce1d
XL
384}
385
ba9703b0
XL
386/// Check that all licenses are in the valid list in `LICENSES`.
387///
2b03887a
FG
388/// Packages listed in `exceptions` are allowed for tools.
389fn check_license_exceptions(
17df50a5
XL
390 metadata: &Metadata,
391 exceptions: &[(&str, &str)],
392 runtime_ids: HashSet<&PackageId>,
393 bad: &mut bool,
394) {
ba9703b0 395 // Validate the EXCEPTIONS list hasn't changed.
17df50a5 396 for (name, license) in exceptions {
ba9703b0
XL
397 // Check that the package actually exists.
398 if !metadata.packages.iter().any(|p| p.name == *name) {
fc512014
XL
399 tidy_error!(
400 bad,
ba9703b0
XL
401 "could not find exception package `{}`\n\
402 Remove from EXCEPTIONS list if it is no longer used.",
403 name
404 );
ba9703b0
XL
405 }
406 // Check that the license hasn't changed.
407 for pkg in metadata.packages.iter().filter(|p| p.name == *name) {
ba9703b0
XL
408 match &pkg.license {
409 None => {
fc512014
XL
410 tidy_error!(
411 bad,
ba9703b0
XL
412 "dependency exception `{}` does not declare a license expression",
413 pkg.id
414 );
ba9703b0
XL
415 }
416 Some(pkg_license) => {
417 if pkg_license.as_str() != *license {
5e7ed085
FG
418 println!("dependency exception `{name}` license has changed");
419 println!(" previously `{license}` now `{pkg_license}`");
ba9703b0
XL
420 println!(" update EXCEPTIONS for the new license");
421 *bad = true;
422 }
423 }
424 }
425 }
0531ce1d 426 }
0531ce1d 427
17df50a5 428 let exception_names: Vec<_> = exceptions.iter().map(|(name, _license)| *name).collect();
8bb4bdeb 429
ba9703b0
XL
430 // Check if any package does not have a valid license.
431 for pkg in &metadata.packages {
432 if pkg.source.is_none() {
433 // No need to check local packages.
0531ce1d 434 continue;
8bb4bdeb 435 }
ba9703b0
XL
436 if !runtime_ids.contains(&pkg.id) && exception_names.contains(&pkg.name.as_str()) {
437 continue;
438 }
439 let license = match &pkg.license {
440 Some(license) => license,
441 None => {
fc512014 442 tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id);
ba9703b0
XL
443 continue;
444 }
445 };
446 if !LICENSES.contains(&license.as_str()) {
447 if pkg.name == "fortanix-sgx-abi" {
448 // This is a specific exception because SGX is considered
449 // "third party". See
450 // https://github.com/rust-lang/rust/issues/62620 for more. In
451 // general, these should never be added.
452 continue;
453 }
fc512014 454 tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id);
ba9703b0 455 }
476ff2be 456 }
476ff2be
SL
457}
458
2b03887a 459/// Checks the dependency of `restricted_dependency_crates` at the given path. Changes `bad` to
f035d41b 460/// `true` if a check failed.
0531ce1d 461///
2b03887a
FG
462/// Specifically, this checks that the dependencies are on the `permitted_dependencies`.
463fn check_permitted_dependencies(
17df50a5 464 metadata: &Metadata,
064997fb 465 descr: &str,
17df50a5
XL
466 permitted_dependencies: &[&'static str],
467 restricted_dependency_crates: &[&'static str],
468 bad: &mut bool,
469) {
9c376795
FG
470 let mut deps = HashSet::new();
471 for to_check in restricted_dependency_crates {
472 let to_check = pkg_from_name(metadata, to_check);
473 use cargo_platform::Cfg;
474 use std::str::FromStr;
475 // We don't expect the compiler to ever run on wasm32, so strip
476 // out those dependencies to avoid polluting the permitted list.
477 deps_of_filtered(metadata, &to_check.id, &mut deps, &|dep_kinds| {
478 dep_kinds.iter().any(|dep_kind| {
479 dep_kind
480 .target
481 .as_ref()
482 .map(|target| {
483 !target.matches(
484 "wasm32-unknown-unknown",
485 &[
486 Cfg::from_str("target_arch=\"wasm32\"").unwrap(),
487 Cfg::from_str("target_os=\"unknown\"").unwrap(),
488 ],
489 )
490 })
491 .unwrap_or(true)
492 })
493 });
494 }
495
f035d41b 496 // Check that the PERMITTED_DEPENDENCIES does not have unused entries.
9c376795
FG
497 for permitted in permitted_dependencies {
498 if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) {
fc512014
XL
499 tidy_error!(
500 bad,
9c376795 501 "could not find allowed package `{permitted}`\n\
f035d41b 502 Remove from PERMITTED_DEPENDENCIES list if it is no longer used.",
ba9703b0 503 );
ba9703b0
XL
504 }
505 }
0531ce1d 506
9c376795
FG
507 // Get in a convenient form.
508 let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
0531ce1d 509
9c376795
FG
510 for dep in deps {
511 let dep = pkg_from_id(metadata, dep);
512 // If this path is in-tree, we don't require it to be explicitly permitted.
513 if dep.source.is_some() {
514 if !permitted_dependencies.contains(dep.name.as_str()) {
515 tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
516 }
0531ce1d 517 }
0531ce1d 518 }
0531ce1d
XL
519}
520
ba9703b0 521/// Prevents multiple versions of some expensive crates.
17df50a5
XL
522fn check_crate_duplicate(
523 metadata: &Metadata,
524 forbidden_to_have_duplicates: &[&str],
525 bad: &mut bool,
526) {
527 for &name in forbidden_to_have_duplicates {
ba9703b0
XL
528 let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect();
529 match matches.len() {
530 0 => {
fc512014
XL
531 tidy_error!(
532 bad,
ba9703b0
XL
533 "crate `{}` is missing, update `check_crate_duplicate` \
534 if it is no longer used",
535 name
536 );
ba9703b0
XL
537 }
538 1 => {}
539 _ => {
fc512014
XL
540 tidy_error!(
541 bad,
ba9703b0
XL
542 "crate `{}` is duplicated in `Cargo.lock`, \
543 it is too expensive to build multiple times, \
544 so make sure only one version appears across all dependencies",
545 name
546 );
547 for pkg in matches {
548 println!(" * {}", pkg.id);
549 }
ba9703b0 550 }
b7449926 551 }
ba9703b0
XL
552 }
553}
554
ba9703b0
XL
555/// Finds a package with the given name.
556fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
557 let mut i = metadata.packages.iter().filter(|p| p.name == name);
558 let result =
5e7ed085
FG
559 i.next().unwrap_or_else(|| panic!("could not find package `{name}` in package list"));
560 assert!(i.next().is_none(), "more than one package found for `{name}`");
ba9703b0
XL
561 result
562}
563
9c376795
FG
564fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package {
565 metadata.packages.iter().find(|p| &p.id == id).unwrap()
566}
567
ba9703b0
XL
568/// Finds all the packages that are in the rust runtime.
569fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> {
ba9703b0
XL
570 let mut result = HashSet::new();
571 for name in RUNTIME_CRATES {
572 let id = &pkg_from_name(metadata, name).id;
9c376795 573 deps_of_filtered(metadata, id, &mut result, &|_| true);
ba9703b0
XL
574 }
575 result
576}
577
9c376795
FG
578/// Recursively find all dependencies.
579fn deps_of_filtered<'a>(
580 metadata: &'a Metadata,
ba9703b0
XL
581 pkg_id: &'a PackageId,
582 result: &mut HashSet<&'a PackageId>,
9c376795 583 filter: &dyn Fn(&[DepKindInfo]) -> bool,
ba9703b0
XL
584) {
585 if !result.insert(pkg_id) {
586 return;
587 }
9c376795
FG
588 let node = metadata
589 .resolve
590 .as_ref()
591 .unwrap()
ba9703b0
XL
592 .nodes
593 .iter()
594 .find(|n| &n.id == pkg_id)
5e7ed085 595 .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
17df50a5 596 for dep in &node.deps {
9c376795
FG
597 if !filter(&dep.dep_kinds) {
598 continue;
599 }
600 deps_of_filtered(metadata, &dep.pkg, result, filter);
b7449926
XL
601 }
602}
136023e0 603
9c376795
FG
604fn direct_deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
605 let resolve = metadata.resolve.as_ref().unwrap();
606 let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap();
607 node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)).collect()
608}
609
136023e0
XL
610fn check_rustfix(metadata: &Metadata, bad: &mut bool) {
611 let cargo = pkg_from_name(metadata, "cargo");
612 let compiletest = pkg_from_name(metadata, "compiletest");
9c376795
FG
613 let cargo_deps = direct_deps_of(metadata, &cargo.id);
614 let compiletest_deps = direct_deps_of(metadata, &compiletest.id);
136023e0
XL
615 let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap();
616 let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap();
617 if cargo_rustfix.version != compiletest_rustfix.version {
618 tidy_error!(
619 bad,
620 "cargo's rustfix version {} does not match compiletest's rustfix version {}\n\
621 rustfix should be kept in sync, update the cargo side first, and then update \
622 compiletest along with cargo.",
623 cargo_rustfix.version,
624 compiletest_rustfix.version
625 );
626 }
627}