Skip to content

Commit 5b521f6

Browse files
committed
Add --filter-platform to cargo metadata.
1 parent a2f4906 commit 5b521f6

File tree

3 files changed

+637
-52
lines changed

3 files changed

+637
-52
lines changed

src/bin/cargo/commands/metadata.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ pub fn cli() -> App {
1212
)
1313
.arg(opt("quiet", "No output printed to stdout").short("q"))
1414
.arg_features()
15+
.arg(
16+
opt(
17+
"filter-platform",
18+
"Only include resolve dependencies matching the given target-triple \
19+
(\"host\" for current host)",
20+
)
21+
.value_name("TRIPLE"),
22+
)
1523
.arg(opt(
1624
"no-deps",
1725
"Output information only about the root package \
@@ -44,6 +52,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
4452
all_features: args.is_present("all-features"),
4553
no_default_features: args.is_present("no-default-features"),
4654
no_deps: args.is_present("no-deps"),
55+
filter_platform: args.value_of("filter-platform").map(|s| s.to_string()),
4756
version,
4857
};
4958

src/cargo/ops/cargo_output_metadata.rs

Lines changed: 96 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
use std::collections::HashMap;
2-
use std::path::PathBuf;
3-
4-
use serde::ser;
5-
use serde::Serialize;
6-
1+
use crate::core::compiler::{CompileKind, CompileTarget, TargetInfo};
72
use crate::core::resolver::{Resolve, ResolveOpts};
8-
use crate::core::{Package, PackageId, Workspace};
3+
use crate::core::{Dependency, Package, PackageId, Workspace};
94
use crate::ops::{self, Packages};
105
use crate::util::CargoResult;
6+
use cargo_platform::Cfg;
7+
use serde::ser;
8+
use serde::Serialize;
9+
use std::collections::HashMap;
10+
use std::path::PathBuf;
1111

1212
const VERSION: u32 = 1;
1313

@@ -17,6 +17,7 @@ pub struct OutputMetadataOptions {
1717
pub all_features: bool,
1818
pub no_deps: bool,
1919
pub version: u32,
20+
pub filter_platform: Option<String>,
2021
}
2122

2223
/// Loads the manifest, resolves the dependencies of the package to the concrete
@@ -30,48 +31,63 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo
3031
VERSION
3132
);
3233
}
33-
if opt.no_deps {
34-
metadata_no_deps(ws, opt)
34+
let (packages, resolve) = if opt.no_deps {
35+
let packages = ws.members().cloned().collect();
36+
(packages, None)
3537
} else {
36-
metadata_full(ws, opt)
37-
}
38-
}
39-
40-
fn metadata_no_deps(ws: &Workspace<'_>, _opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
41-
Ok(ExportInfo {
42-
packages: ws.members().cloned().collect(),
43-
workspace_members: ws.members().map(|pkg| pkg.package_id()).collect(),
44-
resolve: None,
45-
target_directory: ws.target_dir().into_path_unlocked(),
46-
version: VERSION,
47-
workspace_root: ws.root().to_path_buf(),
48-
})
49-
}
50-
51-
fn metadata_full(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
52-
let specs = Packages::All.to_package_id_specs(ws)?;
53-
let opts = ResolveOpts::new(
54-
/*dev_deps*/ true,
55-
&opt.features,
56-
opt.all_features,
57-
!opt.no_default_features,
58-
);
59-
let ws_resolve = ops::resolve_ws_with_opts(ws, opts, &specs)?;
60-
let mut packages = HashMap::new();
61-
for pkg in ws_resolve
62-
.pkg_set
63-
.get_many(ws_resolve.pkg_set.package_ids())?
64-
{
65-
packages.insert(pkg.package_id(), pkg.clone());
66-
}
38+
let specs = Packages::All.to_package_id_specs(ws)?;
39+
let opts = ResolveOpts::new(
40+
/*dev_deps*/ true,
41+
&opt.features,
42+
opt.all_features,
43+
!opt.no_default_features,
44+
);
45+
let ws_resolve = ops::resolve_ws_with_opts(ws, opts, &specs)?;
46+
let mut package_map = HashMap::new();
47+
for pkg in ws_resolve
48+
.pkg_set
49+
.get_many(ws_resolve.pkg_set.package_ids())?
50+
{
51+
package_map.insert(pkg.package_id(), pkg.clone());
52+
}
53+
let packages = package_map.values().map(|p| (*p).clone()).collect();
54+
let rustc = ws.config().load_global_rustc(Some(ws))?;
55+
let (target, cfg) = match &opt.filter_platform {
56+
Some(platform) => {
57+
if platform == "host" {
58+
let ti =
59+
TargetInfo::new(ws.config(), CompileKind::Host, &rustc, CompileKind::Host)?;
60+
(
61+
Some(rustc.host.as_str().to_string()),
62+
Some(ti.cfg().iter().cloned().collect()),
63+
)
64+
} else {
65+
let kind = CompileKind::Target(CompileTarget::new(platform)?);
66+
let ti = TargetInfo::new(ws.config(), kind, &rustc, kind)?;
67+
(
68+
Some(platform.clone()),
69+
Some(ti.cfg().iter().cloned().collect()),
70+
)
71+
}
72+
}
73+
None => (None, None),
74+
};
75+
let resolve = Some(MetadataResolve {
76+
helper: ResolveHelper {
77+
packages: package_map,
78+
resolve: ws_resolve.targeted_resolve,
79+
target,
80+
cfg,
81+
},
82+
root: ws.current_opt().map(|pkg| pkg.package_id()),
83+
});
84+
(packages, resolve)
85+
};
6786

6887
Ok(ExportInfo {
69-
packages: packages.values().map(|p| (*p).clone()).collect(),
88+
packages,
7089
workspace_members: ws.members().map(|pkg| pkg.package_id()).collect(),
71-
resolve: Some(MetadataResolve {
72-
resolve: (packages, ws_resolve.targeted_resolve),
73-
root: ws.current_opt().map(|pkg| pkg.package_id()),
74-
}),
90+
resolve,
7591
target_directory: ws.target_dir().into_path_unlocked(),
7692
version: VERSION,
7793
workspace_root: ws.root().to_path_buf(),
@@ -94,17 +110,28 @@ pub struct ExportInfo {
94110
#[derive(Serialize)]
95111
struct MetadataResolve {
96112
#[serde(rename = "nodes", serialize_with = "serialize_resolve")]
97-
resolve: (HashMap<PackageId, Package>, Resolve),
113+
helper: ResolveHelper,
98114
root: Option<PackageId>,
99115
}
100116

101-
fn serialize_resolve<S>(
102-
(packages, resolve): &(HashMap<PackageId, Package>, Resolve),
103-
s: S,
104-
) -> Result<S::Ok, S::Error>
117+
struct ResolveHelper {
118+
packages: HashMap<PackageId, Package>,
119+
resolve: Resolve,
120+
target: Option<String>,
121+
cfg: Option<Vec<Cfg>>,
122+
}
123+
124+
fn serialize_resolve<S>(helper: &ResolveHelper, s: S) -> Result<S::Ok, S::Error>
105125
where
106126
S: ser::Serializer,
107127
{
128+
let ResolveHelper {
129+
packages,
130+
resolve,
131+
target,
132+
cfg,
133+
} = helper;
134+
108135
#[derive(Serialize)]
109136
struct Dep {
110137
name: String,
@@ -119,12 +146,30 @@ where
119146
features: Vec<&'a str>,
120147
}
121148

149+
// A filter for removing platform dependencies.
150+
let dep_filter = |(_pkg, deps): &(PackageId, &[Dependency])| match (target, cfg) {
151+
(Some(target), Some(cfg)) => deps.iter().any(|dep| {
152+
let platform = match dep.platform() {
153+
Some(p) => p,
154+
None => return true,
155+
};
156+
platform.matches(target, cfg)
157+
}),
158+
(None, None) => true,
159+
_ => unreachable!(),
160+
};
161+
122162
s.collect_seq(resolve.iter().map(|id| {
123163
Node {
124164
id,
125-
dependencies: resolve.deps(id).map(|(pkg, _deps)| pkg).collect(),
165+
dependencies: resolve
166+
.deps(id)
167+
.filter(dep_filter)
168+
.map(|(pkg, _deps)| pkg)
169+
.collect(),
126170
deps: resolve
127171
.deps(id)
172+
.filter(dep_filter)
128173
.filter_map(|(pkg, _deps)| {
129174
packages
130175
.get(&pkg)

0 commit comments

Comments
 (0)