diff --git a/src/bin/cargo/commands/metadata.rs b/src/bin/cargo/commands/metadata.rs index a6deee86717..68eb6cad48a 100644 --- a/src/bin/cargo/commands/metadata.rs +++ b/src/bin/cargo/commands/metadata.rs @@ -12,6 +12,13 @@ pub fn cli() -> App { ) .arg(opt("quiet", "No output printed to stdout").short("q")) .arg_features() + .arg( + opt( + "filter-platform", + "Only include resolve dependencies matching the given target-triple", + ) + .value_name("TRIPLE"), + ) .arg(opt( "no-deps", "Output information only about the root package \ @@ -44,6 +51,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { all_features: args.is_present("all-features"), no_default_features: args.is_present("no-default-features"), no_deps: args.is_present("no-deps"), + filter_platform: args.value_of("filter-platform").map(|s| s.to_string()), version, }; diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index 8c60712283f..a6b64a69260 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -1,14 +1,13 @@ -use std::collections::HashMap; -use std::path::PathBuf; - -use serde::ser; -use serde::Serialize; - +use crate::core::compiler::{CompileKind, CompileTarget, TargetInfo}; use crate::core::resolver::{Resolve, ResolveOpts}; use crate::core::{Package, PackageId, Workspace}; use crate::ops::{self, Packages}; use crate::util::CargoResult; +use serde::Serialize; +use std::collections::HashMap; +use std::path::PathBuf; + const VERSION: u32 = 1; pub struct OutputMetadataOptions { @@ -17,6 +16,7 @@ pub struct OutputMetadataOptions { pub all_features: bool, pub no_deps: bool, pub version: u32, + pub filter_platform: Option, } /// Loads the manifest, resolves the dependencies of the package to the concrete @@ -30,54 +30,33 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo VERSION ); } - if opt.no_deps { - metadata_no_deps(ws, opt) + let (packages, resolve) = if opt.no_deps { + let packages = ws.members().cloned().collect(); + (packages, None) } else { - metadata_full(ws, opt) - } -} - -fn metadata_no_deps(ws: &Workspace<'_>, _opt: &OutputMetadataOptions) -> CargoResult { - Ok(ExportInfo { - packages: ws.members().cloned().collect(), - workspace_members: ws.members().map(|pkg| pkg.package_id()).collect(), - resolve: None, - target_directory: ws.target_dir().into_path_unlocked(), - version: VERSION, - workspace_root: ws.root().to_path_buf(), - }) -} - -fn metadata_full(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> CargoResult { - let specs = Packages::All.to_package_id_specs(ws)?; - let opts = ResolveOpts::new( - /*dev_deps*/ true, - &opt.features, - opt.all_features, - !opt.no_default_features, - ); - let ws_resolve = ops::resolve_ws_with_opts(ws, opts, &specs)?; - let mut packages = HashMap::new(); - for pkg in ws_resolve - .pkg_set - .get_many(ws_resolve.pkg_set.package_ids())? - { - packages.insert(pkg.package_id(), pkg.clone()); - } + let resolve_opts = ResolveOpts::new( + /*dev_deps*/ true, + &opt.features, + opt.all_features, + !opt.no_default_features, + ); + let (packages, resolve) = build_resolve_graph(ws, resolve_opts, &opt.filter_platform)?; + (packages, Some(resolve)) + }; Ok(ExportInfo { - packages: packages.values().map(|p| (*p).clone()).collect(), + packages, workspace_members: ws.members().map(|pkg| pkg.package_id()).collect(), - resolve: Some(MetadataResolve { - resolve: (packages, ws_resolve.targeted_resolve), - root: ws.current_opt().map(|pkg| pkg.package_id()), - }), + resolve, target_directory: ws.target_dir().into_path_unlocked(), version: VERSION, workspace_root: ws.root().to_path_buf(), }) } +/// This is the structure that is serialized and displayed to the user. +/// +/// See cargo-metadata.adoc for detailed documentation of the format. #[derive(Serialize)] pub struct ExportInfo { packages: Vec, @@ -88,52 +67,124 @@ pub struct ExportInfo { workspace_root: PathBuf, } -/// Newtype wrapper to provide a custom `Serialize` implementation. -/// The one from lock file does not fit because it uses a non-standard -/// format for `PackageId`s #[derive(Serialize)] struct MetadataResolve { - #[serde(rename = "nodes", serialize_with = "serialize_resolve")] - resolve: (HashMap, Resolve), + nodes: Vec, root: Option, } -fn serialize_resolve( - (packages, resolve): &(HashMap, Resolve), - s: S, -) -> Result -where - S: ser::Serializer, -{ - #[derive(Serialize)] - struct Dep { - name: String, - pkg: PackageId, - } +#[derive(Serialize)] +struct MetadataResolveNode { + id: PackageId, + dependencies: Vec, + deps: Vec, + features: Vec, +} - #[derive(Serialize)] - struct Node<'a> { - id: PackageId, - dependencies: Vec, - deps: Vec, - features: Vec<&'a str>, - } +#[derive(Serialize)] +struct Dep { + name: String, + pkg: PackageId, +} - s.collect_seq(resolve.iter().map(|id| { - Node { - id, - dependencies: resolve.deps(id).map(|(pkg, _deps)| pkg).collect(), - deps: resolve - .deps(id) - .filter_map(|(pkg, _deps)| { - packages - .get(&pkg) - .and_then(|pkg| pkg.targets().iter().find(|t| t.is_lib())) - .and_then(|lib_target| resolve.extern_crate_name(id, pkg, lib_target).ok()) - .map(|name| Dep { name, pkg }) - }) - .collect(), - features: resolve.features_sorted(id), +/// Builds the resolve graph as it will be displayed to the user. +fn build_resolve_graph( + ws: &Workspace<'_>, + resolve_opts: ResolveOpts, + target: &Option, +) -> CargoResult<(Vec, MetadataResolve)> { + let target_info = match target { + Some(target) => { + let config = ws.config(); + let ct = CompileTarget::new(target)?; + let short_name = ct.short_name().to_string(); + let kind = CompileKind::Target(ct); + let rustc = config.load_global_rustc(Some(ws))?; + Some((short_name, TargetInfo::new(config, kind, &rustc, kind)?)) } - })) + None => None, + }; + // Resolve entire workspace. + let specs = Packages::All.to_package_id_specs(ws)?; + let ws_resolve = ops::resolve_ws_with_opts(ws, resolve_opts, &specs)?; + // Download all Packages. This is needed to serialize the information + // for every package. In theory this could honor target filtering, + // but that would be somewhat complex. + let mut package_map: HashMap = ws_resolve + .pkg_set + .get_many(ws_resolve.pkg_set.package_ids())? + .into_iter() + .map(|pkg| (pkg.package_id(), pkg.clone())) + .collect(); + // Start from the workspace roots, and recurse through filling out the + // map, filtering targets as necessary. + let mut node_map = HashMap::new(); + for member_pkg in ws.members() { + build_resolve_graph_r( + &mut node_map, + member_pkg.package_id(), + &ws_resolve.targeted_resolve, + &package_map, + target_info.as_ref(), + ); + } + // Get a Vec of Packages. + let actual_packages = package_map + .drain() + .filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg)) + .collect(); + let mr = MetadataResolve { + nodes: node_map.drain().map(|(_pkg_id, node)| node).collect(), + root: ws.current_opt().map(|pkg| pkg.package_id()), + }; + Ok((actual_packages, mr)) +} + +fn build_resolve_graph_r( + node_map: &mut HashMap, + pkg_id: PackageId, + resolve: &Resolve, + package_map: &HashMap, + target: Option<&(String, TargetInfo)>, +) { + if node_map.contains_key(&pkg_id) { + return; + } + let features = resolve + .features_sorted(pkg_id) + .into_iter() + .map(|s| s.to_string()) + .collect(); + let deps: Vec = resolve + .deps(pkg_id) + .filter(|(_dep_id, deps)| match target { + Some((short_name, info)) => deps.iter().any(|dep| { + let platform = match dep.platform() { + Some(p) => p, + None => return true, + }; + platform.matches(short_name, info.cfg()) + }), + None => true, + }) + .filter_map(|(dep_id, _deps)| { + package_map + .get(&dep_id) + .and_then(|pkg| pkg.targets().iter().find(|t| t.is_lib())) + .and_then(|lib_target| resolve.extern_crate_name(pkg_id, dep_id, lib_target).ok()) + .map(|name| Dep { name, pkg: dep_id }) + }) + .collect(); + let dumb_deps: Vec = deps.iter().map(|dep| dep.pkg).collect(); + let to_visit = dumb_deps.clone(); + let node = MetadataResolveNode { + id: pkg_id, + dependencies: dumb_deps, + deps, + features, + }; + node_map.insert(pkg_id, node); + for dep_id in to_visit { + build_resolve_graph_r(node_map, dep_id, resolve, package_map, target); + } } diff --git a/src/doc/man/cargo-metadata.adoc b/src/doc/man/cargo-metadata.adoc index 906cb999e8f..45bd3b73736 100644 --- a/src/doc/man/cargo-metadata.adoc +++ b/src/doc/man/cargo-metadata.adoc @@ -202,6 +202,9 @@ The output has the following format: /* The resolved dependency graph, with the concrete versions and features selected. The set depends on the enabled features. This is null if --no-deps is specified. + By default, this includes all dependencies for all target platforms. + The `--filter-platform` flag may be used to narrow to a specific + target triple. */ "resolve": { /* Array of nodes within the dependency graph. @@ -265,6 +268,14 @@ The output has the following format: Specify the version of the output format to use. Currently `1` is the only possible value. +*--filter-platform* _TRIPLE_:: + This filters the `resolve` output to only include dependencies for the + given target triple. Without this flag, the resolve includes all targets. ++ +Note that the dependencies listed in the "packages" array still includes all +dependencies. Each package definition is intended to be an unaltered +reproduction of the information within `Cargo.toml`. + include::options-features.adoc[] === Display Options diff --git a/src/doc/man/generated/cargo-metadata.html b/src/doc/man/generated/cargo-metadata.html index 892e652a845..7530f323a9f 100644 --- a/src/doc/man/generated/cargo-metadata.html +++ b/src/doc/man/generated/cargo-metadata.html @@ -209,6 +209,9 @@

OUTPUT FORMAT

/* The resolved dependency graph, with the concrete versions and features selected. The set depends on the enabled features. This is null if --no-deps is specified. + By default, this includes all dependencies for all target platforms. + The `--filter-platform` flag may be used to narrow to a specific + target triple. */ "resolve": { /* Array of nodes within the dependency graph. @@ -279,6 +282,16 @@

Output Options

Specify the version of the output format to use. Currently 1 is the only possible value.

+
--filter-platform TRIPLE
+
+

This filters the resolve output to only include dependencies for the +given target triple. Without this flag, the resolve includes all targets.

+
+

Note that the dependencies listed in the "packages" array still includes all +dependencies. Each package definition is intended to be an unaltered +reproduction of the information within Cargo.toml.

+
+
diff --git a/src/etc/man/cargo-metadata.1 b/src/etc/man/cargo-metadata.1 index 924c599b9dd..7ab6f89bca2 100644 --- a/src/etc/man/cargo-metadata.1 +++ b/src/etc/man/cargo-metadata.1 @@ -2,12 +2,12 @@ .\" Title: cargo-metadata .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.10 -.\" Date: 2019-09-17 +.\" Date: 2019-10-28 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "CARGO\-METADATA" "1" "2019-09-17" "\ \&" "\ \&" +.TH "CARGO\-METADATA" "1" "2019-10-28" "\ \&" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -223,6 +223,9 @@ The output has the following format: /* The resolved dependency graph, with the concrete versions and features selected. The set depends on the enabled features. This is null if \-\-no\-deps is specified. + By default, this includes all dependencies for all target platforms. + The `\-\-filter\-platform` flag may be used to narrow to a specific + target triple. */ "resolve": { /* Array of nodes within the dependency graph. @@ -288,6 +291,16 @@ dependencies. Specify the version of the output format to use. Currently \fB1\fP is the only possible value. .RE +.sp +\fB\-\-filter\-platform\fP \fITRIPLE\fP +.RS 4 +This filters the \fBresolve\fP output to only include dependencies for the +given target triple. Without this flag, the resolve includes all targets. +.sp +Note that the dependencies listed in the "packages" array still includes all +dependencies. Each package definition is intended to be an unaltered +reproduction of the information within \fBCargo.toml\fP. +.RE .SS "Feature Selection" .sp When no feature options are given, the \fBdefault\fP feature is activated for diff --git a/tests/testsuite/metadata.rs b/tests/testsuite/metadata.rs index ef37256a0ea..d56c70e00f9 100644 --- a/tests/testsuite/metadata.rs +++ b/tests/testsuite/metadata.rs @@ -1,5 +1,6 @@ +use cargo_test_support::cross_compile::alternate; use cargo_test_support::registry::Package; -use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, main_file, project}; +use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, main_file, project, rustc_host}; #[cargo_test] fn cargo_metadata_simple() { @@ -1794,13 +1795,629 @@ fn deps_with_bin_only() { .file("bdep/src/main.rs", "fn main() {}") .build(); - let output = p - .cargo("metadata") - .exec_with_output() - .expect("cargo metadata failed"); - let stdout = std::str::from_utf8(&output.stdout).unwrap(); - let meta: serde_json::Value = serde_json::from_str(stdout).expect("failed to parse json"); - let nodes = &meta["resolve"]["nodes"]; - assert!(nodes[0]["deps"].as_array().unwrap().is_empty()); - assert!(nodes[1]["deps"].as_array().unwrap().is_empty()); + p.cargo("metadata") + .with_json( + r#" +{ + "packages": [ + { + "name": "foo", + "version": "0.1.0", + "id": "foo 0.1.0 ([..])", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [ + { + "name": "bdep", + "source": null, + "req": "*", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "foo", + "src_path": "[..]/foo/src/lib.rs", + "edition": "2015", + "doctest": true + } + ], + "features": {}, + "manifest_path": "[..]/foo/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "edition": "2015", + "links": null + } + ], + "workspace_members": [ + "foo 0.1.0 ([..])" + ], + "resolve": { + "nodes": [ + { + "id": "foo 0.1.0 ([..])", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "foo 0.1.0 ([..])" + }, + "target_directory": "[..]/foo/target", + "version": 1, + "workspace_root": "[..]foo" +} +"#, + ) + .run(); +} + +#[cargo_test] +fn filter_platform() { + // Testing the --filter-platform flag. + Package::new("normal-dep", "0.0.1").publish(); + Package::new("host-dep", "0.0.1").publish(); + Package::new("alt-dep", "0.0.1").publish(); + Package::new("cfg-dep", "0.0.1").publish(); + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + normal-dep = "0.0.1" + + [target.{}.dependencies] + host-dep = "0.0.1" + + [target.{}.dependencies] + alt-dep = "0.0.1" + + [target.'cfg(foobar)'.dependencies] + cfg-dep = "0.0.1" + "#, + rustc_host(), + alternate() + ), + ) + .file("src/lib.rs", "") + .build(); + + let alt_dep = r#" + { + "name": "alt-dep", + "version": "0.0.1", + "id": "alt-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": null, + "license_file": null, + "description": null, + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "alt-dep", + "src_path": "[..]/alt-dep-0.0.1/src/lib.rs", + "edition": "2015", + "doctest": true + } + ], + "features": {}, + "manifest_path": "[..]/alt-dep-0.0.1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "edition": "2015", + "links": null + }, + "#; + + let cfg_dep = r#" + { + "name": "cfg-dep", + "version": "0.0.1", + "id": "cfg-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": null, + "license_file": null, + "description": null, + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "cfg-dep", + "src_path": "[..]/cfg-dep-0.0.1/src/lib.rs", + "edition": "2015", + "doctest": true + } + ], + "features": {}, + "manifest_path": "[..]/cfg-dep-0.0.1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "edition": "2015", + "links": null + }, + "#; + + let host_dep = r#" + { + "name": "host-dep", + "version": "0.0.1", + "id": "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": null, + "license_file": null, + "description": null, + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "host-dep", + "src_path": "[..]/host-dep-0.0.1/src/lib.rs", + "edition": "2015", + "doctest": true + } + ], + "features": {}, + "manifest_path": "[..]/host-dep-0.0.1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "edition": "2015", + "links": null + }, + "#; + + let normal_dep = r#" + { + "name": "normal-dep", + "version": "0.0.1", + "id": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": null, + "license_file": null, + "description": null, + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "normal-dep", + "src_path": "[..]/normal-dep-0.0.1/src/lib.rs", + "edition": "2015", + "doctest": true + } + ], + "features": {}, + "manifest_path": "[..]/normal-dep-0.0.1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "edition": "2015", + "links": null + }, + "#; + + let foo = r#" + { + "name": "foo", + "version": "0.1.0", + "id": "foo 0.1.0 (path+file:[..]foo)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [ + { + "name": "normal-dep", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.0.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "cfg-dep", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.0.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(foobar)", + "registry": null + }, + { + "name": "alt-dep", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.0.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "$ALT", + "registry": null + }, + { + "name": "host-dep", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.0.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "$HOST", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "foo", + "src_path": "[..]/foo/src/lib.rs", + "edition": "2015", + "doctest": true + } + ], + "features": {}, + "manifest_path": "[..]/foo/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "edition": "2015", + "links": null + } + "# + .replace("$ALT", &alternate()) + .replace("$HOST", &rustc_host()); + + // Normal metadata, no filtering, returns *everything*. + p.cargo("metadata") + .with_json( + &r#" +{ + "packages": [ + $ALT_DEP + $CFG_DEP + $HOST_DEP + $NORMAL_DEP + $FOO + ], + "workspace_members": [ + "foo 0.1.0 (path+file:[..]foo)" + ], + "resolve": { + "nodes": [ + { + "id": "alt-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "cfg-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "foo 0.1.0 (path+file:[..]foo)", + "dependencies": [ + "alt-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "alt_dep", + "pkg": "alt-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + }, + { + "name": "cfg_dep", + "pkg": "cfg-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + }, + { + "name": "host_dep", + "pkg": "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + }, + { + "name": "normal_dep", + "pkg": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + } + ], + "features": [] + }, + { + "id": "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "foo 0.1.0 (path+file:[..]foo)" + }, + "target_directory": "[..]/foo/target", + "version": 1, + "workspace_root": "[..]/foo" +} +"# + .replace("$ALT_DEP", alt_dep) + .replace("$CFG_DEP", cfg_dep) + .replace("$HOST_DEP", host_dep) + .replace("$NORMAL_DEP", normal_dep) + .replace("$FOO", &foo), + ) + .run(); + + // Filter on alternate, removes cfg and host. + p.cargo("metadata --filter-platform") + .arg(alternate()) + .with_json( + &r#" +{ + "packages": [ + $ALT_DEP + $NORMAL_DEP + $FOO + ], + "workspace_members": "{...}", + "resolve": { + "nodes": [ + { + "id": "alt-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "foo 0.1.0 (path+file:[..]foo)", + "dependencies": [ + "alt-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "alt_dep", + "pkg": "alt-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + }, + { + "name": "normal_dep", + "pkg": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + } + ], + "features": [] + }, + { + "id": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "foo 0.1.0 (path+file:[..]foo)" + }, + "target_directory": "[..]foo/target", + "version": 1, + "workspace_root": "[..]foo" +} +"# + .replace("$ALT_DEP", alt_dep) + .replace("$NORMAL_DEP", normal_dep) + .replace("$FOO", &foo), + ) + .run(); + + // Filter on host, removes alt and cfg. + p.cargo("metadata --filter-platform") + .arg(rustc_host()) + .with_json( + &r#" +{ + "packages": [ + $HOST_DEP + $NORMAL_DEP + $FOO + ], + "workspace_members": "{...}", + "resolve": { + "nodes": [ + { + "id": "foo 0.1.0 (path+file:[..]foo)", + "dependencies": [ + "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "host_dep", + "pkg": "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + }, + { + "name": "normal_dep", + "pkg": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + } + ], + "features": [] + }, + { + "id": "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "foo 0.1.0 (path+file:[..]foo)" + }, + "target_directory": "[..]foo/target", + "version": 1, + "workspace_root": "[..]foo" +} +"# + .replace("$HOST_DEP", host_dep) + .replace("$NORMAL_DEP", normal_dep) + .replace("$FOO", &foo), + ) + .run(); + + // Filter host with cfg, removes alt only + p.cargo("metadata --filter-platform") + .arg(rustc_host()) + .env("RUSTFLAGS", "--cfg=foobar") + .with_json( + &r#" +{ + "packages": [ + $CFG_DEP + $HOST_DEP + $NORMAL_DEP + $FOO + ], + "workspace_members": "{...}", + "resolve": { + "nodes": [ + { + "id": "cfg-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "foo 0.1.0 (path+file:[..]/foo)", + "dependencies": [ + "cfg-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cfg_dep", + "pkg": "cfg-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + }, + { + "name": "host_dep", + "pkg": "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + }, + { + "name": "normal_dep", + "pkg": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" + } + ], + "features": [] + }, + { + "id": "host-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "normal-dep 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "foo 0.1.0 (path+file:[..]/foo)" + }, + "target_directory": "[..]/foo/target", + "version": 1, + "workspace_root": "[..]/foo" +} +"# + .replace("$CFG_DEP", cfg_dep) + .replace("$HOST_DEP", host_dep) + .replace("$NORMAL_DEP", normal_dep) + .replace("$FOO", &foo), + ) + .run(); }