|
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,56 +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) = match mode { |
272 |
| - Mode::Libstd => ("libstd", "src/rustc/std_shim", build.std_features()), |
273 |
| - Mode::Libtest => ("libtest", "src/rustc/test_shim", String::new()), |
274 |
| - Mode::Librustc => ("librustc", "src/rustc", build.rustc_features()), |
| 296 | + let (name, path, features, root) = match mode { |
| 297 | + Mode::Libstd => { |
| 298 | + ("libstd", "src/rustc/std_shim", build.std_features(), "std_shim") |
| 299 | + } |
| 300 | + Mode::Libtest => { |
| 301 | + ("libtest", "src/rustc/test_shim", String::new(), "test_shim") |
| 302 | + } |
| 303 | + Mode::Librustc => { |
| 304 | + ("librustc", "src/rustc", build.rustc_features(), "rustc-main") |
| 305 | + } |
275 | 306 | _ => panic!("can only test libraries"),
|
276 | 307 | };
|
277 | 308 | println!("Testing {} stage{} ({} -> {})", name, compiler.stage,
|
278 | 309 | compiler.host, target);
|
279 | 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 | + |
280 | 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. |
281 | 334 | let mut cargo = build.cargo(compiler, mode, target, "test");
|
282 | 335 | cargo.arg("--manifest-path")
|
283 | 336 | .arg(build.src.join(path).join("Cargo.toml"))
|
284 | 337 | .arg("--features").arg(features);
|
285 | 338 |
|
286 |
| - // Generate a list of `-p` arguments to pass to the `cargo test` invocation |
287 |
| - // by crawling the corresponding Cargo.lock file. |
288 |
| - let lockfile = build.src.join(path).join("Cargo.lock"); |
289 |
| - let mut contents = String::new(); |
290 |
| - t!(t!(File::open(&lockfile)).read_to_string(&mut contents)); |
291 |
| - let mut lines = contents.lines(); |
292 |
| - while let Some(line) = lines.next() { |
293 |
| - let prefix = "name = \""; |
294 |
| - 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() { |
295 | 346 | continue
|
296 | 347 | }
|
297 |
| - lines.next(); // skip `version = ...` |
298 |
| - |
299 |
| - // skip crates.io or otherwise non-path crates |
300 |
| - if let Some(line) = lines.next() { |
301 |
| - if line.starts_with("source") { |
302 |
| - continue |
303 |
| - } |
304 |
| - } |
305 |
| - |
306 |
| - let crate_name = &line[prefix.len()..line.len() - 1]; |
307 |
| - |
308 | 348 | // Right now jemalloc is our only target-specific crate in the sense
|
309 | 349 | // that it's not present on all platforms. Custom skip it here for now,
|
310 | 350 | // but if we add more this probably wants to get more generalized.
|
311 |
| - if crate_name.contains("jemalloc") { |
312 |
| - continue |
| 351 | + if !id.contains("jemalloc") { |
| 352 | + cargo.arg("-p").arg(&id2pkg[id].name); |
| 353 | + } |
| 354 | + for dep in id2deps[id] { |
| 355 | + if visited.insert(dep) { |
| 356 | + next.push(dep); |
| 357 | + } |
313 | 358 | }
|
314 |
| - |
315 |
| - cargo.arg("-p").arg(crate_name); |
316 | 359 | }
|
317 | 360 |
|
318 | 361 | // The tests are going to run with the *target* libraries, so we need to
|
|
0 commit comments