|
13 | 13 | //! This file implements the various regression test suites that we execute on
|
14 | 14 | //! our CI.
|
15 | 15 |
|
| 16 | +use std::collections::{HashMap, HashSet}; |
16 | 17 | use std::env;
|
17 |
| -use std::fs::{self, File}; |
18 |
| -use std::io::prelude::*; |
| 18 | +use std::fs; |
19 | 19 | use std::path::{PathBuf, Path};
|
20 | 20 | use std::process::Command;
|
21 | 21 |
|
22 | 22 | use build_helper::output;
|
| 23 | +use rustc_serialize::json; |
23 | 24 |
|
24 | 25 | use {Build, Compiler, Mode};
|
25 | 26 | use util::{self, dylib_path, dylib_path_var};
|
26 | 27 |
|
27 | 28 | const ADB_TEST_DIR: &'static str = "/data/tmp";
|
28 | 29 |
|
| 30 | +#[derive(RustcDecodable)] |
| 31 | +struct Output { |
| 32 | + packages: Vec<Package>, |
| 33 | + resolve: Resolve, |
| 34 | +} |
| 35 | + |
| 36 | +#[derive(RustcDecodable)] |
| 37 | +struct Package { |
| 38 | + id: String, |
| 39 | + name: String, |
| 40 | + source: Option<String>, |
| 41 | +} |
| 42 | + |
| 43 | +#[derive(RustcDecodable)] |
| 44 | +struct Resolve { |
| 45 | + nodes: Vec<ResolveNode>, |
| 46 | +} |
| 47 | + |
| 48 | +#[derive(RustcDecodable)] |
| 49 | +struct ResolveNode { |
| 50 | + id: String, |
| 51 | + dependencies: Vec<String>, |
| 52 | +} |
| 53 | + |
29 | 54 | /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
|
30 | 55 | ///
|
31 | 56 | /// This tool in `src/tools` will verify the validity of all our links in the
|
@@ -263,90 +288,74 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
|
263 | 288 | /// It essentially is the driver for running `cargo test`.
|
264 | 289 | ///
|
265 | 290 | /// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
|
266 |
| -/// arguments, and those arguments are discovered from `Cargo.lock`. |
| 291 | +/// arguments, and those arguments are discovered from `cargo metadata`. |
267 | 292 | pub fn krate(build: &Build,
|
268 | 293 | compiler: &Compiler,
|
269 | 294 | target: &str,
|
270 | 295 | mode: Mode) {
|
271 |
| - let (name, path, features, excluded) = match mode { |
| 296 | + let (name, path, features, root) = match mode { |
272 | 297 | Mode::Libstd => {
|
273 |
| - let excluded = vec![ |
274 |
| - "alloc_jemalloc", "arena", "bootstrap", "cargotest", "compiletest", |
275 |
| - "error_index_generator", "flate", "fmt_macros", "getopts", "graphviz", |
276 |
| - "linkchecker", "log", "proc_macro", "rbml", "rustbook", "rustc", "rustc-main", |
277 |
| - "rustc_back", "rustc_bitflags", "rustc_borrowck", "rustc_const_eval", |
278 |
| - "rustc_const_math", "rustc_data_structures", "rustc_driver", "rustc_errors", |
279 |
| - "rustc_incremental", "rustc_lint", "rustc_llvm", "rustc_metadata", "rustc_mir", |
280 |
| - "rustc_passes", "rustc_platform_intrinsics", "rustc_plugin", "rustc_privacy", |
281 |
| - "rustc_resolve", "rustc_save_analysis", "rustc_trans", "rustc_typeck", "rustdoc", |
282 |
| - "serialize", "syntax", "syntax_ext", "syntax_pos", "term", "test", "test_shim", |
283 |
| - "tidy", "unwind", |
284 |
| - ]; |
285 |
| - ("libstd", "src/rustc/std_shim", build.std_features(), excluded) |
| 298 | + ("libstd", "src/rustc/std_shim", build.std_features(), "std_shim") |
286 | 299 | }
|
287 | 300 | Mode::Libtest => {
|
288 |
| - let excluded = vec![ |
289 |
| - "alloc", "alloc_jemalloc", "alloc_system", "arena", "bootstrap", "build_helper", |
290 |
| - "cargotest", "collections", "compiletest", "core", "error_index_generator", |
291 |
| - "flate", "fmt_macros", "graphviz", "libc", "linkchecker", "log", "panic_abort", |
292 |
| - "panic_unwind", "proc_macro", "rand", "rbml", "rustbook", "rustc", "rustc-main", |
293 |
| - "rustc_back", "rustc_bitflags", "rustc_borrowck", "rustc_const_eval", |
294 |
| - "rustc_const_math", "rustc_data_structures", "rustc_driver", "rustc_errors", |
295 |
| - "rustc_incremental", "rustc_lint", "rustc_llvm", "rustc_metadata", "rustc_mir", |
296 |
| - "rustc_passes", "rustc_platform_intrinsics", "rustc_plugin", "rustc_privacy", |
297 |
| - "rustc_resolve", "rustc_save_analysis", "rustc_trans", "rustc_typeck", |
298 |
| - "rustc_unicode", "rustdoc", "serialize", "std", "std_shim", "syntax", "syntax_ext", |
299 |
| - "syntax_pos", "tidy", "unwind", |
300 |
| - ]; |
301 |
| - ("libtest", "src/rustc/test_shim", String::new(), excluded) |
| 301 | + ("libtest", "src/rustc/test_shim", String::new(), "test_shim") |
302 | 302 | }
|
303 | 303 | Mode::Librustc => {
|
304 |
| - let excluded = vec![ |
305 |
| - "alloc", "alloc_jemalloc", "alloc_system", "bootstrap", "cargotest", "collections", |
306 |
| - "compiletest", "core", "error_index_generator", "getopts", "libc", "linkchecker", |
307 |
| - "panic_abort", "panic_unwind", "rand", "rustbook", "rustc_unicode", "std", |
308 |
| - "std_shim", "term", "test", "test_shim", "tidy", "unwind", |
309 |
| - ]; |
310 |
| - ("librustc", "src/rustc", build.rustc_features(), excluded) |
| 304 | + ("librustc", "src/rustc", build.rustc_features(), "rustc-main") |
311 | 305 | }
|
312 | 306 | _ => panic!("can only test libraries"),
|
313 | 307 | };
|
314 | 308 | println!("Testing {} stage{} ({} -> {})", name, compiler.stage,
|
315 | 309 | compiler.host, target);
|
316 | 310 |
|
| 311 | + // Run `cargo metadata` to figure out what crates we're testing. |
| 312 | + // |
| 313 | + // Down below we're going to call `cargo test`, but to test the right set |
| 314 | + // of packages we're going to have to know what `-p` arguments to pass it |
| 315 | + // to know what crates to test. Here we run `cargo metadata` to learn about |
| 316 | + // the dependency graph and what `-p` arguments there are. |
| 317 | + let mut cargo = Command::new(&build.cargo); |
| 318 | + cargo.arg("metadata") |
| 319 | + .arg("--manifest-path").arg(build.src.join(path).join("Cargo.toml")); |
| 320 | + let output = output(&mut cargo); |
| 321 | + let output: Output = json::decode(&output).unwrap(); |
| 322 | + let id2pkg = output.packages.iter() |
| 323 | + .map(|pkg| (&pkg.id, pkg)) |
| 324 | + .collect::<HashMap<_, _>>(); |
| 325 | + let id2deps = output.resolve.nodes.iter() |
| 326 | + .map(|node| (&node.id, &node.dependencies)) |
| 327 | + .collect::<HashMap<_, _>>(); |
| 328 | + |
317 | 329 | // Build up the base `cargo test` command.
|
| 330 | + // |
| 331 | + // Pass in some standard flags then iterate over the graph we've discovered |
| 332 | + // in `cargo metadata` with the maps above and figure out what `-p` |
| 333 | + // arguments need to get passed. |
318 | 334 | let mut cargo = build.cargo(compiler, mode, target, "test");
|
319 | 335 | cargo.arg("--manifest-path")
|
320 | 336 | .arg(build.src.join(path).join("Cargo.toml"))
|
321 | 337 | .arg("--features").arg(features);
|
322 | 338 |
|
323 |
| - // Generate a list of `-p` arguments to pass to the `cargo test` invocation |
324 |
| - // by crawling the corresponding Cargo.lock file. |
325 |
| - let lockfile = build.src.join("src").join("Cargo.lock"); |
326 |
| - let mut contents = String::new(); |
327 |
| - t!(t!(File::open(&lockfile)).read_to_string(&mut contents)); |
328 |
| - let mut lines = contents.lines(); |
329 |
| - while let Some(line) = lines.next() { |
330 |
| - let prefix = "name = \""; |
331 |
| - if !line.starts_with(prefix) { |
| 339 | + let mut visited = HashSet::new(); |
| 340 | + let root_pkg = output.packages.iter().find(|p| p.name == root).unwrap(); |
| 341 | + let mut next = vec![&root_pkg.id]; |
| 342 | + while let Some(id) = next.pop() { |
| 343 | + // Skip any packages with sources listed, as these come from crates.io |
| 344 | + // and we shouldn't be testing them. |
| 345 | + if id2pkg[id].source.is_some() { |
332 | 346 | continue
|
333 | 347 | }
|
334 |
| - lines.next(); // skip `version = ...` |
335 |
| - |
336 |
| - // skip crates.io or otherwise non-path crates |
337 |
| - if let Some(line) = lines.next() { |
338 |
| - if line.starts_with("source") { |
339 |
| - continue |
340 |
| - } |
| 348 | + // Right now jemalloc is our only target-specific crate in the sense |
| 349 | + // that it's not present on all platforms. Custom skip it here for now, |
| 350 | + // but if we add more this probably wants to get more generalized. |
| 351 | + if !id.contains("jemalloc") { |
| 352 | + cargo.arg("-p").arg(&id2pkg[id].name); |
341 | 353 | }
|
342 |
| - |
343 |
| - let crate_name = &line[prefix.len()..line.len() - 1]; |
344 |
| - |
345 |
| - if excluded.contains(&crate_name) { |
346 |
| - continue |
| 354 | + for dep in id2deps[id] { |
| 355 | + if visited.insert(dep) { |
| 356 | + next.push(dep); |
| 357 | + } |
347 | 358 | }
|
348 |
| - |
349 |
| - cargo.arg("-p").arg(crate_name); |
350 | 359 | }
|
351 | 360 |
|
352 | 361 | // The tests are going to run with the *target* libraries, so we need to
|
|
0 commit comments