mirror of
https://github.com/rust-lang/cargo
synced 2024-09-13 04:51:31 +00:00
Add rename info to Cargo metadata
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.
This commit is contained in:
parent
2db5b45dcd
commit
39b1f752f6
|
@ -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;
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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(),
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
|
@ -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,
|
||||
|
@ -88,20 +88,27 @@ 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>,
|
||||
}
|
||||
|
||||
|
@ -109,7 +116,18 @@ where
|
|||
.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),
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ fn cargo_metadata_simple() {
|
|||
"nodes": [
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "foo 0.5.0 (path+file:[..]foo)"
|
||||
}
|
||||
|
@ -148,6 +149,7 @@ crate-type = ["lib", "staticlib"]
|
|||
"nodes": [
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "foo 0.5.0 (path+file:[..]foo)"
|
||||
}
|
||||
|
@ -231,6 +233,7 @@ optional_feat = []
|
|||
"nodes": [
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [
|
||||
"default",
|
||||
"default_feat"
|
||||
|
@ -411,6 +414,9 @@ fn cargo_metadata_with_deps_and_version() {
|
|||
"dependencies": [
|
||||
"bar 0.0.1 (registry+[..])"
|
||||
],
|
||||
"deps": [
|
||||
{ "name": "bar", "pkg": "bar 0.0.1 (registry+[..])" }
|
||||
],
|
||||
"features": [],
|
||||
"id": "foo 0.5.0 (path+file:[..]foo)"
|
||||
},
|
||||
|
@ -418,11 +424,15 @@ fn cargo_metadata_with_deps_and_version() {
|
|||
"dependencies": [
|
||||
"baz 0.0.1 (registry+[..])"
|
||||
],
|
||||
"deps": [
|
||||
{ "name": "baz", "pkg": "baz 0.0.1 (registry+[..])" }
|
||||
],
|
||||
"features": [],
|
||||
"id": "bar 0.0.1 (registry+[..])"
|
||||
},
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "baz 0.0.1 (registry+[..])"
|
||||
}
|
||||
|
@ -506,7 +516,8 @@ name = "ex"
|
|||
{
|
||||
"id": "foo 0.1.0 (path+file:[..]foo)",
|
||||
"features": [],
|
||||
"dependencies": []
|
||||
"dependencies": [],
|
||||
"deps": []
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -588,7 +599,8 @@ crate-type = ["rlib", "dylib"]
|
|||
{
|
||||
"id": "foo 0.1.0 (path+file:[..]foo)",
|
||||
"features": [],
|
||||
"dependencies": []
|
||||
"dependencies": [],
|
||||
"deps": []
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -688,11 +700,13 @@ fn workspace_metadata() {
|
|||
"nodes": [
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "baz 0.5.0 (path+file:[..]baz)"
|
||||
},
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "bar 0.5.0 (path+file:[..]bar)"
|
||||
}
|
||||
|
@ -1127,6 +1141,7 @@ fn cargo_metadata_path_to_cargo_toml_project() {
|
|||
"nodes": [
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "bar 0.5.0 ([..])"
|
||||
}
|
||||
|
@ -1207,6 +1222,7 @@ fn package_edition_2018() {
|
|||
"nodes": [
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "foo 0.1.0 (path+file:[..])"
|
||||
}
|
||||
|
@ -1302,6 +1318,7 @@ fn target_edition_2018() {
|
|||
"nodes": [
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "foo 0.1.0 (path+file:[..])"
|
||||
}
|
||||
|
@ -1319,3 +1336,198 @@ fn target_edition_2018() {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_dependency() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
Package::new("bar", "0.2.0").publish();
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
cargo-features = ["rename-dependency"]
|
||||
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0" }
|
||||
baz = { version = "0.2.0", package = "bar" }
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "extern crate bar; extern crate baz;")
|
||||
.build();
|
||||
|
||||
assert_that(
|
||||
p.cargo("metadata").masquerade_as_nightly_cargo(),
|
||||
execs().with_json(r#"
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"authors": [],
|
||||
"categories": [],
|
||||
"dependencies": [
|
||||
{
|
||||
"features": [],
|
||||
"kind": null,
|
||||
"name": "bar",
|
||||
"optional": false,
|
||||
"rename": null,
|
||||
"req": "^0.1.0",
|
||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||
"target": null,
|
||||
"uses_default_features": true
|
||||
},
|
||||
{
|
||||
"features": [],
|
||||
"kind": null,
|
||||
"name": "bar",
|
||||
"optional": false,
|
||||
"rename": "baz",
|
||||
"req": "^0.2.0",
|
||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||
"target": null,
|
||||
"uses_default_features": true
|
||||
}
|
||||
],
|
||||
"description": null,
|
||||
"edition": "2015",
|
||||
"features": {},
|
||||
"id": "foo 0.0.1[..]",
|
||||
"keywords": [],
|
||||
"license": null,
|
||||
"license_file": null,
|
||||
"manifest_path": "[..]",
|
||||
"metadata": null,
|
||||
"name": "foo",
|
||||
"readme": null,
|
||||
"repository": null,
|
||||
"source": null,
|
||||
"targets": [
|
||||
{
|
||||
"crate_types": [
|
||||
"lib"
|
||||
],
|
||||
"edition": "2015",
|
||||
"kind": [
|
||||
"lib"
|
||||
],
|
||||
"name": "foo",
|
||||
"src_path": "[..]"
|
||||
}
|
||||
],
|
||||
"version": "0.0.1"
|
||||
},
|
||||
{
|
||||
"authors": [],
|
||||
"categories": [],
|
||||
"dependencies": [],
|
||||
"description": null,
|
||||
"edition": "2015",
|
||||
"features": {},
|
||||
"id": "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keywords": [],
|
||||
"license": null,
|
||||
"license_file": null,
|
||||
"manifest_path": "[..]",
|
||||
"metadata": null,
|
||||
"name": "bar",
|
||||
"readme": null,
|
||||
"repository": null,
|
||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||
"targets": [
|
||||
{
|
||||
"crate_types": [
|
||||
"lib"
|
||||
],
|
||||
"edition": "2015",
|
||||
"kind": [
|
||||
"lib"
|
||||
],
|
||||
"name": "bar",
|
||||
"src_path": "[..]"
|
||||
}
|
||||
],
|
||||
"version": "0.1.0"
|
||||
},
|
||||
{
|
||||
"authors": [],
|
||||
"categories": [],
|
||||
"dependencies": [],
|
||||
"description": null,
|
||||
"edition": "2015",
|
||||
"features": {},
|
||||
"id": "bar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keywords": [],
|
||||
"license": null,
|
||||
"license_file": null,
|
||||
"manifest_path": "[..]",
|
||||
"metadata": null,
|
||||
"name": "bar",
|
||||
"readme": null,
|
||||
"repository": null,
|
||||
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||
"targets": [
|
||||
{
|
||||
"crate_types": [
|
||||
"lib"
|
||||
],
|
||||
"edition": "2015",
|
||||
"kind": [
|
||||
"lib"
|
||||
],
|
||||
"name": "bar",
|
||||
"src_path": "[..]"
|
||||
}
|
||||
],
|
||||
"version": "0.2.0"
|
||||
}
|
||||
],
|
||||
"resolve": {
|
||||
"nodes": [
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "bar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)"
|
||||
},
|
||||
{
|
||||
"dependencies": [],
|
||||
"deps": [],
|
||||
"features": [],
|
||||
"id": "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)"
|
||||
},
|
||||
{
|
||||
"dependencies": [
|
||||
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)"
|
||||
],
|
||||
"deps": [
|
||||
{
|
||||
"name": "bar",
|
||||
"pkg": "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)"
|
||||
},
|
||||
{
|
||||
"name": "baz",
|
||||
"pkg": "bar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)"
|
||||
}
|
||||
],
|
||||
"features": [],
|
||||
"id": "foo 0.0.1[..]"
|
||||
}
|
||||
],
|
||||
"root": "foo 0.0.1[..]"
|
||||
},
|
||||
"target_directory": "[..]",
|
||||
"version": 1,
|
||||
"workspace_members": [
|
||||
"foo 0.0.1[..]"
|
||||
],
|
||||
"workspace_root": "[..]"
|
||||
}"#,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue