Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions src/cargo/ops/cargo_output_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ pub fn output_metadata(ws: &Workspace,
fn metadata_no_deps(ws: &Workspace,
_opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
Ok(ExportInfo {
packages: vec![try!(ws.current()).clone()],
packages: ws.members().cloned().collect(),
workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
resolve: None,
version: VERSION,
})
Expand All @@ -53,28 +54,36 @@ fn metadata_full(ws: &Workspace,

Ok(ExportInfo {
packages: packages,
resolve: Some(MetadataResolve(resolve, try!(ws.current()).package_id().clone())),
workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
resolve: Some(MetadataResolve{
resolve: resolve,
root: ws.current_opt().map(|pkg| pkg.package_id().clone()),
}),
version: VERSION,
})
}

#[derive(RustcEncodable)]
pub struct ExportInfo {
packages: Vec<Package>,
workspace_members: Vec<PackageId>,
resolve: Option<MetadataResolve>,
version: u32,
}

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

impl Encodable for MetadataResolve {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
#[derive(RustcEncodable)]
struct EncodableResolve<'a> {
root: &'a PackageId,
root: Option<&'a PackageId>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change is backwards compatible, because root would be null only in those cases, where previously cargo metadata did not work at all.

nodes: Vec<Node<'a>>,
}

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

let resolve = &self.0;
let root = &self.1;
let encodable = EncodableResolve {
root: root,
nodes: resolve.iter().map(|id| {
root: self.root.as_ref(),
nodes: self.resolve.iter().map(|id| {
Node {
id: id,
dependencies: resolve.deps(id).collect(),
dependencies: self.resolve.deps(id).collect(),
}
}).collect(),
};
Expand Down
19 changes: 8 additions & 11 deletions src/cargo/ops/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,18 @@ pub fn resolve_with_previous<'a>(registry: &mut PackageRegistry,
.clone()]));

// If we're resolving everything then we include all members of the
// workspace. If we want a specific set of requirements then we only
// resolve the main crate as it's the only one we're compiling. This
// workspace. If we want a specific set of requirements and we're
// compiling only a single workspace crate then resolve only it. This
// case should only happen after we have a previous resolution, however,
// so assert that the previous exists.
let method = match method {
Method::Everything => Method::Everything,
Method::Required { .. } => {
assert!(previous.is_some());
if member.package_id() == try!(ws.current()).package_id() {
method
} else {
continue
if let Method::Required { .. } = method {
assert!(previous.is_some());
if let Some(current) = ws.current_opt() {
if member.package_id() != current.package_id() {
continue;
}
}
};
}

// If we don't have a previous instance of resolve then we just need to
// resolve our entire summary (method should be Everything) and we just
Expand Down
127 changes: 126 additions & 1 deletion tests/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ extern crate hamcrest;

use hamcrest::assert_that;
use cargotest::support::registry::Package;
use cargotest::support::{project, execs, basic_bin_manifest, main_file};
use cargotest::support::{project, execs, basic_bin_manifest, basic_lib_manifest, main_file};

#[test]
fn cargo_metadata_simple() {
Expand Down Expand Up @@ -32,6 +32,7 @@ fn cargo_metadata_simple() {
"manifest_path": "[..]Cargo.toml"
}
],
"workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
"resolve": {
"nodes": [
{
Expand Down Expand Up @@ -149,6 +150,7 @@ fn cargo_metadata_with_deps_and_version() {
"version": "0.5.0"
}
],
"workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
"resolve": {
"nodes": [
{
Expand All @@ -174,6 +176,128 @@ fn cargo_metadata_with_deps_and_version() {
}"#));
}

#[test]
fn workspace_metadata() {
let p = project("foo")
.file("Cargo.toml", r#"
[workspace]
members = ["bar", "baz"]
"#)
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
.file("bar/src/lib.rs", "")
.file("baz/Cargo.toml", &basic_lib_manifest("baz"))
.file("baz/src/lib.rs", "");
p.build();

assert_that(p.cargo_process("metadata"), execs().with_status(0).with_json(r#"
{
"packages": [
{
"name": "bar",
"version": "0.5.0",
"id": "bar[..]",
"source": null,
"dependencies": [],
"targets": [
{
"kind": [ "lib" ],
"name": "bar",
"src_path": "[..]bar[..]src[..]lib.rs"
}
],
"features": {},
"manifest_path": "[..]bar[..]Cargo.toml"
},
{
"name": "baz",
"version": "0.5.0",
"id": "baz[..]",
"source": null,
"dependencies": [],
"targets": [
{
"kind": [ "lib" ],
"name": "baz",
"src_path": "[..]baz[..]src[..]lib.rs"
}
],
"features": {},
"manifest_path": "[..]baz[..]Cargo.toml"
}
],
"workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
"resolve": {
"nodes": [
{
"dependencies": [],
"id": "baz 0.5.0 (path+file:[..]baz)"
},
{
"dependencies": [],
"id": "bar 0.5.0 (path+file:[..]bar)"
}
],
"root": null
},
"version": 1
}"#))
}

#[test]
fn workspace_metadata_no_deps() {
let p = project("foo")
.file("Cargo.toml", r#"
[workspace]
members = ["bar", "baz"]
"#)
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
.file("bar/src/lib.rs", "")
.file("baz/Cargo.toml", &basic_lib_manifest("baz"))
.file("baz/src/lib.rs", "");
p.build();

assert_that(p.cargo_process("metadata").arg("--no-deps"), execs().with_status(0).with_json(r#"
{
"packages": [
{
"name": "bar",
"version": "0.5.0",
"id": "bar[..]",
"source": null,
"dependencies": [],
"targets": [
{
"kind": [ "lib" ],
"name": "bar",
"src_path": "[..]bar[..]src[..]lib.rs"
}
],
"features": {},
"manifest_path": "[..]bar[..]Cargo.toml"
},
{
"name": "baz",
"version": "0.5.0",
"id": "baz[..]",
"source": null,
"dependencies": [],
"targets": [
{
"kind": [ "lib" ],
"name": "baz",
"src_path": "[..]baz[..]src[..]lib.rs"
}
],
"features": {},
"manifest_path": "[..]baz[..]Cargo.toml"
}
],
"workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
"resolve": null,
"version": 1
}"#))
}

#[test]
fn cargo_metadata_with_invalid_manifest() {
let p = project("foo")
Expand Down Expand Up @@ -204,6 +328,7 @@ const MANIFEST_OUTPUT: &'static str=
"features":{},
"manifest_path":"[..]Cargo.toml"
}],
"workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ],
"resolve": null,
"version": 1
}"#;
Expand Down