Skip to content

Commit eff0a95

Browse files
authored
Auto merge of #3051 - matklad:ws-metadata, r=alexcrichton
`cargo metadata` works with workspaces Closes #3003
2 parents 88e46e9 + 578c1a1 commit eff0a95

File tree

3 files changed

+150
-21
lines changed

3 files changed

+150
-21
lines changed

src/cargo/ops/cargo_output_metadata.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ pub fn output_metadata(ws: &Workspace,
3333
fn metadata_no_deps(ws: &Workspace,
3434
_opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
3535
Ok(ExportInfo {
36-
packages: vec![try!(ws.current()).clone()],
36+
packages: ws.members().cloned().collect(),
37+
workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
3738
resolve: None,
3839
version: VERSION,
3940
})
@@ -53,28 +54,36 @@ fn metadata_full(ws: &Workspace,
5354

5455
Ok(ExportInfo {
5556
packages: packages,
56-
resolve: Some(MetadataResolve(resolve, try!(ws.current()).package_id().clone())),
57+
workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
58+
resolve: Some(MetadataResolve{
59+
resolve: resolve,
60+
root: ws.current_opt().map(|pkg| pkg.package_id().clone()),
61+
}),
5762
version: VERSION,
5863
})
5964
}
6065

6166
#[derive(RustcEncodable)]
6267
pub struct ExportInfo {
6368
packages: Vec<Package>,
69+
workspace_members: Vec<PackageId>,
6470
resolve: Option<MetadataResolve>,
6571
version: u32,
6672
}
6773

6874
/// Newtype wrapper to provide a custom `Encodable` implementation.
6975
/// The one from lockfile does not fit because it uses a non-standard
7076
/// format for `PackageId`s
71-
struct MetadataResolve(Resolve, PackageId);
77+
struct MetadataResolve{
78+
resolve: Resolve,
79+
root: Option<PackageId>,
80+
}
7281

7382
impl Encodable for MetadataResolve {
7483
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
7584
#[derive(RustcEncodable)]
7685
struct EncodableResolve<'a> {
77-
root: &'a PackageId,
86+
root: Option<&'a PackageId>,
7887
nodes: Vec<Node<'a>>,
7988
}
8089

@@ -84,14 +93,12 @@ impl Encodable for MetadataResolve {
8493
dependencies: Vec<&'a PackageId>,
8594
}
8695

87-
let resolve = &self.0;
88-
let root = &self.1;
8996
let encodable = EncodableResolve {
90-
root: root,
91-
nodes: resolve.iter().map(|id| {
97+
root: self.root.as_ref(),
98+
nodes: self.resolve.iter().map(|id| {
9299
Node {
93100
id: id,
94-
dependencies: resolve.deps(id).collect(),
101+
dependencies: self.resolve.deps(id).collect(),
95102
}
96103
}).collect(),
97104
};

src/cargo/ops/resolve.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,18 @@ pub fn resolve_with_previous<'a>(registry: &mut PackageRegistry,
6060
.clone()]));
6161

6262
// If we're resolving everything then we include all members of the
63-
// workspace. If we want a specific set of requirements then we only
64-
// resolve the main crate as it's the only one we're compiling. This
63+
// workspace. If we want a specific set of requirements and we're
64+
// compiling only a single workspace crate then resolve only it. This
6565
// case should only happen after we have a previous resolution, however,
6666
// so assert that the previous exists.
67-
let method = match method {
68-
Method::Everything => Method::Everything,
69-
Method::Required { .. } => {
70-
assert!(previous.is_some());
71-
if member.package_id() == try!(ws.current()).package_id() {
72-
method
73-
} else {
74-
continue
67+
if let Method::Required { .. } = method {
68+
assert!(previous.is_some());
69+
if let Some(current) = ws.current_opt() {
70+
if member.package_id() != current.package_id() {
71+
continue;
7572
}
7673
}
77-
};
74+
}
7875

7976
// If we don't have a previous instance of resolve then we just need to
8077
// resolve our entire summary (method should be Everything) and we just

tests/metadata.rs

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ extern crate hamcrest;
33

44
use hamcrest::assert_that;
55
use cargotest::support::registry::Package;
6-
use cargotest::support::{project, execs, basic_bin_manifest, main_file};
6+
use cargotest::support::{project, execs, basic_bin_manifest, basic_lib_manifest, main_file};
77

88
#[test]
99
fn cargo_metadata_simple() {
@@ -32,6 +32,7 @@ fn cargo_metadata_simple() {
3232
"manifest_path": "[..]Cargo.toml"
3333
}
3434
],
35+
"workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
3536
"resolve": {
3637
"nodes": [
3738
{
@@ -149,6 +150,7 @@ fn cargo_metadata_with_deps_and_version() {
149150
"version": "0.5.0"
150151
}
151152
],
153+
"workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
152154
"resolve": {
153155
"nodes": [
154156
{
@@ -174,6 +176,128 @@ fn cargo_metadata_with_deps_and_version() {
174176
}"#));
175177
}
176178

179+
#[test]
180+
fn workspace_metadata() {
181+
let p = project("foo")
182+
.file("Cargo.toml", r#"
183+
[workspace]
184+
members = ["bar", "baz"]
185+
"#)
186+
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
187+
.file("bar/src/lib.rs", "")
188+
.file("baz/Cargo.toml", &basic_lib_manifest("baz"))
189+
.file("baz/src/lib.rs", "");
190+
p.build();
191+
192+
assert_that(p.cargo_process("metadata"), execs().with_status(0).with_json(r#"
193+
{
194+
"packages": [
195+
{
196+
"name": "bar",
197+
"version": "0.5.0",
198+
"id": "bar[..]",
199+
"source": null,
200+
"dependencies": [],
201+
"targets": [
202+
{
203+
"kind": [ "lib" ],
204+
"name": "bar",
205+
"src_path": "[..]bar[..]src[..]lib.rs"
206+
}
207+
],
208+
"features": {},
209+
"manifest_path": "[..]bar[..]Cargo.toml"
210+
},
211+
{
212+
"name": "baz",
213+
"version": "0.5.0",
214+
"id": "baz[..]",
215+
"source": null,
216+
"dependencies": [],
217+
"targets": [
218+
{
219+
"kind": [ "lib" ],
220+
"name": "baz",
221+
"src_path": "[..]baz[..]src[..]lib.rs"
222+
}
223+
],
224+
"features": {},
225+
"manifest_path": "[..]baz[..]Cargo.toml"
226+
}
227+
],
228+
"workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
229+
"resolve": {
230+
"nodes": [
231+
{
232+
"dependencies": [],
233+
"id": "baz 0.5.0 (path+file:[..]baz)"
234+
},
235+
{
236+
"dependencies": [],
237+
"id": "bar 0.5.0 (path+file:[..]bar)"
238+
}
239+
],
240+
"root": null
241+
},
242+
"version": 1
243+
}"#))
244+
}
245+
246+
#[test]
247+
fn workspace_metadata_no_deps() {
248+
let p = project("foo")
249+
.file("Cargo.toml", r#"
250+
[workspace]
251+
members = ["bar", "baz"]
252+
"#)
253+
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
254+
.file("bar/src/lib.rs", "")
255+
.file("baz/Cargo.toml", &basic_lib_manifest("baz"))
256+
.file("baz/src/lib.rs", "");
257+
p.build();
258+
259+
assert_that(p.cargo_process("metadata").arg("--no-deps"), execs().with_status(0).with_json(r#"
260+
{
261+
"packages": [
262+
{
263+
"name": "bar",
264+
"version": "0.5.0",
265+
"id": "bar[..]",
266+
"source": null,
267+
"dependencies": [],
268+
"targets": [
269+
{
270+
"kind": [ "lib" ],
271+
"name": "bar",
272+
"src_path": "[..]bar[..]src[..]lib.rs"
273+
}
274+
],
275+
"features": {},
276+
"manifest_path": "[..]bar[..]Cargo.toml"
277+
},
278+
{
279+
"name": "baz",
280+
"version": "0.5.0",
281+
"id": "baz[..]",
282+
"source": null,
283+
"dependencies": [],
284+
"targets": [
285+
{
286+
"kind": [ "lib" ],
287+
"name": "baz",
288+
"src_path": "[..]baz[..]src[..]lib.rs"
289+
}
290+
],
291+
"features": {},
292+
"manifest_path": "[..]baz[..]Cargo.toml"
293+
}
294+
],
295+
"workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
296+
"resolve": null,
297+
"version": 1
298+
}"#))
299+
}
300+
177301
#[test]
178302
fn cargo_metadata_with_invalid_manifest() {
179303
let p = project("foo")
@@ -204,6 +328,7 @@ const MANIFEST_OUTPUT: &'static str=
204328
"features":{},
205329
"manifest_path":"[..]Cargo.toml"
206330
}],
331+
"workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ],
207332
"resolve": null,
208333
"version": 1
209334
}"#;

0 commit comments

Comments
 (0)