Skip to content

Commit

Permalink
Auto merge of #5871 - matklad:meta-rename, r=alexcrichton
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Aug 7, 2018
2 parents 97a988e + 39b1f75 commit f67349c
Show file tree
Hide file tree
Showing 4 changed files with 276 additions and 41 deletions.
24 changes: 1 addition & 23 deletions src/cargo/core/compiler/build_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,29 +92,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
}

pub fn extern_crate_name(&self, unit: &Unit<'a>, dep: &Unit<'a>) -> CargoResult<String> {
let deps = {
let a = unit.pkg.package_id();
let b = dep.pkg.package_id();
if a == b {
&[]
} else {
self.resolve.dependencies_listed(a, b)
}
};

let crate_name = dep.target.crate_name();
let mut names = deps.iter()
.map(|d| d.rename().map(|s| s.as_str()).unwrap_or(&crate_name));
let name = names.next().unwrap_or(&crate_name);
for n in names {
if n == name {
continue
}
bail!("multiple dependencies listed for the same crate must \
all have the same name, but the dependency on `{}` \
is listed as having different names", dep.pkg.package_id());
}
Ok(name.to_string())
self.resolve.extern_crate_name(unit.pkg.package_id(), dep.pkg.package_id(), dep.target)
}

/// Whether a dependency should be compiled for the host or target platform,
Expand Down
31 changes: 29 additions & 2 deletions src/cargo/core/resolver/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::iter::FromIterator;

use url::Url;

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

pub fn dependencies_listed(&self, from: &PackageId, to: &PackageId) -> &[Dependency] {
pub fn extern_crate_name(
&self,
from: &PackageId,
to: &PackageId,
to_target: &Target,
) -> CargoResult<String> {
let deps = if from == to {
&[]
} else {
self.dependencies_listed(from, to)
};

let crate_name = to_target.crate_name();
let mut names = deps.iter()
.map(|d| d.rename().map(|s| s.as_str()).unwrap_or(&crate_name));
let name = names.next().unwrap_or(&crate_name);
for n in names {
if n == name {
continue
}
bail!("multiple dependencies listed for the same crate must \
all have the same name, but the dependency on `{}` \
is listed as having different names", to);
}
Ok(name.to_string())
}

fn dependencies_listed(&self, from: &PackageId, to: &PackageId) -> &[Dependency] {
// We've got a dependency on `from` to `to`, but this dependency edge
// may be affected by [replace]. If the `to` package is listed as the
// target of a replacement (aka the key of a reverse replacement map)
Expand Down
46 changes: 32 additions & 14 deletions src/cargo/ops/cargo_output_metadata.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::ser;

use core::resolver::Resolve;
use core::{Package, PackageId, Workspace};
use core::{Package, PackageId, Workspace, PackageSet};
use ops::{self, Packages};
use util::CargoResult;

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

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

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

let packages = packages
let packages = package_set
.package_ids()
.map(|i| packages.get(i).map(|p| p.clone()))
.map(|i| package_set.get(i).map(|p| p.clone()))
.collect::<CargoResult<Vec<_>>>()?;

Ok(ExportInfo {
packages,
workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
resolve: Some(MetadataResolve {
resolve,
resolve: (package_set, resolve),
root: ws.current_opt().map(|pkg| pkg.package_id().clone()),
}),
target_directory: ws.target_dir().display().to_string(),
Expand All @@ -75,10 +75,10 @@ fn metadata_full(ws: &Workspace, opt: &OutputMetadataOptions) -> CargoResult<Exp
}

#[derive(Serialize)]
pub struct ExportInfo {
pub struct ExportInfo<'a> {
packages: Vec<Package>,
workspace_members: Vec<PackageId>,
resolve: Option<MetadataResolve>,
resolve: Option<MetadataResolve<'a>>,
target_directory: String,
version: u32,
workspace_root: String,
Expand All @@ -88,28 +88,46 @@ pub struct ExportInfo {
/// The one from lockfile does not fit because it uses a non-standard
/// format for `PackageId`s
#[derive(Serialize)]
struct MetadataResolve {
struct MetadataResolve<'a> {
#[serde(rename = "nodes", serialize_with = "serialize_resolve")]
resolve: Resolve,
resolve: (PackageSet<'a>, Resolve),
root: Option<PackageId>,
}

fn serialize_resolve<S>(resolve: &Resolve, s: S) -> Result<S::Ok, S::Error>
fn serialize_resolve<S>((package_set, resolve): &(PackageSet, Resolve), s: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
#[derive(Serialize)]
struct Dep<'a> {
name: Option<String>,
pkg: &'a PackageId
}

#[derive(Serialize)]
struct Node<'a> {
id: &'a PackageId,
dependencies: Vec<&'a PackageId>,
deps: Vec<Dep<'a>>,
features: Vec<&'a str>,
}

s.collect_seq(resolve
.iter()
.map(|id| Node {
id,
dependencies: resolve.deps(id).map(|p| p.0).collect(),
dependencies: resolve.deps(id).map(|(pkg, _deps)| pkg).collect(),
deps: resolve.deps(id)
.map(|(pkg, _deps)| {
let name = package_set.get(pkg).ok()
.and_then(|pkg| pkg.targets().iter().find(|t| t.is_lib()))
.and_then(|lib_target| {
resolve.extern_crate_name(id, pkg, lib_target).ok()
});

Dep { name, pkg }
})
.collect(),
features: resolve.features_sorted(id),
}))
}
Loading

0 comments on commit f67349c

Please sign in to comment.