2019-01-11 17:32:31 +01:00
|
|
|
//! Checks the licenses of third-party dependencies by inspecting vendors.
|
2016-12-11 00:27:42 +01:00
|
|
|
|
2019-12-22 23:42:04 +01:00
|
|
|
use std::collections::{BTreeSet, HashMap, HashSet};
|
2018-11-16 22:22:06 +01:00
|
|
|
use std::fs;
|
2016-12-11 00:27:42 +01:00
|
|
|
use std::path::Path;
|
2018-02-23 02:52:56 +01:00
|
|
|
use std::process::Command;
|
|
|
|
|
2019-05-09 18:03:13 +02:00
|
|
|
use serde::Deserialize;
|
2018-02-23 02:52:56 +01:00
|
|
|
use serde_json;
|
|
|
|
|
2018-09-02 01:46:57 +02:00
|
|
|
const LICENSES: &[&str] = &[
|
2017-02-09 20:44:39 +01:00
|
|
|
"MIT/Apache-2.0",
|
2017-02-16 00:57:06 +01:00
|
|
|
"MIT / Apache-2.0",
|
2017-02-09 20:44:39 +01:00
|
|
|
"Apache-2.0/MIT",
|
2017-07-18 23:26:55 +02:00
|
|
|
"Apache-2.0 / MIT",
|
2017-02-09 20:44:39 +01:00
|
|
|
"MIT OR Apache-2.0",
|
2019-05-04 21:20:24 +02:00
|
|
|
"Apache-2.0 OR MIT",
|
2019-08-29 19:22:24 +02:00
|
|
|
"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
|
2017-02-09 20:44:39 +01:00
|
|
|
"MIT",
|
|
|
|
"Unlicense/MIT",
|
2018-07-26 02:25:12 +02:00
|
|
|
"Unlicense OR MIT",
|
2017-02-09 20:44:39 +01:00
|
|
|
];
|
|
|
|
|
2018-02-27 06:45:04 +01:00
|
|
|
/// These are exceptions to Rust's permissive licensing policy, and
|
|
|
|
/// should be considered bugs. Exceptions are only allowed in Rust
|
|
|
|
/// tooling. It is _crucial_ that no exception crates be dependencies
|
2019-01-11 17:32:31 +01:00
|
|
|
/// of the Rust runtime (std/test).
|
2018-09-02 01:46:57 +02:00
|
|
|
const EXCEPTIONS: &[&str] = &[
|
2018-02-23 01:59:04 +01:00
|
|
|
"mdbook", // MPL2, mdbook
|
|
|
|
"openssl", // BSD+advertising clause, cargo, mdbook
|
|
|
|
"pest", // MPL2, mdbook via handlebars
|
2019-01-19 05:15:25 +01:00
|
|
|
"arrayref", // BSD-2-Clause, mdbook via handlebars via pest
|
2018-02-23 01:59:04 +01:00
|
|
|
"thread-id", // Apache-2.0, mdbook
|
|
|
|
"toml-query", // MPL-2.0, mdbook
|
|
|
|
"is-match", // MPL-2.0, mdbook
|
|
|
|
"cssparser", // MPL-2.0, rustdoc
|
|
|
|
"smallvec", // MPL-2.0, rustdoc
|
2019-06-10 20:22:31 +02:00
|
|
|
"rdrand", // ISC, mdbook, rustfmt
|
|
|
|
"fuchsia-cprng", // BSD-3-Clause, mdbook, rustfmt
|
2017-10-27 16:12:51 +02:00
|
|
|
"fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
|
2018-02-23 01:59:04 +01:00
|
|
|
"fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
|
|
|
|
"cssparser-macros", // MPL-2.0, rustdoc
|
|
|
|
"selectors", // MPL-2.0, rustdoc
|
2018-04-26 05:10:11 +02:00
|
|
|
"clippy_lints", // MPL-2.0, rls
|
|
|
|
"colored", // MPL-2.0, rustfmt
|
2018-07-06 02:34:00 +02:00
|
|
|
"ordslice", // Apache-2.0, rls
|
2018-07-29 05:54:27 +02:00
|
|
|
"cloudabi", // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
|
2019-01-11 17:32:31 +01:00
|
|
|
"ryu", // Apache-2.0, rls/cargo/... (because of serde)
|
2018-09-20 23:37:53 +02:00
|
|
|
"bytesize", // Apache-2.0, cargo
|
2018-12-03 02:33:20 +01:00
|
|
|
"im-rc", // MPL-2.0+, cargo
|
2018-12-08 12:06:54 +01:00
|
|
|
"adler32", // BSD-3-Clause AND Zlib, cargo dep that isn't used
|
2019-02-17 00:09:27 +01:00
|
|
|
"constant_time_eq", // CC0-1.0, rustfmt
|
2019-05-23 22:27:49 +02:00
|
|
|
"utf8parse", // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
|
|
|
|
"vte", // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
|
|
|
|
"sized-chunks", // MPL-2.0+, cargo via im-rc
|
2019-11-25 17:14:07 +01:00
|
|
|
"bitmaps", // MPL-2.0+, cargo via im-rc
|
2019-06-21 17:35:48 +02:00
|
|
|
// FIXME: this dependency violates the documentation comment above:
|
|
|
|
"fortanix-sgx-abi", // MPL-2.0+, libstd but only for `sgx` target
|
2019-11-12 19:45:33 +01:00
|
|
|
"dunce", // CC0-1.0 mdbook-linkcheck
|
|
|
|
"codespan-reporting", // Apache-2.0 mdbook-linkcheck
|
|
|
|
"codespan", // Apache-2.0 mdbook-linkcheck
|
2016-12-11 00:27:42 +01:00
|
|
|
];
|
|
|
|
|
2018-02-27 06:45:04 +01:00
|
|
|
/// Which crates to check against the whitelist?
|
2019-12-22 23:42:04 +01:00
|
|
|
const WHITELIST_CRATES: &[CrateVersion<'_>] =
|
|
|
|
&[CrateVersion("rustc", "0.0.0"), CrateVersion("rustc_codegen_llvm", "0.0.0")];
|
2018-02-27 06:45:04 +01:00
|
|
|
|
|
|
|
/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
|
2019-03-01 10:14:09 +01:00
|
|
|
const WHITELIST: &[Crate<'_>] = &[
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("adler32"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("aho-corasick"),
|
2019-05-31 22:01:27 +02:00
|
|
|
Crate("annotate-snippets"),
|
|
|
|
Crate("ansi_term"),
|
2018-04-26 00:49:52 +02:00
|
|
|
Crate("arrayvec"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("atty"),
|
2019-05-15 16:30:15 +02:00
|
|
|
Crate("autocfg"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("backtrace"),
|
|
|
|
Crate("backtrace-sys"),
|
|
|
|
Crate("bitflags"),
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("build_const"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("byteorder"),
|
2019-07-24 17:02:35 +02:00
|
|
|
Crate("c2-chacha"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("cc"),
|
2018-08-21 19:23:47 +02:00
|
|
|
Crate("cfg-if"),
|
2018-05-24 15:51:38 +02:00
|
|
|
Crate("chalk-engine"),
|
|
|
|
Crate("chalk-macros"),
|
2018-08-21 19:23:47 +02:00
|
|
|
Crate("cloudabi"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("cmake"),
|
2018-12-14 23:37:51 +01:00
|
|
|
Crate("compiler_builtins"),
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("crc"),
|
|
|
|
Crate("crc32fast"),
|
2018-04-26 00:49:52 +02:00
|
|
|
Crate("crossbeam-deque"),
|
|
|
|
Crate("crossbeam-epoch"),
|
2019-10-07 22:43:10 +02:00
|
|
|
Crate("crossbeam-queue"),
|
2018-04-26 00:49:52 +02:00
|
|
|
Crate("crossbeam-utils"),
|
2018-05-28 18:54:11 +02:00
|
|
|
Crate("datafrog"),
|
bootstrap: Merge the libtest build step with libstd
Since its inception rustbuild has always worked in three stages: one for
libstd, one for libtest, and one for rustc. These three stages were
architected around crates.io dependencies, where rustc wants to depend
on crates.io crates but said crates don't explicitly depend on libstd,
requiring a sysroot assembly step in the middle. This same logic was
applied for libtest where libtest wants to depend on crates.io crates
(`getopts`) but `getopts` didn't say that it depended on std, so it
needed `std` built ahead of time.
Lots of time has passed since the inception of rustbuild, however,
and we've since gotten to the point where even `std` itself is depending
on crates.io crates (albeit with some wonky configuration). This
commit applies the same logic to the two dependencies that the `test`
crate pulls in from crates.io, `getopts` and `unicode-width`. Over the
many years since rustbuild's inception `unicode-width` was the only
dependency picked up by the `test` crate, so the extra configuration
necessary to get crates building in this crate graph is unlikely to be
too much of a burden on developers.
After this patch it means that there are now only two build phasese of
rustbuild, one for libstd and one for rustc. The libtest/libproc_macro
build phase is all lumped into one now with `std`.
This was originally motivated by rust-lang/cargo#7216 where Cargo was
having to deal with synthesizing dependency edges but this commit makes
them explicit in this repository.
2019-08-16 17:29:08 +02:00
|
|
|
Crate("dlmalloc"),
|
2018-04-26 00:49:52 +02:00
|
|
|
Crate("either"),
|
2018-03-02 19:15:02 +01:00
|
|
|
Crate("ena"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("env_logger"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("filetime"),
|
|
|
|
Crate("flate2"),
|
bootstrap: Merge the libtest build step with libstd
Since its inception rustbuild has always worked in three stages: one for
libstd, one for libtest, and one for rustc. These three stages were
architected around crates.io dependencies, where rustc wants to depend
on crates.io crates but said crates don't explicitly depend on libstd,
requiring a sysroot assembly step in the middle. This same logic was
applied for libtest where libtest wants to depend on crates.io crates
(`getopts`) but `getopts` didn't say that it depended on std, so it
needed `std` built ahead of time.
Lots of time has passed since the inception of rustbuild, however,
and we've since gotten to the point where even `std` itself is depending
on crates.io crates (albeit with some wonky configuration). This
commit applies the same logic to the two dependencies that the `test`
crate pulls in from crates.io, `getopts` and `unicode-width`. Over the
many years since rustbuild's inception `unicode-width` was the only
dependency picked up by the `test` crate, so the extra configuration
necessary to get crates building in this crate graph is unlikely to be
too much of a burden on developers.
After this patch it means that there are now only two build phasese of
rustbuild, one for libstd and one for rustc. The libtest/libproc_macro
build phase is all lumped into one now with `std`.
This was originally motivated by rust-lang/cargo#7216 where Cargo was
having to deal with synthesizing dependency edges but this commit makes
them explicit in this repository.
2019-08-16 17:29:08 +02:00
|
|
|
Crate("fortanix-sgx-abi"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("fuchsia-zircon"),
|
|
|
|
Crate("fuchsia-zircon-sys"),
|
2018-04-08 13:44:29 +02:00
|
|
|
Crate("getopts"),
|
2019-07-24 17:02:35 +02:00
|
|
|
Crate("getrandom"),
|
bootstrap: Merge the libtest build step with libstd
Since its inception rustbuild has always worked in three stages: one for
libstd, one for libtest, and one for rustc. These three stages were
architected around crates.io dependencies, where rustc wants to depend
on crates.io crates but said crates don't explicitly depend on libstd,
requiring a sysroot assembly step in the middle. This same logic was
applied for libtest where libtest wants to depend on crates.io crates
(`getopts`) but `getopts` didn't say that it depended on std, so it
needed `std` built ahead of time.
Lots of time has passed since the inception of rustbuild, however,
and we've since gotten to the point where even `std` itself is depending
on crates.io crates (albeit with some wonky configuration). This
commit applies the same logic to the two dependencies that the `test`
crate pulls in from crates.io, `getopts` and `unicode-width`. Over the
many years since rustbuild's inception `unicode-width` was the only
dependency picked up by the `test` crate, so the extra configuration
necessary to get crates building in this crate graph is unlikely to be
too much of a burden on developers.
After this patch it means that there are now only two build phasese of
rustbuild, one for libstd and one for rustc. The libtest/libproc_macro
build phase is all lumped into one now with `std`.
This was originally motivated by rust-lang/cargo#7216 where Cargo was
having to deal with synthesizing dependency edges but this commit makes
them explicit in this repository.
2019-08-16 17:29:08 +02:00
|
|
|
Crate("hashbrown"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("humantime"),
|
2019-05-14 18:42:57 +02:00
|
|
|
Crate("indexmap"),
|
2019-03-20 16:34:30 +01:00
|
|
|
Crate("itertools"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("jobserver"),
|
|
|
|
Crate("kernel32-sys"),
|
|
|
|
Crate("lazy_static"),
|
|
|
|
Crate("libc"),
|
2018-11-16 12:08:23 +01:00
|
|
|
Crate("libz-sys"),
|
2018-08-05 00:24:39 +02:00
|
|
|
Crate("lock_api"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("log"),
|
|
|
|
Crate("log_settings"),
|
2019-04-05 01:41:49 +02:00
|
|
|
Crate("measureme"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("memchr"),
|
2018-09-03 12:59:30 +02:00
|
|
|
Crate("memmap"),
|
2018-04-26 00:49:52 +02:00
|
|
|
Crate("memoffset"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("miniz-sys"),
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("miniz_oxide"),
|
|
|
|
Crate("miniz_oxide_c_api"),
|
2018-04-26 00:49:52 +02:00
|
|
|
Crate("nodrop"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("num_cpus"),
|
|
|
|
Crate("owning_ref"),
|
|
|
|
Crate("parking_lot"),
|
|
|
|
Crate("parking_lot_core"),
|
2018-05-23 04:40:02 +02:00
|
|
|
Crate("pkg-config"),
|
2018-08-05 00:24:39 +02:00
|
|
|
Crate("polonius-engine"),
|
2019-07-24 17:02:35 +02:00
|
|
|
Crate("ppv-lite86"),
|
2018-12-17 19:23:04 +01:00
|
|
|
Crate("proc-macro2"),
|
2019-10-22 17:51:35 +02:00
|
|
|
Crate("punycode"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("quick-error"),
|
2018-12-17 19:23:04 +01:00
|
|
|
Crate("quote"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("rand"),
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("rand_chacha"),
|
2018-08-21 19:23:47 +02:00
|
|
|
Crate("rand_core"),
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("rand_hc"),
|
|
|
|
Crate("rand_isaac"),
|
|
|
|
Crate("rand_pcg"),
|
|
|
|
Crate("rand_xorshift"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("redox_syscall"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("redox_termios"),
|
|
|
|
Crate("regex"),
|
|
|
|
Crate("regex-syntax"),
|
2018-02-26 18:07:16 +01:00
|
|
|
Crate("remove_dir_all"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("rustc-demangle"),
|
2018-05-24 15:51:38 +02:00
|
|
|
Crate("rustc-hash"),
|
2018-04-26 00:49:52 +02:00
|
|
|
Crate("rustc-rayon"),
|
|
|
|
Crate("rustc-rayon-core"),
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("rustc_version"),
|
2018-03-07 02:44:10 +01:00
|
|
|
Crate("scoped-tls"),
|
2018-04-26 00:49:52 +02:00
|
|
|
Crate("scopeguard"),
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("semver"),
|
|
|
|
Crate("semver-parser"),
|
|
|
|
Crate("serde"),
|
2018-12-17 19:23:04 +01:00
|
|
|
Crate("serde_derive"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("smallvec"),
|
|
|
|
Crate("stable_deref_trait"),
|
2018-12-17 19:23:04 +01:00
|
|
|
Crate("syn"),
|
2018-12-03 01:14:35 +01:00
|
|
|
Crate("synstructure"),
|
2018-05-13 15:26:55 +02:00
|
|
|
Crate("tempfile"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("termcolor"),
|
|
|
|
Crate("terminon"),
|
|
|
|
Crate("termion"),
|
2020-01-29 01:13:48 +01:00
|
|
|
Crate("termize"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("thread_local"),
|
2018-02-26 18:07:16 +01:00
|
|
|
Crate("ucd-util"),
|
2019-12-19 04:57:30 +01:00
|
|
|
Crate("unicode-normalization"),
|
2020-01-02 13:02:22 +01:00
|
|
|
Crate("unicode-script"),
|
|
|
|
Crate("unicode-security"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("unicode-width"),
|
2018-12-17 19:23:04 +01:00
|
|
|
Crate("unicode-xid"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("unreachable"),
|
|
|
|
Crate("utf8-ranges"),
|
2018-12-08 12:06:54 +01:00
|
|
|
Crate("vcpkg"),
|
2018-08-21 19:23:47 +02:00
|
|
|
Crate("version_check"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("void"),
|
2019-08-29 20:08:13 +02:00
|
|
|
Crate("wasi"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("winapi"),
|
|
|
|
Crate("winapi-build"),
|
|
|
|
Crate("winapi-i686-pc-windows-gnu"),
|
2018-08-05 00:24:39 +02:00
|
|
|
Crate("winapi-util"),
|
2018-03-02 04:22:06 +01:00
|
|
|
Crate("winapi-x86_64-pc-windows-gnu"),
|
2018-03-01 20:08:48 +01:00
|
|
|
Crate("wincolor"),
|
2019-10-21 20:23:59 +02:00
|
|
|
Crate("hermit-abi"),
|
2018-02-24 01:25:21 +01:00
|
|
|
];
|
2018-02-23 02:52:56 +01:00
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
// Some types for Serde to deserialize the output of `cargo metadata` to.
|
2018-02-23 02:52:56 +01:00
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct Output {
|
2018-02-27 06:45:04 +01:00
|
|
|
resolve: Resolve,
|
2018-02-24 01:01:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct Resolve {
|
|
|
|
nodes: Vec<ResolveNode>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct ResolveNode {
|
|
|
|
id: String,
|
|
|
|
dependencies: Vec<String>,
|
2018-02-23 02:52:56 +01:00
|
|
|
}
|
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
/// A unique identifier for a crate.
|
2018-02-27 06:45:04 +01:00
|
|
|
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
|
2019-01-11 17:32:31 +01:00
|
|
|
struct Crate<'a>(&'a str); // (name)
|
2018-02-27 06:45:04 +01:00
|
|
|
|
2018-02-28 01:33:55 +01:00
|
|
|
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
|
|
|
|
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)
|
|
|
|
|
2019-03-01 10:14:09 +01:00
|
|
|
impl Crate<'_> {
|
2018-02-28 01:33:55 +01:00
|
|
|
pub fn id_str(&self) -> String {
|
|
|
|
format!("{} ", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> CrateVersion<'a> {
|
2019-01-11 17:32:31 +01:00
|
|
|
/// Returns the struct and whether or not the dependency is in-tree.
|
2018-02-28 21:12:15 +01:00
|
|
|
pub fn from_str(s: &'a str) -> (Self, bool) {
|
2018-07-23 15:32:57 +02:00
|
|
|
let mut parts = s.split(' ');
|
2018-02-27 06:45:04 +01:00
|
|
|
let name = parts.next().unwrap();
|
2018-02-28 01:33:55 +01:00
|
|
|
let version = parts.next().unwrap();
|
2018-02-28 21:12:15 +01:00
|
|
|
let path = parts.next().unwrap();
|
2018-02-27 06:45:04 +01:00
|
|
|
|
2018-02-28 21:12:15 +01:00
|
|
|
let is_path_dep = path.starts_with("(path+");
|
|
|
|
|
|
|
|
(CrateVersion(name, version), is_path_dep)
|
2018-02-27 06:45:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn id_str(&self) -> String {
|
2018-02-28 01:33:55 +01:00
|
|
|
format!("{} {}", self.0, self.1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> From<CrateVersion<'a>> for Crate<'a> {
|
|
|
|
fn from(cv: CrateVersion<'a>) -> Crate<'a> {
|
|
|
|
Crate(cv.0)
|
2018-02-27 06:45:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-23 02:52:56 +01:00
|
|
|
/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
|
|
|
|
///
|
2018-02-24 01:01:51 +01:00
|
|
|
/// Specifically, this checks that the license is correct.
|
2016-12-11 00:27:42 +01:00
|
|
|
pub fn check(path: &Path, bad: &mut bool) {
|
2019-01-11 17:32:31 +01:00
|
|
|
// Check licences.
|
2018-08-22 04:50:46 +02:00
|
|
|
let path = path.join("../vendor");
|
2016-12-11 00:27:42 +01:00
|
|
|
assert!(path.exists(), "vendor directory missing");
|
|
|
|
let mut saw_dir = false;
|
2018-02-23 02:52:56 +01:00
|
|
|
for dir in t!(path.read_dir()) {
|
2016-12-11 00:27:42 +01:00
|
|
|
saw_dir = true;
|
|
|
|
let dir = t!(dir);
|
2017-02-09 20:44:39 +01:00
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
// Skip our exceptions.
|
2018-09-02 02:36:37 +02:00
|
|
|
let is_exception = EXCEPTIONS.iter().any(|exception| {
|
2019-12-22 23:42:04 +01:00
|
|
|
dir.path().to_str().unwrap().contains(&format!("vendor/{}", exception))
|
2018-09-02 02:36:37 +02:00
|
|
|
});
|
|
|
|
if is_exception {
|
2018-02-23 02:52:56 +01:00
|
|
|
continue;
|
2017-02-09 20:44:39 +01:00
|
|
|
}
|
|
|
|
|
2016-12-11 00:27:42 +01:00
|
|
|
let toml = dir.path().join("Cargo.toml");
|
2019-05-23 22:33:08 +02:00
|
|
|
*bad = !check_license(&toml) || *bad;
|
2016-12-11 00:27:42 +01:00
|
|
|
}
|
|
|
|
assert!(saw_dir, "no vendored source");
|
2018-02-24 01:01:51 +01:00
|
|
|
}
|
2018-02-23 02:52:56 +01:00
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
|
|
|
|
/// check failed.
|
2018-02-24 01:01:51 +01:00
|
|
|
///
|
2019-01-11 17:32:31 +01:00
|
|
|
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
|
2018-02-26 18:05:43 +01:00
|
|
|
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
|
2019-01-11 17:32:31 +01:00
|
|
|
// Get dependencies from Cargo metadata.
|
2018-02-27 06:45:04 +01:00
|
|
|
let resolve = get_deps(path, cargo);
|
2018-02-24 01:01:51 +01:00
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
// Get the whitelist in a convenient form.
|
2018-02-27 06:45:04 +01:00
|
|
|
let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();
|
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
// Check dependencies.
|
2018-02-27 19:02:54 +01:00
|
|
|
let mut visited = BTreeSet::new();
|
|
|
|
let mut unapproved = BTreeSet::new();
|
2018-02-27 06:45:04 +01:00
|
|
|
for &krate in WHITELIST_CRATES.iter() {
|
2018-02-28 23:28:30 +01:00
|
|
|
let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
|
2018-02-27 06:45:04 +01:00
|
|
|
unapproved.append(&mut bad);
|
|
|
|
}
|
2018-02-24 01:01:51 +01:00
|
|
|
|
2018-09-01 21:17:57 +02:00
|
|
|
if !unapproved.is_empty() {
|
2018-02-24 01:01:51 +01:00
|
|
|
println!("Dependencies not on the whitelist:");
|
|
|
|
for dep in unapproved {
|
2018-02-27 19:02:54 +01:00
|
|
|
println!("* {}", dep.id_str());
|
2018-02-24 01:01:51 +01:00
|
|
|
}
|
|
|
|
*bad = true;
|
|
|
|
}
|
2018-08-08 08:09:36 +02:00
|
|
|
|
|
|
|
check_crate_duplicate(&resolve, bad);
|
2016-12-11 00:27:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_license(path: &Path) -> bool {
|
|
|
|
if !path.exists() {
|
|
|
|
panic!("{} does not exist", path.display());
|
|
|
|
}
|
2018-11-16 22:22:06 +01:00
|
|
|
let contents = t!(fs::read_to_string(&path));
|
2016-12-11 00:27:42 +01:00
|
|
|
|
|
|
|
let mut found_license = false;
|
|
|
|
for line in contents.lines() {
|
|
|
|
if !line.starts_with("license") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let license = extract_license(line);
|
|
|
|
if !LICENSES.contains(&&*license) {
|
|
|
|
println!("invalid license {} in {}", license, path.display());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
found_license = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if !found_license {
|
|
|
|
println!("no license in {}", path.display());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn extract_license(line: &str) -> String {
|
|
|
|
let first_quote = line.find('"');
|
|
|
|
let last_quote = line.rfind('"');
|
|
|
|
if let (Some(f), Some(l)) = (first_quote, last_quote) {
|
2018-02-23 01:59:04 +01:00
|
|
|
let license = &line[f + 1..l];
|
2016-12-11 00:27:42 +01:00
|
|
|
license.into()
|
|
|
|
} else {
|
|
|
|
"bad-license-parse".into()
|
|
|
|
}
|
|
|
|
}
|
2018-02-23 02:52:56 +01:00
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
/// Gets the dependencies of the crate at the given path using `cargo metadata`.
|
2018-02-27 06:45:04 +01:00
|
|
|
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
|
2019-01-11 17:32:31 +01:00
|
|
|
// Run `cargo metadata` to get the set of dependencies.
|
2018-02-26 18:05:43 +01:00
|
|
|
let output = Command::new(cargo)
|
2018-02-23 02:52:56 +01:00
|
|
|
.arg("metadata")
|
|
|
|
.arg("--format-version")
|
|
|
|
.arg("1")
|
|
|
|
.arg("--manifest-path")
|
2018-08-22 04:50:46 +02:00
|
|
|
.arg(path.join("../Cargo.toml"))
|
2018-02-23 02:52:56 +01:00
|
|
|
.output()
|
|
|
|
.expect("Unable to run `cargo metadata`")
|
|
|
|
.stdout;
|
|
|
|
let output = String::from_utf8_lossy(&output);
|
|
|
|
let output: Output = serde_json::from_str(&output).unwrap();
|
|
|
|
|
2018-02-27 06:45:04 +01:00
|
|
|
output.resolve
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
|
|
|
|
/// the whitelist. Returns a list of illegal dependencies.
|
2019-03-01 10:14:09 +01:00
|
|
|
fn check_crate_whitelist<'a>(
|
|
|
|
whitelist: &'a HashSet<Crate<'_>>,
|
2018-02-27 06:45:04 +01:00
|
|
|
resolve: &'a Resolve,
|
2019-03-01 10:14:09 +01:00
|
|
|
visited: &mut BTreeSet<CrateVersion<'a>>,
|
2018-02-28 01:33:55 +01:00
|
|
|
krate: CrateVersion<'a>,
|
2018-02-28 23:28:30 +01:00
|
|
|
must_be_on_whitelist: bool,
|
2018-02-27 19:02:54 +01:00
|
|
|
) -> BTreeSet<Crate<'a>> {
|
2019-01-11 17:32:31 +01:00
|
|
|
// This will contain bad deps.
|
2018-02-27 19:02:54 +01:00
|
|
|
let mut unapproved = BTreeSet::new();
|
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
// Check if we have already visited this crate.
|
2018-02-27 19:02:54 +01:00
|
|
|
if visited.contains(&krate) {
|
|
|
|
return unapproved;
|
|
|
|
}
|
|
|
|
|
|
|
|
visited.insert(krate);
|
2018-02-27 06:45:04 +01:00
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
// If this path is in-tree, we don't require it to be on the whitelist.
|
2018-02-28 23:28:30 +01:00
|
|
|
if must_be_on_whitelist {
|
2019-01-11 17:32:31 +01:00
|
|
|
// If this dependency is not on `WHITELIST`, add to bad set.
|
2018-02-28 23:28:30 +01:00
|
|
|
if !whitelist.contains(&krate.into()) {
|
|
|
|
unapproved.insert(krate.into());
|
|
|
|
}
|
2018-02-27 06:45:04 +01:00
|
|
|
}
|
|
|
|
|
2019-01-11 17:32:31 +01:00
|
|
|
// Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!).
|
2018-02-27 06:45:04 +01:00
|
|
|
let to_check = resolve
|
|
|
|
.nodes
|
|
|
|
.iter()
|
|
|
|
.find(|n| n.id.starts_with(&krate.id_str()))
|
|
|
|
.expect("crate does not exist");
|
|
|
|
|
|
|
|
for dep in to_check.dependencies.iter() {
|
2018-02-28 21:12:15 +01:00
|
|
|
let (krate, is_path_dep) = CrateVersion::from_str(dep);
|
2018-02-27 06:45:04 +01:00
|
|
|
|
2018-02-28 23:28:30 +01:00
|
|
|
let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
|
|
|
|
unapproved.append(&mut bad);
|
2018-02-27 06:45:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
unapproved
|
2018-02-23 02:52:56 +01:00
|
|
|
}
|
2018-08-08 08:09:36 +02:00
|
|
|
|
|
|
|
fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) {
|
|
|
|
const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
|
2019-01-11 17:32:31 +01:00
|
|
|
// These two crates take quite a long time to build, so don't allow two versions of them
|
|
|
|
// to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
|
|
|
|
// under control.
|
2019-03-01 15:06:14 +01:00
|
|
|
"cargo",
|
2018-08-09 06:42:26 +02:00
|
|
|
"rustc-ap-syntax",
|
2018-08-08 08:09:36 +02:00
|
|
|
];
|
2018-07-21 21:43:31 +02:00
|
|
|
let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new();
|
2018-08-08 08:09:36 +02:00
|
|
|
for node in resolve.nodes.iter() {
|
2019-12-22 23:42:04 +01:00
|
|
|
name_to_id.entry(node.id.split_whitespace().next().unwrap()).or_default().push(&node.id);
|
2018-08-08 08:09:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for name in FORBIDDEN_TO_HAVE_DUPLICATES {
|
|
|
|
if name_to_id[name].len() <= 1 {
|
2019-12-22 23:42:04 +01:00
|
|
|
continue;
|
2018-08-08 08:09:36 +02:00
|
|
|
}
|
|
|
|
println!("crate `{}` is duplicated in `Cargo.lock`", name);
|
|
|
|
for id in name_to_id[name].iter() {
|
|
|
|
println!(" * {}", id);
|
|
|
|
}
|
|
|
|
*bad = true;
|
|
|
|
}
|
|
|
|
}
|