diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index bba4d65e8c3..597aefadcfe 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -7,12 +7,16 @@ use crate::cache::INTERNER; use crate::util::output; use crate::{Build, Crate}; -#[derive(Deserialize)] +/// For more information, see the output of +/// +#[derive(Debug, Deserialize)] struct Output { packages: Vec, } -#[derive(Deserialize)] +/// For more information, see the output of +/// +#[derive(Debug, Deserialize)] struct Package { name: String, source: Option, @@ -20,25 +24,18 @@ struct Package { dependencies: Vec, } -#[derive(Deserialize)] +/// For more information, see the output of +/// +#[derive(Debug, Deserialize)] struct Dependency { name: String, source: Option, } +/// Collects and stores package metadata of each workspace members into `build`, +/// by executing `cargo metadata` commands. pub fn build(build: &mut Build) { - // Run `cargo metadata` to figure out what crates we're testing. - let mut cargo = Command::new(&build.initial_cargo); - cargo - .arg("metadata") - .arg("--format-version") - .arg("1") - .arg("--no-deps") - .arg("--manifest-path") - .arg(build.src.join("Cargo.toml")); - let output = output(&mut cargo); - let output: Output = serde_json::from_str(&output).unwrap(); - for package in output.packages { + for package in workspace_members(build) { if package.source.is_none() { let name = INTERNER.intern_string(package.name); let mut path = PathBuf::from(package.manifest_path); @@ -57,3 +54,35 @@ pub fn build(build: &mut Build) { } } } + +/// Invokes `cargo metadata` to get package metadata of each workspace member. +/// +/// Note that `src/tools/cargo` is no longer a workspace member but we still +/// treat it as one here, by invoking an additional `cargo metadata` command. +fn workspace_members(build: &Build) -> impl Iterator { + let cmd_metadata = |manifest_path| { + let mut cargo = Command::new(&build.initial_cargo); + cargo + .arg("metadata") + .arg("--format-version") + .arg("1") + .arg("--no-deps") + .arg("--manifest-path") + .arg(manifest_path); + cargo + }; + + // Collects `metadata.packages` from the root workspace. + let root_manifest_path = build.src.join("Cargo.toml"); + let root_output = output(&mut cmd_metadata(&root_manifest_path)); + let Output { packages, .. } = serde_json::from_str(&root_output).unwrap(); + + // Collects `metadata.packages` from src/tools/cargo separately. + let cargo_manifest_path = build.src.join("src/tools/cargo/Cargo.toml"); + let cargo_output = output(&mut cmd_metadata(&cargo_manifest_path)); + let Output { packages: cargo_packages, .. } = serde_json::from_str(&cargo_output).unwrap(); + + // We only care about the root package from `src/tool/cargo` workspace. + let cargo_package = cargo_packages.into_iter().find(|pkg| pkg.name == "cargo").into_iter(); + packages.into_iter().chain(cargo_package) +}