Skip to content

Commit f67349c

Browse files
committed
Auto merge of #5871 - matklad:meta-rename, r=alexcrichton
Meta rename Some work towards #5583 Previously, `cargo metadata` exposed dependencies info as a graph of package id without any additional information on edges. However, we do want to add some data to edges, including for example, package renames and `cfg` info. Internally, the edges info is represented as a `Vec<Dependnecy>`. We could have exposed that directly, but that risks exposing and ossifying an implementation details. So instead we collapse a `Vec<Dependnecy>` to a single JSON object, which at the moment contains `id` and `rename` info only. It should be possible to add additional fields to that object backwards compatibly. Such representation does not correspond directly to any internal Cargo data structure, but hopefully it shouldn't be to hard to maintain. This representation also does not quite correspond to the "real world", where dependencies are between crate (cargo targets), and not packages. However, because each dep edge is a JSON object, adding a target filter should be possible, which would handle dev-, build-, and potential future bin-specific dependencies backwards-compatibly.
2 parents 97a988e + 39b1f75 commit f67349c

File tree

4 files changed

+276
-41
lines changed

4 files changed

+276
-41
lines changed

src/cargo/core/compiler/build_context/mod.rs

+1-23
Original file line numberDiff line numberDiff line change
@@ -92,29 +92,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
9292
}
9393

9494
pub fn extern_crate_name(&self, unit: &Unit<'a>, dep: &Unit<'a>) -> CargoResult<String> {
95-
let deps = {
96-
let a = unit.pkg.package_id();
97-
let b = dep.pkg.package_id();
98-
if a == b {
99-
&[]
100-
} else {
101-
self.resolve.dependencies_listed(a, b)
102-
}
103-
};
104-
105-
let crate_name = dep.target.crate_name();
106-
let mut names = deps.iter()
107-
.map(|d| d.rename().map(|s| s.as_str()).unwrap_or(&crate_name));
108-
let name = names.next().unwrap_or(&crate_name);
109-
for n in names {
110-
if n == name {
111-
continue
112-
}
113-
bail!("multiple dependencies listed for the same crate must \
114-
all have the same name, but the dependency on `{}` \
115-
is listed as having different names", dep.pkg.package_id());
116-
}
117-
Ok(name.to_string())
95+
self.resolve.extern_crate_name(unit.pkg.package_id(), dep.pkg.package_id(), dep.target)
11896
}
11997

12098
/// Whether a dependency should be compiled for the host or target platform,

src/cargo/core/resolver/resolve.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::iter::FromIterator;
44

55
use url::Url;
66

7-
use core::{Dependency, PackageId, PackageIdSpec, Summary};
7+
use core::{Dependency, PackageId, PackageIdSpec, Summary, Target};
88
use util::Graph;
99
use util::errors::CargoResult;
1010
use util::graph::{Edges, Nodes};
@@ -213,7 +213,34 @@ unable to verify that `{0}` is the same as when the lockfile was generated
213213
&self.metadata
214214
}
215215

216-
pub fn dependencies_listed(&self, from: &PackageId, to: &PackageId) -> &[Dependency] {
216+
pub fn extern_crate_name(
217+
&self,
218+
from: &PackageId,
219+
to: &PackageId,
220+
to_target: &Target,
221+
) -> CargoResult<String> {
222+
let deps = if from == to {
223+
&[]
224+
} else {
225+
self.dependencies_listed(from, to)
226+
};
227+
228+
let crate_name = to_target.crate_name();
229+
let mut names = deps.iter()
230+
.map(|d| d.rename().map(|s| s.as_str()).unwrap_or(&crate_name));
231+
let name = names.next().unwrap_or(&crate_name);
232+
for n in names {
233+
if n == name {
234+
continue
235+
}
236+
bail!("multiple dependencies listed for the same crate must \
237+
all have the same name, but the dependency on `{}` \
238+
is listed as having different names", to);
239+
}
240+
Ok(name.to_string())
241+
}
242+
243+
fn dependencies_listed(&self, from: &PackageId, to: &PackageId) -> &[Dependency] {
217244
// We've got a dependency on `from` to `to`, but this dependency edge
218245
// may be affected by [replace]. If the `to` package is listed as the
219246
// target of a replacement (aka the key of a reverse replacement map)

src/cargo/ops/cargo_output_metadata.rs

+32-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use serde::ser;
22

33
use core::resolver::Resolve;
4-
use core::{Package, PackageId, Workspace};
4+
use core::{Package, PackageId, Workspace, PackageSet};
55
use ops::{self, Packages};
66
use util::CargoResult;
77

@@ -18,7 +18,7 @@ pub struct OutputMetadataOptions {
1818
/// Loads the manifest, resolves the dependencies of the project to the concrete
1919
/// used versions - considering overrides - and writes all dependencies in a JSON
2020
/// format to stdout.
21-
pub fn output_metadata(ws: &Workspace, opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
21+
pub fn output_metadata<'a>(ws: &'a Workspace, opt: &OutputMetadataOptions) -> CargoResult<ExportInfo<'a>> {
2222
if opt.version != VERSION {
2323
bail!(
2424
"metadata version {} not supported, only {} is currently supported",
@@ -33,7 +33,7 @@ pub fn output_metadata(ws: &Workspace, opt: &OutputMetadataOptions) -> CargoResu
3333
}
3434
}
3535

36-
fn metadata_no_deps(ws: &Workspace, _opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
36+
fn metadata_no_deps<'a>(ws: &'a Workspace, _opt: &OutputMetadataOptions) -> CargoResult<ExportInfo<'a>> {
3737
Ok(ExportInfo {
3838
packages: ws.members().cloned().collect(),
3939
workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
@@ -44,7 +44,7 @@ fn metadata_no_deps(ws: &Workspace, _opt: &OutputMetadataOptions) -> CargoResult
4444
})
4545
}
4646

47-
fn metadata_full(ws: &Workspace, opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
47+
fn metadata_full<'a>(ws: &'a Workspace, opt: &OutputMetadataOptions) -> CargoResult<ExportInfo<'a>> {
4848
let specs = Packages::All.to_package_id_specs(ws)?;
4949
let deps = ops::resolve_ws_precisely(
5050
ws,
@@ -54,18 +54,18 @@ fn metadata_full(ws: &Workspace, opt: &OutputMetadataOptions) -> CargoResult<Exp
5454
opt.no_default_features,
5555
&specs,
5656
)?;
57-
let (packages, resolve) = deps;
57+
let (package_set, resolve) = deps;
5858

59-
let packages = packages
59+
let packages = package_set
6060
.package_ids()
61-
.map(|i| packages.get(i).map(|p| p.clone()))
61+
.map(|i| package_set.get(i).map(|p| p.clone()))
6262
.collect::<CargoResult<Vec<_>>>()?;
6363

6464
Ok(ExportInfo {
6565
packages,
6666
workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
6767
resolve: Some(MetadataResolve {
68-
resolve,
68+
resolve: (package_set, resolve),
6969
root: ws.current_opt().map(|pkg| pkg.package_id().clone()),
7070
}),
7171
target_directory: ws.target_dir().display().to_string(),
@@ -75,10 +75,10 @@ fn metadata_full(ws: &Workspace, opt: &OutputMetadataOptions) -> CargoResult<Exp
7575
}
7676

7777
#[derive(Serialize)]
78-
pub struct ExportInfo {
78+
pub struct ExportInfo<'a> {
7979
packages: Vec<Package>,
8080
workspace_members: Vec<PackageId>,
81-
resolve: Option<MetadataResolve>,
81+
resolve: Option<MetadataResolve<'a>>,
8282
target_directory: String,
8383
version: u32,
8484
workspace_root: String,
@@ -88,28 +88,46 @@ pub struct ExportInfo {
8888
/// The one from lockfile does not fit because it uses a non-standard
8989
/// format for `PackageId`s
9090
#[derive(Serialize)]
91-
struct MetadataResolve {
91+
struct MetadataResolve<'a> {
9292
#[serde(rename = "nodes", serialize_with = "serialize_resolve")]
93-
resolve: Resolve,
93+
resolve: (PackageSet<'a>, Resolve),
9494
root: Option<PackageId>,
9595
}
9696

97-
fn serialize_resolve<S>(resolve: &Resolve, s: S) -> Result<S::Ok, S::Error>
97+
fn serialize_resolve<S>((package_set, resolve): &(PackageSet, Resolve), s: S) -> Result<S::Ok, S::Error>
9898
where
9999
S: ser::Serializer,
100100
{
101+
#[derive(Serialize)]
102+
struct Dep<'a> {
103+
name: Option<String>,
104+
pkg: &'a PackageId
105+
}
106+
101107
#[derive(Serialize)]
102108
struct Node<'a> {
103109
id: &'a PackageId,
104110
dependencies: Vec<&'a PackageId>,
111+
deps: Vec<Dep<'a>>,
105112
features: Vec<&'a str>,
106113
}
107114

108115
s.collect_seq(resolve
109116
.iter()
110117
.map(|id| Node {
111118
id,
112-
dependencies: resolve.deps(id).map(|p| p.0).collect(),
119+
dependencies: resolve.deps(id).map(|(pkg, _deps)| pkg).collect(),
120+
deps: resolve.deps(id)
121+
.map(|(pkg, _deps)| {
122+
let name = package_set.get(pkg).ok()
123+
.and_then(|pkg| pkg.targets().iter().find(|t| t.is_lib()))
124+
.and_then(|lib_target| {
125+
resolve.extern_crate_name(id, pkg, lib_target).ok()
126+
});
127+
128+
Dep { name, pkg }
129+
})
130+
.collect(),
113131
features: resolve.features_sorted(id),
114132
}))
115133
}

0 commit comments

Comments
 (0)