Skip to content

Make cargo metadata --no-deps print all path deps (including other workspaces) #9024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
60 changes: 58 additions & 2 deletions src/cargo/ops/cargo_output_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ use crate::core::{Dependency, Package, PackageId, Workspace};
use crate::ops::{self, Packages};
use crate::util::interning::InternedString;
use crate::util::CargoResult;
use crate::Config;
use cargo_platform::Platform;
use serde::Serialize;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf;
use std::rc::Rc;

const VERSION: u32 = 1;

Expand All @@ -35,7 +37,10 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo
}
let config = ws.config();
let (packages, resolve) = if opt.no_deps {
let packages = ws.members().map(|pkg| pkg.serialized(config)).collect();
let packages = path_packages(ws)?
.into_iter()
.map(|pkg| pkg.serialized(config))
.collect();
(packages, None)
} else {
let (packages, resolve) = build_resolve_graph(ws, opt)?;
Expand Down Expand Up @@ -103,6 +108,57 @@ impl From<&Dependency> for DepKindInfo {
}
}

fn path_packages_r<'p, 'cfg: 'p>(
package: &'p Package,
config: &'cfg Config,
found: &mut BTreeSet<Package>,
workspace_cache: &mut BTreeMap<PathBuf, Rc<Workspace<'cfg>>>,
) -> CargoResult<()> {
if found.contains(package) {
return Ok(());
}
found.insert(package.clone());

for dependency in package.dependencies() {
let source_id = dependency.source_id();

if !source_id.is_path() {
continue;
}

if let Ok(mut path) = source_id.url().to_file_path() {
path.push("Cargo.toml");

let workspace = if let Some(workspace) = workspace_cache.get(&path) {
workspace
} else {
let workspace = Rc::new(Workspace::new(&path, config)?);
// Cache the workspace of every crate in this workspace, because Workspace::new
// does a full scan for members every time it's called, and so is slow.
for member in workspace.members() {
workspace_cache.insert(member.manifest_path().to_path_buf(), workspace.clone());
}
workspace_cache.get(&path).unwrap()
};

path_packages_r(&workspace.load(&path)?, config, found, workspace_cache)?;
}
}

Ok(())
}

fn path_packages(ws: &Workspace<'_>) -> CargoResult<BTreeSet<Package>> {
let mut found = BTreeSet::new();
let mut workspace_cache = BTreeMap::new();

for package in ws.members() {
path_packages_r(package, ws.config(), &mut found, &mut workspace_cache)?;
}

Ok(found)
}

/// Builds the resolve graph as it will be displayed to the user.
fn build_resolve_graph(
ws: &Workspace<'_>,
Expand Down
7 changes: 4 additions & 3 deletions src/doc/man/cargo-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ The output has the following format:
```javascript
{
/* Array of all packages in the workspace.
It also includes all feature-enabled dependencies unless --no-deps is used.
With --no-deps, includes all packages in local workspaces.
Otherwise, all packages in current workspace, and all feature-enabled dependencies.
*/
"packages": [
{
Expand Down Expand Up @@ -198,7 +199,7 @@ The output has the following format:
"links": null,
}
],
/* Array of members of the workspace.
/* Array of members of the current workspace.
Each entry is the Package ID for the package.
*/
"workspace_members": [
Expand Down Expand Up @@ -292,7 +293,7 @@ The output has the following format:
{{#options}}

{{#option "`--no-deps`" }}
Output information only about the workspace members and don't fetch
Output information only about the members of local workspaces and don't fetch
dependencies.
{{/option}}

Expand Down
9 changes: 5 additions & 4 deletions src/doc/man/generated_txt/cargo-metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ OUTPUT FORMAT

{
/* Array of all packages in the workspace.
It also includes all feature-enabled dependencies unless --no-deps is used.
With --no-deps, includes all packages in local workspaces.
Otherwise, all packages in current workspace, and all feature-enabled dependencies.
*/
"packages": [
{
Expand Down Expand Up @@ -193,7 +194,7 @@ OUTPUT FORMAT
"links": null,
}
],
/* Array of members of the workspace.
/* Array of members of the current workspace.
Each entry is the Package ID for the package.
*/
"workspace_members": [
Expand Down Expand Up @@ -282,8 +283,8 @@ OUTPUT FORMAT
OPTIONS
Output Options
--no-deps
Output information only about the workspace members and don't fetch
dependencies.
Output information only about the members of local workspaces and
don't fetch dependencies.

--format-version version
Specify the version of the output format to use. Currently 1 is the
Expand Down
7 changes: 4 additions & 3 deletions src/doc/src/commands/cargo-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ The output has the following format:
```javascript
{
/* Array of all packages in the workspace.
It also includes all feature-enabled dependencies unless --no-deps is used.
With --no-deps, includes all packages in local workspaces.
Otherwise, all packages in current workspace, and all feature-enabled dependencies.
*/
"packages": [
{
Expand Down Expand Up @@ -198,7 +199,7 @@ The output has the following format:
"links": null,
}
],
/* Array of members of the workspace.
/* Array of members of the current workspace.
Each entry is the Package ID for the package.
*/
"workspace_members": [
Expand Down Expand Up @@ -292,7 +293,7 @@ The output has the following format:
<dl>

<dt class="option-term" id="option-cargo-metadata---no-deps"><a class="option-anchor" href="#option-cargo-metadata---no-deps"></a><code>--no-deps</code></dt>
<dd class="option-desc">Output information only about the workspace members and don't fetch
<dd class="option-desc">Output information only about the members of local workspaces and don't fetch
dependencies.</dd>


Expand Down
7 changes: 4 additions & 3 deletions src/etc/man/cargo-metadata.1
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ The output has the following format:
.nf
{
/* Array of all packages in the workspace.
It also includes all feature\-enabled dependencies unless \-\-no\-deps is used.
With \-\-no\-deps, includes all packages in local workspaces.
Otherwise, all packages in current workspace, and all feature\-enabled dependencies.
*/
"packages": [
{
Expand Down Expand Up @@ -195,7 +196,7 @@ The output has the following format:
"links": null,
}
],
/* Array of members of the workspace.
/* Array of members of the current workspace.
Each entry is the Package ID for the package.
*/
"workspace_members": [
Expand Down Expand Up @@ -287,7 +288,7 @@ The output has the following format:
.sp
\fB\-\-no\-deps\fR
.RS 4
Output information only about the workspace members and don't fetch
Output information only about the members of local workspaces and don't fetch
dependencies.
.RE
.sp
Expand Down
68 changes: 66 additions & 2 deletions tests/testsuite/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,12 +909,26 @@ fn workspace_metadata_no_deps() {
r#"
[workspace]
members = ["bar", "baz"]
exclude = ["qux"]
"#,
)
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
.file("bar/src/lib.rs", "")
.file("baz/Cargo.toml", &basic_lib_manifest("baz"))
.file(
"baz/Cargo.toml",
r#"
[package]
name = "baz"
version = "0.5.0"
authors = ["[email protected]"]

[dependencies]
qux = { path = "../qux" }
"#,
)
.file("baz/src/lib.rs", "")
.file("qux/Cargo.toml", &basic_lib_manifest("qux"))
.file("qux/src/lib.rs", "")
.build();

p.cargo("metadata --no-deps")
Expand Down Expand Up @@ -973,7 +987,20 @@ fn workspace_metadata_no_deps() {
"id": "baz[..]",
"keywords": [],
"source": null,
"dependencies": [],
"dependencies": [
{
"features": [],
"kind": null,
"name": "qux",
"optional": false,
"registry": null,
"rename": null,
"req": "*",
"source": null,
"target": null,
"uses_default_features": true
}
],
"license": null,
"license_file": null,
"links": null,
Expand All @@ -995,6 +1022,43 @@ fn workspace_metadata_no_deps() {
"manifest_path": "[..]baz/Cargo.toml",
"metadata": null,
"publish": null
},
{
"authors": [
"[email protected]"
],
"categories": [],
"name": "qux",
"readme": null,
"repository": null,
"homepage": null,
"documentation": null,
"version": "0.5.0",
"id": "qux[..]",
"keywords": [],
"source": null,
"dependencies": [],
"license": null,
"license_file": null,
"links": null,
"description": null,
"edition": "2015",
"targets": [
{
"kind": [ "lib" ],
"crate_types": ["lib"],
"doc": true,
"doctest": true,
"test": true,
"edition": "2015",
"name": "qux",
"src_path": "[..]qux/src/lib.rs"
}
],
"features": {},
"manifest_path": "[..]qux/Cargo.toml",
"metadata": null,
"publish": null
}
],
"workspace_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"],
Expand Down