Skip to content

Commit

Permalink
Auto merge of #3051 - matklad:ws-metadata, r=alexcrichton
Browse files Browse the repository at this point in the history
`cargo metadata` works with workspaces

Closes #3003
  • Loading branch information
bors committed Aug 28, 2016
2 parents 88e46e9 + 578c1a1 commit eff0a95
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 21 deletions.
25 changes: 16 additions & 9 deletions src/cargo/ops/cargo_output_metadata.rs
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>,
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
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
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

0 comments on commit eff0a95

Please sign in to comment.