]>
Commit | Line | Data |
---|---|---|
ba9703b0 | 1 | //! Checks the licenses of third-party dependencies. |
476ff2be | 2 | |
e8be2606 | 3 | use cargo_metadata::{Metadata, Package, PackageId}; |
9c376795 | 4 | use std::collections::HashSet; |
476ff2be SL |
5 | use std::path::Path; |
6 | ||
ba9703b0 XL |
7 | /// These are licenses that are allowed for all crates, including the runtime, |
8 | /// rustc, tools, etc. | |
49aad941 | 9 | #[rustfmt::skip] |
b7449926 | 10 | const LICENSES: &[&str] = &[ |
49aad941 FG |
11 | // tidy-alphabetical-start |
12 | "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident | |
13 | "0BSD OR MIT OR Apache-2.0", // adler license | |
14 | "0BSD", | |
3b2f2976 | 15 | "Apache-2.0 / MIT", |
c620b35d | 16 | "Apache-2.0 OR ISC OR MIT", |
416331ca | 17 | "Apache-2.0 OR MIT", |
e1599b0c | 18 | "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license |
c620b35d | 19 | "Apache-2.0", |
49aad941 | 20 | "Apache-2.0/MIT", |
4b012472 | 21 | "BSD-2-Clause OR Apache-2.0 OR MIT", // zerocopy |
a2a8927a | 22 | "ISC", |
49aad941 | 23 | "MIT / Apache-2.0", |
781aab86 | 24 | "MIT OR Apache-2.0 OR LGPL-2.1-or-later", // r-efi, r-efi-alloc |
49aad941 FG |
25 | "MIT OR Apache-2.0 OR Zlib", // tinyvec_macros |
26 | "MIT OR Apache-2.0", | |
27 | "MIT OR Zlib OR Apache-2.0", // miniz_oxide | |
28 | "MIT", | |
29 | "MIT/Apache-2.0", | |
30 | "Unicode-DFS-2016", // tinystr and icu4x | |
8faf50e0 | 31 | "Unlicense OR MIT", |
49aad941 FG |
32 | "Unlicense/MIT", |
33 | "Zlib OR Apache-2.0 OR MIT", // tinyvec | |
34 | // tidy-alphabetical-end | |
8bb4bdeb XL |
35 | ]; |
36 | ||
ed00b5ec FG |
37 | type ExceptionList = &'static [(&'static str, &'static str)]; |
38 | ||
39 | /// The workspaces to check for licensing and optionally permitted dependencies. | |
40 | /// | |
41 | /// Each entry consists of a tuple with the following elements: | |
42 | /// | |
43 | /// * The path to the workspace root Cargo.toml file. | |
44 | /// * The list of license exceptions. | |
45 | /// * Optionally a tuple of: | |
46 | /// * A list of crates for which dependencies need to be explicitly allowed. | |
47 | /// * The list of allowed dependencies. | |
48 | // FIXME auto detect all cargo workspaces | |
49 | pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>)] = &[ | |
50 | // The root workspace has to be first for check_rustfix to work. | |
51 | (".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES))), | |
52 | // Outside of the alphabetical section because rustfmt formats it using multiple lines. | |
53 | ( | |
54 | "compiler/rustc_codegen_cranelift", | |
55 | EXCEPTIONS_CRANELIFT, | |
56 | Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)), | |
57 | ), | |
58 | // tidy-alphabetical-start | |
e8be2606 | 59 | ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), |
ed00b5ec FG |
60 | //("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo |
61 | //("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo | |
62 | //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo | |
63 | ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None), | |
64 | ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None), | |
65 | //("src/etc/test-float-parse", &[], None), // FIXME uncomment once all deps are vendored | |
66 | ("src/tools/cargo", EXCEPTIONS_CARGO, None), | |
67 | //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored | |
68 | //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored | |
69 | ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None), | |
70 | ("src/tools/x", &[], None), | |
71 | // tidy-alphabetical-end | |
72 | ]; | |
73 | ||
0531ce1d XL |
74 | /// These are exceptions to Rust's permissive licensing policy, and |
75 | /// should be considered bugs. Exceptions are only allowed in Rust | |
76 | /// tooling. It is _crucial_ that no exception crates be dependencies | |
9fa01778 | 77 | /// of the Rust runtime (std/test). |
49aad941 | 78 | #[rustfmt::skip] |
ed00b5ec | 79 | const EXCEPTIONS: ExceptionList = &[ |
49aad941 | 80 | // tidy-alphabetical-start |
487cf647 | 81 | ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc |
487cf647 | 82 | ("colored", "MPL-2.0"), // rustfmt |
49aad941 FG |
83 | ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) |
84 | ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) | |
85 | ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above. | |
86 | ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot | |
87 | ("mdbook", "MPL-2.0"), // mdbook | |
ed00b5ec | 88 | ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`) |
add651ee | 89 | ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), // rustc (license is the same as LLVM uses) |
ed00b5ec | 90 | ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 // cargo/... (because of serde) |
49aad941 FG |
91 | ("self_cell", "Apache-2.0"), // rustc (fluent translations) |
92 | ("snap", "BSD-3-Clause"), // rustc | |
c620b35d FG |
93 | ("wasm-encoder", "Apache-2.0 WITH LLVM-exception"), // rustc |
94 | ("wasmparser", "Apache-2.0 WITH LLVM-exception"), // rustc | |
49aad941 FG |
95 | // tidy-alphabetical-end |
96 | ]; | |
97 | ||
ed00b5ec FG |
98 | // FIXME uncomment once rust-lang/stdarch#1462 lands |
99 | /* | |
100 | const EXCEPTIONS_STDARCH: ExceptionList = &[ | |
101 | // tidy-alphabetical-start | |
102 | ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 | |
103 | ("wasmparser", "Apache-2.0 WITH LLVM-exception"), | |
104 | ("wasmprinter", "Apache-2.0 WITH LLVM-exception"), | |
105 | // tidy-alphabetical-end | |
106 | ]; | |
107 | */ | |
108 | ||
109 | const EXCEPTIONS_CARGO: ExceptionList = &[ | |
49aad941 FG |
110 | // tidy-alphabetical-start |
111 | ("bitmaps", "MPL-2.0+"), | |
112 | ("bytesize", "Apache-2.0"), | |
add651ee FG |
113 | ("ciborium", "Apache-2.0"), |
114 | ("ciborium-io", "Apache-2.0"), | |
115 | ("ciborium-ll", "Apache-2.0"), | |
fe692bf9 | 116 | ("dunce", "CC0-1.0 OR MIT-0 OR Apache-2.0"), |
781aab86 | 117 | ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"), |
49aad941 FG |
118 | ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), |
119 | ("im-rc", "MPL-2.0+"), | |
49aad941 FG |
120 | ("normalize-line-endings", "Apache-2.0"), |
121 | ("openssl", "Apache-2.0"), | |
ed00b5ec | 122 | ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 |
49aad941 FG |
123 | ("sha1_smol", "BSD-3-Clause"), |
124 | ("similar", "Apache-2.0"), | |
125 | ("sized-chunks", "MPL-2.0+"), | |
126 | ("subtle", "BSD-3-Clause"), | |
ed00b5ec | 127 | ("supports-hyperlinks", "Apache-2.0"), |
49aad941 FG |
128 | ("unicode-bom", "Apache-2.0"), |
129 | // tidy-alphabetical-end | |
0531ce1d XL |
130 | ]; |
131 | ||
ed00b5ec FG |
132 | const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[ |
133 | // tidy-alphabetical-start | |
ed00b5ec | 134 | ("dissimilar", "Apache-2.0"), |
ed00b5ec | 135 | ("notify", "CC0-1.0"), |
31ef2f64 | 136 | ("option-ext", "MPL-2.0"), |
ed00b5ec | 137 | ("pulldown-cmark-to-cmark", "Apache-2.0"), |
c0240ec0 | 138 | ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), |
ed00b5ec FG |
139 | ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 |
140 | ("scip", "Apache-2.0"), | |
141 | ("snap", "BSD-3-Clause"), | |
142 | // tidy-alphabetical-end | |
143 | ]; | |
144 | ||
145 | const EXCEPTIONS_CRANELIFT: ExceptionList = &[ | |
49aad941 | 146 | // tidy-alphabetical-start |
17df50a5 XL |
147 | ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"), |
148 | ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"), | |
149 | ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"), | |
150 | ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"), | |
fe692bf9 | 151 | ("cranelift-control", "Apache-2.0 WITH LLVM-exception"), |
17df50a5 XL |
152 | ("cranelift-entity", "Apache-2.0 WITH LLVM-exception"), |
153 | ("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"), | |
064997fb | 154 | ("cranelift-isle", "Apache-2.0 WITH LLVM-exception"), |
17df50a5 XL |
155 | ("cranelift-jit", "Apache-2.0 WITH LLVM-exception"), |
156 | ("cranelift-module", "Apache-2.0 WITH LLVM-exception"), | |
157 | ("cranelift-native", "Apache-2.0 WITH LLVM-exception"), | |
158 | ("cranelift-object", "Apache-2.0 WITH LLVM-exception"), | |
17df50a5 | 159 | ("mach", "BSD-2-Clause"), |
064997fb | 160 | ("regalloc2", "Apache-2.0 WITH LLVM-exception"), |
17df50a5 | 161 | ("target-lexicon", "Apache-2.0 WITH LLVM-exception"), |
9c376795 | 162 | ("wasmtime-jit-icache-coherence", "Apache-2.0 WITH LLVM-exception"), |
49aad941 | 163 | // tidy-alphabetical-end |
17df50a5 XL |
164 | ]; |
165 | ||
ed00b5ec FG |
166 | const EXCEPTIONS_GCC: ExceptionList = &[ |
167 | // tidy-alphabetical-start | |
168 | ("gccjit", "GPL-3.0"), | |
169 | ("gccjit_sys", "GPL-3.0"), | |
170 | // tidy-alphabetical-end | |
171 | ]; | |
ed00b5ec FG |
172 | |
173 | const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[ | |
174 | ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde. BSL is not acceptble, but we use it under Apache-2.0 | |
175 | ]; | |
176 | ||
177 | const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[ | |
178 | ("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptible, but we use it under MIT OR Apache-2.0 | |
064997fb FG |
179 | ]; |
180 | ||
ba9703b0 XL |
181 | /// These are the root crates that are part of the runtime. The licenses for |
182 | /// these and all their dependencies *must not* be in the exception list. | |
183 | const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; | |
184 | ||
fe692bf9 FG |
185 | const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!()); |
186 | ||
f035d41b | 187 | /// Crates rustc is allowed to depend on. Avoid adding to the list if possible. |
ba9703b0 XL |
188 | /// |
189 | /// This list is here to provide a speed-bump to adding a new dependency to | |
190 | /// rustc. Please check with the compiler team before adding an entry. | |
2b03887a | 191 | const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ |
49aad941 | 192 | // tidy-alphabetical-start |
e8be2606 | 193 | "addr2line", |
3dfed10e | 194 | "adler", |
5099ac24 | 195 | "ahash", |
ba9703b0 | 196 | "aho-corasick", |
fe692bf9 | 197 | "allocator-api2", // FIXME: only appears in Cargo.lock due to https://github.com/rust-lang/cargo/issues/10801 |
ba9703b0 | 198 | "annotate-snippets", |
c0240ec0 | 199 | "anstyle", |
487cf647 | 200 | "ar_archive_writer", |
ba9703b0 | 201 | "arrayvec", |
ba9703b0 | 202 | "autocfg", |
ba9703b0 XL |
203 | "bitflags", |
204 | "block-buffer", | |
49aad941 | 205 | "byteorder", // via ruzstd in object in thorin-dwp |
ba9703b0 XL |
206 | "cc", |
207 | "cfg-if", | |
e8be2606 | 208 | "cfg_aliases", |
ba9703b0 | 209 | "compiler_builtins", |
5099ac24 | 210 | "cpufeatures", |
ba9703b0 | 211 | "crc32fast", |
923072b8 | 212 | "crossbeam-channel", |
ba9703b0 XL |
213 | "crossbeam-deque", |
214 | "crossbeam-epoch", | |
ba9703b0 | 215 | "crossbeam-utils", |
5099ac24 | 216 | "crypto-common", |
e8be2606 | 217 | "ctrlc", |
add651ee FG |
218 | "darling", |
219 | "darling_core", | |
220 | "darling_macro", | |
ba9703b0 | 221 | "datafrog", |
c620b35d | 222 | "deranged", |
ed00b5ec | 223 | "derivative", |
487cf647 | 224 | "derive_more", |
add651ee | 225 | "derive_setters", |
ba9703b0 | 226 | "digest", |
487cf647 FG |
227 | "displaydoc", |
228 | "dissimilar", | |
ba9703b0 XL |
229 | "dlmalloc", |
230 | "either", | |
9ffffee4 | 231 | "elsa", |
ba9703b0 | 232 | "ena", |
fe692bf9 | 233 | "equivalent", |
add651ee | 234 | "errno", |
3dfed10e | 235 | "expect-test", |
a2a8927a | 236 | "fallible-iterator", // dependency of `thorin` |
487cf647 | 237 | "fastrand", |
49aad941 | 238 | "field-offset", |
ba9703b0 | 239 | "flate2", |
04454e1e FG |
240 | "fluent-bundle", |
241 | "fluent-langneg", | |
242 | "fluent-syntax", | |
add651ee | 243 | "fnv", |
ba9703b0 | 244 | "fortanix-sgx-abi", |
ba9703b0 XL |
245 | "generic-array", |
246 | "getopts", | |
247 | "getrandom", | |
3dfed10e | 248 | "gimli", |
fc512014 | 249 | "gsgdt", |
ba9703b0 XL |
250 | "hashbrown", |
251 | "hermit-abi", | |
487cf647 | 252 | "icu_list", |
ed00b5ec | 253 | "icu_list_data", |
487cf647 | 254 | "icu_locid", |
ed00b5ec FG |
255 | "icu_locid_transform", |
256 | "icu_locid_transform_data", | |
487cf647 FG |
257 | "icu_provider", |
258 | "icu_provider_adapters", | |
259 | "icu_provider_macros", | |
add651ee | 260 | "ident_case", |
ba9703b0 | 261 | "indexmap", |
04454e1e FG |
262 | "intl-memoizer", |
263 | "intl_pluralrules", | |
ba9703b0 | 264 | "itertools", |
17df50a5 | 265 | "itoa", |
ed00b5ec | 266 | "jemalloc-sys", |
ba9703b0 | 267 | "jobserver", |
ba9703b0 | 268 | "lazy_static", |
c620b35d | 269 | "leb128", |
ba9703b0 | 270 | "libc", |
a2a8927a | 271 | "libloading", |
fe692bf9 | 272 | "linux-raw-sys", |
487cf647 | 273 | "litemap", |
ba9703b0 XL |
274 | "lock_api", |
275 | "log", | |
17df50a5 | 276 | "matchers", |
ba9703b0 XL |
277 | "md-5", |
278 | "measureme", | |
279 | "memchr", | |
6a06907d | 280 | "memmap2", |
ba9703b0 XL |
281 | "memoffset", |
282 | "miniz_oxide", | |
e8be2606 | 283 | "nix", |
fe692bf9 | 284 | "nu-ansi-term", |
c620b35d | 285 | "num-conv", |
3c0e092e | 286 | "num_cpus", |
3dfed10e | 287 | "object", |
c295e0f8 | 288 | "odht", |
f9f354fc | 289 | "once_cell", |
fe692bf9 | 290 | "overload", |
ba9703b0 XL |
291 | "parking_lot", |
292 | "parking_lot_core", | |
3dfed10e | 293 | "pathdiff", |
6a06907d XL |
294 | "perf-event-open-sys", |
295 | "pin-project-lite", | |
ba9703b0 | 296 | "polonius-engine", |
ed00b5ec | 297 | "portable-atomic", // dependency for platforms doesn't support `AtomicU64` in std |
c620b35d | 298 | "powerfmt", |
ba9703b0 | 299 | "ppv-lite86", |
04454e1e | 300 | "proc-macro-hack", |
ba9703b0 | 301 | "proc-macro2", |
f9f354fc | 302 | "psm", |
49aad941 | 303 | "pulldown-cmark", |
ba9703b0 | 304 | "punycode", |
ba9703b0 | 305 | "quote", |
781aab86 FG |
306 | "r-efi", |
307 | "r-efi-alloc", | |
ba9703b0 XL |
308 | "rand", |
309 | "rand_chacha", | |
310 | "rand_core", | |
ba9703b0 | 311 | "rand_xorshift", |
c295e0f8 | 312 | "rand_xoshiro", |
ba9703b0 | 313 | "redox_syscall", |
ba9703b0 | 314 | "regex", |
17df50a5 | 315 | "regex-automata", |
ba9703b0 | 316 | "regex-syntax", |
ba9703b0 XL |
317 | "rustc-demangle", |
318 | "rustc-hash", | |
319 | "rustc-rayon", | |
320 | "rustc-rayon-core", | |
add651ee | 321 | "rustc_apfloat", |
ba9703b0 | 322 | "rustc_version", |
fe692bf9 | 323 | "rustix", |
49aad941 | 324 | "ruzstd", // via object in thorin-dwp |
17df50a5 | 325 | "ryu", |
ba9703b0 XL |
326 | "scoped-tls", |
327 | "scopeguard", | |
04454e1e | 328 | "self_cell", |
ba9703b0 | 329 | "semver", |
ba9703b0 XL |
330 | "serde", |
331 | "serde_derive", | |
17df50a5 | 332 | "serde_json", |
9c376795 | 333 | "sha1", |
29967ef6 | 334 | "sha2", |
17df50a5 | 335 | "sharded-slab", |
c0240ec0 | 336 | "shlex", |
3c0e092e | 337 | "smallvec", |
1b1a35ee | 338 | "snap", |
ba9703b0 | 339 | "stable_deref_trait", |
f9f354fc | 340 | "stacker", |
9c376795 | 341 | "static_assertions", |
add651ee | 342 | "strsim", |
ba9703b0 XL |
343 | "syn", |
344 | "synstructure", | |
345 | "tempfile", | |
346 | "termcolor", | |
ba9703b0 | 347 | "termize", |
49aad941 | 348 | "thin-vec", |
04454e1e FG |
349 | "thiserror", |
350 | "thiserror-impl", | |
a2a8927a | 351 | "thorin-dwp", |
ba9703b0 | 352 | "thread_local", |
add651ee FG |
353 | "time", |
354 | "time-core", | |
355 | "time-macros", | |
04454e1e | 356 | "tinystr", |
17df50a5 | 357 | "tinyvec", |
2b03887a | 358 | "tinyvec_macros", |
3dfed10e XL |
359 | "tracing", |
360 | "tracing-attributes", | |
361 | "tracing-core", | |
17df50a5 | 362 | "tracing-log", |
17df50a5 XL |
363 | "tracing-subscriber", |
364 | "tracing-tree", | |
9c376795 | 365 | "twox-hash", |
04454e1e | 366 | "type-map", |
ba9703b0 | 367 | "typenum", |
04454e1e FG |
368 | "unic-langid", |
369 | "unic-langid-impl", | |
370 | "unic-langid-macros", | |
371 | "unic-langid-macros-impl", | |
9ffffee4 | 372 | "unicase", |
2b03887a | 373 | "unicode-ident", |
ba9703b0 | 374 | "unicode-normalization", |
add651ee | 375 | "unicode-properties", |
ba9703b0 XL |
376 | "unicode-script", |
377 | "unicode-security", | |
378 | "unicode-width", | |
379 | "unicode-xid", | |
4b012472 | 380 | "unwinding", |
f2b60f7d | 381 | "valuable", |
ba9703b0 XL |
382 | "version_check", |
383 | "wasi", | |
c620b35d FG |
384 | "wasm-encoder", |
385 | "wasmparser", | |
ba9703b0 | 386 | "winapi", |
ba9703b0 XL |
387 | "winapi-i686-pc-windows-gnu", |
388 | "winapi-util", | |
389 | "winapi-x86_64-pc-windows-gnu", | |
49aad941 | 390 | "windows", |
c620b35d | 391 | "windows-core", |
fe692bf9 | 392 | "windows-sys", |
49aad941 FG |
393 | "windows-targets", |
394 | "windows_aarch64_gnullvm", | |
395 | "windows_aarch64_msvc", | |
396 | "windows_i686_gnu", | |
31ef2f64 | 397 | "windows_i686_gnullvm", |
49aad941 FG |
398 | "windows_i686_msvc", |
399 | "windows_x86_64_gnu", | |
400 | "windows_x86_64_gnullvm", | |
401 | "windows_x86_64_msvc", | |
487cf647 | 402 | "writeable", |
487cf647 FG |
403 | "yoke", |
404 | "yoke-derive", | |
4b012472 FG |
405 | "zerocopy", |
406 | "zerocopy-derive", | |
487cf647 FG |
407 | "zerofrom", |
408 | "zerofrom-derive", | |
409 | "zerovec", | |
410 | "zerovec-derive", | |
49aad941 | 411 | // tidy-alphabetical-end |
0531ce1d XL |
412 | ]; |
413 | ||
ed00b5ec FG |
414 | // These crates come from ICU4X and are licensed under the unicode license. |
415 | // It currently doesn't have an SPDX identifier, so they cannot put one there. | |
416 | // See https://github.com/unicode-org/icu4x/pull/3875 | |
417 | // FIXME: This should be removed once ICU4X crates update. | |
418 | const ICU4X_UNICODE_LICENSE_DEPENDENCIES: &[&str] = &[ | |
419 | // tidy-alphabetical-start | |
420 | "icu_list", | |
421 | "icu_list_data", | |
422 | "icu_locid", | |
423 | "icu_locid_transform", | |
424 | "icu_locid_transform_data", | |
425 | "icu_provider", | |
426 | "icu_provider_adapters", | |
427 | "icu_provider_macros", | |
428 | "litemap", | |
429 | "tinystr", | |
430 | "writeable", | |
431 | "yoke", | |
432 | "yoke-derive", | |
433 | "zerofrom", | |
434 | "zerofrom-derive", | |
435 | "zerovec", | |
436 | "zerovec-derive", | |
437 | // tidy-alphabetical-end | |
438 | ]; | |
439 | ||
17df50a5 | 440 | const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ |
49aad941 | 441 | // tidy-alphabetical-start |
064997fb | 442 | "ahash", |
17df50a5 | 443 | "anyhow", |
fe692bf9 | 444 | "arbitrary", |
17df50a5 | 445 | "bitflags", |
49aad941 | 446 | "bumpalo", |
17df50a5 XL |
447 | "cfg-if", |
448 | "cranelift-bforest", | |
449 | "cranelift-codegen", | |
450 | "cranelift-codegen-meta", | |
451 | "cranelift-codegen-shared", | |
fe692bf9 | 452 | "cranelift-control", |
17df50a5 XL |
453 | "cranelift-entity", |
454 | "cranelift-frontend", | |
064997fb | 455 | "cranelift-isle", |
17df50a5 XL |
456 | "cranelift-jit", |
457 | "cranelift-module", | |
458 | "cranelift-native", | |
459 | "cranelift-object", | |
460 | "crc32fast", | |
add651ee | 461 | "equivalent", |
9c376795 | 462 | "fallible-iterator", |
17df50a5 XL |
463 | "gimli", |
464 | "hashbrown", | |
465 | "indexmap", | |
466 | "libc", | |
467 | "libloading", | |
468 | "log", | |
469 | "mach", | |
136023e0 | 470 | "memchr", |
17df50a5 | 471 | "object", |
e8be2606 | 472 | "once_cell", |
c620b35d FG |
473 | "proc-macro2", |
474 | "quote", | |
064997fb | 475 | "regalloc2", |
17df50a5 | 476 | "region", |
fe692bf9 | 477 | "rustc-hash", |
064997fb | 478 | "slice-group-by", |
17df50a5 | 479 | "smallvec", |
9c376795 | 480 | "stable_deref_trait", |
c620b35d | 481 | "syn", |
17df50a5 | 482 | "target-lexicon", |
c620b35d | 483 | "unicode-ident", |
064997fb | 484 | "version_check", |
9c376795 | 485 | "wasmtime-jit-icache-coherence", |
17df50a5 XL |
486 | "winapi", |
487 | "winapi-i686-pc-windows-gnu", | |
488 | "winapi-x86_64-pc-windows-gnu", | |
f2b60f7d | 489 | "windows-sys", |
fe692bf9 FG |
490 | "windows-targets", |
491 | "windows_aarch64_gnullvm", | |
492 | "windows_aarch64_msvc", | |
493 | "windows_i686_gnu", | |
e8be2606 | 494 | "windows_i686_gnullvm", |
fe692bf9 FG |
495 | "windows_i686_msvc", |
496 | "windows_x86_64_gnu", | |
497 | "windows_x86_64_gnullvm", | |
498 | "windows_x86_64_msvc", | |
c620b35d FG |
499 | "zerocopy", |
500 | "zerocopy-derive", | |
49aad941 | 501 | // tidy-alphabetical-end |
17df50a5 XL |
502 | ]; |
503 | ||
ba9703b0 XL |
504 | /// Dependency checks. |
505 | /// | |
3dfed10e XL |
506 | /// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path |
507 | /// to the cargo executable. | |
508 | pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { | |
ed00b5ec | 509 | let mut checked_runtime_licenses = false; |
ed00b5ec FG |
510 | |
511 | for &(workspace, exceptions, permitted_deps) in WORKSPACES { | |
512 | if !root.join(workspace).join("Cargo.lock").exists() { | |
513 | tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock"); | |
514 | continue; | |
515 | } | |
516 | ||
517 | let mut cmd = cargo_metadata::MetadataCommand::new(); | |
518 | cmd.cargo_path(cargo) | |
519 | .manifest_path(root.join(workspace).join("Cargo.toml")) | |
520 | .features(cargo_metadata::CargoOpt::AllFeatures) | |
521 | .other_options(vec!["--locked".to_owned()]); | |
522 | let metadata = t!(cmd.exec()); | |
49aad941 | 523 | |
ed00b5ec FG |
524 | check_license_exceptions(&metadata, exceptions, bad); |
525 | if let Some((crates, permitted_deps)) = permitted_deps { | |
526 | check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad); | |
527 | } | |
17df50a5 | 528 | |
ed00b5ec FG |
529 | if workspace == "." { |
530 | let runtime_ids = compute_runtime_crates(&metadata); | |
531 | check_runtime_license_exceptions(&metadata, runtime_ids, bad); | |
532 | checked_runtime_licenses = true; | |
ed00b5ec FG |
533 | } |
534 | } | |
064997fb | 535 | |
ed00b5ec FG |
536 | // Sanity check to ensure we don't accidentally remove the workspace containing the runtime |
537 | // crates. | |
538 | assert!(checked_runtime_licenses); | |
0531ce1d XL |
539 | } |
540 | ||
ed00b5ec | 541 | /// Check that all licenses of runtime dependencies are in the valid list in `LICENSES`. |
ba9703b0 | 542 | /// |
ed00b5ec FG |
543 | /// Unlike for tools we don't allow exceptions to the `LICENSES` list for the runtime with the sole |
544 | /// exception of `fortanix-sgx-abi` which is only used on x86_64-fortanix-unknown-sgx. | |
545 | fn check_runtime_license_exceptions( | |
17df50a5 | 546 | metadata: &Metadata, |
17df50a5 XL |
547 | runtime_ids: HashSet<&PackageId>, |
548 | bad: &mut bool, | |
549 | ) { | |
ed00b5ec FG |
550 | for pkg in &metadata.packages { |
551 | if !runtime_ids.contains(&pkg.id) { | |
552 | // Only checking dependencies of runtime libraries here. | |
553 | continue; | |
554 | } | |
555 | if pkg.source.is_none() { | |
556 | // No need to check local packages. | |
557 | continue; | |
558 | } | |
559 | let license = match &pkg.license { | |
560 | Some(license) => license, | |
561 | None => { | |
562 | tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id); | |
563 | continue; | |
564 | } | |
565 | }; | |
566 | if !LICENSES.contains(&license.as_str()) { | |
567 | // This is a specific exception because SGX is considered "third party". | |
568 | // See https://github.com/rust-lang/rust/issues/62620 for more. | |
569 | // In general, these should never be added and this exception | |
570 | // should not be taken as precedent for any new target. | |
571 | if pkg.name == "fortanix-sgx-abi" && pkg.license.as_deref() == Some("MPL-2.0") { | |
572 | continue; | |
573 | } | |
c620b35d FG |
574 | |
575 | // This exception is due to the fact that the feature set of the | |
576 | // `object` crate is different between rustc and libstd. In the | |
577 | // standard library only a conservative set of features are enabled | |
578 | // which notably does not include the `wasm` feature which pulls in | |
579 | // this dependency. In the compiler, however, the `wasm` feature is | |
580 | // enabled. This exception is intended to be here so long as the | |
581 | // `EXCEPTIONS` above contains `wasmparser`, but once that goes away | |
582 | // this can be removed. | |
583 | if pkg.name == "wasmparser" | |
584 | && pkg.license.as_deref() == Some("Apache-2.0 WITH LLVM-exception") | |
585 | { | |
586 | continue; | |
587 | } | |
588 | ||
ed00b5ec FG |
589 | tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); |
590 | } | |
591 | } | |
592 | } | |
593 | ||
594 | /// Check that all licenses of tool dependencies are in the valid list in `LICENSES`. | |
595 | /// | |
596 | /// Packages listed in `exceptions` are allowed for tools. | |
597 | fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], bad: &mut bool) { | |
ba9703b0 | 598 | // Validate the EXCEPTIONS list hasn't changed. |
17df50a5 | 599 | for (name, license) in exceptions { |
ba9703b0 XL |
600 | // Check that the package actually exists. |
601 | if !metadata.packages.iter().any(|p| p.name == *name) { | |
fc512014 XL |
602 | tidy_error!( |
603 | bad, | |
ba9703b0 XL |
604 | "could not find exception package `{}`\n\ |
605 | Remove from EXCEPTIONS list if it is no longer used.", | |
606 | name | |
607 | ); | |
ba9703b0 XL |
608 | } |
609 | // Check that the license hasn't changed. | |
610 | for pkg in metadata.packages.iter().filter(|p| p.name == *name) { | |
ba9703b0 XL |
611 | match &pkg.license { |
612 | None => { | |
fc512014 XL |
613 | tidy_error!( |
614 | bad, | |
ba9703b0 XL |
615 | "dependency exception `{}` does not declare a license expression", |
616 | pkg.id | |
617 | ); | |
ba9703b0 XL |
618 | } |
619 | Some(pkg_license) => { | |
620 | if pkg_license.as_str() != *license { | |
5e7ed085 FG |
621 | println!("dependency exception `{name}` license has changed"); |
622 | println!(" previously `{license}` now `{pkg_license}`"); | |
ba9703b0 XL |
623 | println!(" update EXCEPTIONS for the new license"); |
624 | *bad = true; | |
625 | } | |
626 | } | |
627 | } | |
628 | } | |
0531ce1d | 629 | } |
0531ce1d | 630 | |
17df50a5 | 631 | let exception_names: Vec<_> = exceptions.iter().map(|(name, _license)| *name).collect(); |
8bb4bdeb | 632 | |
ba9703b0 XL |
633 | // Check if any package does not have a valid license. |
634 | for pkg in &metadata.packages { | |
635 | if pkg.source.is_none() { | |
636 | // No need to check local packages. | |
0531ce1d | 637 | continue; |
8bb4bdeb | 638 | } |
ed00b5ec | 639 | if exception_names.contains(&pkg.name.as_str()) { |
ba9703b0 XL |
640 | continue; |
641 | } | |
642 | let license = match &pkg.license { | |
643 | Some(license) => license, | |
644 | None => { | |
ed00b5ec FG |
645 | if ICU4X_UNICODE_LICENSE_DEPENDENCIES.contains(&pkg.name.as_str()) { |
646 | // See the comment on ICU4X_UNICODE_LICENSE_DEPENDENCIES. | |
647 | continue; | |
648 | } | |
fc512014 | 649 | tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id); |
ba9703b0 XL |
650 | continue; |
651 | } | |
652 | }; | |
653 | if !LICENSES.contains(&license.as_str()) { | |
fc512014 | 654 | tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); |
ba9703b0 | 655 | } |
476ff2be | 656 | } |
476ff2be SL |
657 | } |
658 | ||
2b03887a | 659 | /// Checks the dependency of `restricted_dependency_crates` at the given path. Changes `bad` to |
f035d41b | 660 | /// `true` if a check failed. |
0531ce1d | 661 | /// |
2b03887a FG |
662 | /// Specifically, this checks that the dependencies are on the `permitted_dependencies`. |
663 | fn check_permitted_dependencies( | |
17df50a5 | 664 | metadata: &Metadata, |
064997fb | 665 | descr: &str, |
17df50a5 XL |
666 | permitted_dependencies: &[&'static str], |
667 | restricted_dependency_crates: &[&'static str], | |
668 | bad: &mut bool, | |
669 | ) { | |
fe692bf9 | 670 | let mut has_permitted_dep_error = false; |
9c376795 FG |
671 | let mut deps = HashSet::new(); |
672 | for to_check in restricted_dependency_crates { | |
673 | let to_check = pkg_from_name(metadata, to_check); | |
e8be2606 | 674 | deps_of(metadata, &to_check.id, &mut deps); |
9c376795 FG |
675 | } |
676 | ||
f035d41b | 677 | // Check that the PERMITTED_DEPENDENCIES does not have unused entries. |
9c376795 FG |
678 | for permitted in permitted_dependencies { |
679 | if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) { | |
fc512014 XL |
680 | tidy_error!( |
681 | bad, | |
9c376795 | 682 | "could not find allowed package `{permitted}`\n\ |
f035d41b | 683 | Remove from PERMITTED_DEPENDENCIES list if it is no longer used.", |
ba9703b0 | 684 | ); |
fe692bf9 | 685 | has_permitted_dep_error = true; |
ba9703b0 XL |
686 | } |
687 | } | |
0531ce1d | 688 | |
9c376795 FG |
689 | // Get in a convenient form. |
690 | let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect(); | |
0531ce1d | 691 | |
9c376795 FG |
692 | for dep in deps { |
693 | let dep = pkg_from_id(metadata, dep); | |
694 | // If this path is in-tree, we don't require it to be explicitly permitted. | |
695 | if dep.source.is_some() { | |
696 | if !permitted_dependencies.contains(dep.name.as_str()) { | |
697 | tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); | |
fe692bf9 | 698 | has_permitted_dep_error = true; |
9c376795 | 699 | } |
0531ce1d | 700 | } |
0531ce1d | 701 | } |
fe692bf9 FG |
702 | |
703 | if has_permitted_dep_error { | |
704 | eprintln!("Go to `{PERMITTED_DEPS_LOCATION}` for the list."); | |
705 | } | |
0531ce1d XL |
706 | } |
707 | ||
ba9703b0 XL |
708 | /// Finds a package with the given name. |
709 | fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package { | |
710 | let mut i = metadata.packages.iter().filter(|p| p.name == name); | |
711 | let result = | |
5e7ed085 FG |
712 | i.next().unwrap_or_else(|| panic!("could not find package `{name}` in package list")); |
713 | assert!(i.next().is_none(), "more than one package found for `{name}`"); | |
ba9703b0 XL |
714 | result |
715 | } | |
716 | ||
9c376795 FG |
717 | fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package { |
718 | metadata.packages.iter().find(|p| &p.id == id).unwrap() | |
719 | } | |
720 | ||
ba9703b0 XL |
721 | /// Finds all the packages that are in the rust runtime. |
722 | fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> { | |
ba9703b0 XL |
723 | let mut result = HashSet::new(); |
724 | for name in RUNTIME_CRATES { | |
725 | let id = &pkg_from_name(metadata, name).id; | |
e8be2606 | 726 | deps_of(metadata, id, &mut result); |
ba9703b0 XL |
727 | } |
728 | result | |
729 | } | |
730 | ||
9c376795 | 731 | /// Recursively find all dependencies. |
e8be2606 | 732 | fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId, result: &mut HashSet<&'a PackageId>) { |
ba9703b0 XL |
733 | if !result.insert(pkg_id) { |
734 | return; | |
735 | } | |
9c376795 FG |
736 | let node = metadata |
737 | .resolve | |
738 | .as_ref() | |
739 | .unwrap() | |
ba9703b0 XL |
740 | .nodes |
741 | .iter() | |
742 | .find(|n| &n.id == pkg_id) | |
5e7ed085 | 743 | .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve")); |
17df50a5 | 744 | for dep in &node.deps { |
e8be2606 | 745 | deps_of(metadata, &dep.pkg, result); |
b7449926 XL |
746 | } |
747 | } |