mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
Auto merge of #14504 - eopb:push-xknxowwslrpt, r=epage
Include public/private dependency status in `cargo metadata` fixes #14502 > [!TIP] > This change can be reviewed commit-by-commit. > Descriptions on individual commits are available to justify some decisions `@rustbot` label Command-metadata Z-public-dependency
This commit is contained in:
commit
b958d79acd
@ -15,6 +15,9 @@ Deprecated, use `<cyan,bold>cargo metadata --no-deps</>` instead.\
|
|||||||
|
|
||||||
pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
|
pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
|
||||||
let ws = args.workspace(gctx)?;
|
let ws = args.workspace(gctx)?;
|
||||||
gctx.shell().print_json(&ws.current()?.serialized())?;
|
gctx.shell().print_json(
|
||||||
|
&ws.current()?
|
||||||
|
.serialized(gctx.cli_unstable(), ws.unstable_features()),
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use std::sync::Arc;
|
|||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::core::compiler::{CompileKind, CompileTarget};
|
use crate::core::compiler::{CompileKind, CompileTarget};
|
||||||
use crate::core::{PackageId, SourceId, Summary};
|
use crate::core::{CliUnstable, Feature, Features, PackageId, SourceId, Summary};
|
||||||
use crate::util::errors::CargoResult;
|
use crate::util::errors::CargoResult;
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
use crate::util::OptVersionReq;
|
use crate::util::OptVersionReq;
|
||||||
@ -52,50 +52,32 @@ struct Inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct SerializedDependency<'a> {
|
pub struct SerializedDependency {
|
||||||
name: &'a str,
|
name: InternedString,
|
||||||
source: SourceId,
|
source: SourceId,
|
||||||
req: String,
|
req: String,
|
||||||
kind: DepKind,
|
kind: DepKind,
|
||||||
rename: Option<&'a str>,
|
rename: Option<InternedString>,
|
||||||
|
|
||||||
optional: bool,
|
optional: bool,
|
||||||
uses_default_features: bool,
|
uses_default_features: bool,
|
||||||
features: &'a [InternedString],
|
features: Vec<InternedString>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
artifact: Option<&'a Artifact>,
|
artifact: Option<Artifact>,
|
||||||
target: Option<&'a Platform>,
|
target: Option<Platform>,
|
||||||
/// The registry URL this dependency is from.
|
/// The registry URL this dependency is from.
|
||||||
/// If None, then it comes from the default registry (crates.io).
|
/// If None, then it comes from the default registry (crates.io).
|
||||||
registry: Option<&'a str>,
|
registry: Option<String>,
|
||||||
|
|
||||||
/// The file system path for a local path dependency.
|
/// The file system path for a local path dependency.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
path: Option<PathBuf>,
|
path: Option<PathBuf>,
|
||||||
}
|
|
||||||
|
|
||||||
impl ser::Serialize for Dependency {
|
/// `public` flag is unset if `-Zpublic-dependency` is not enabled
|
||||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
///
|
||||||
where
|
/// Once that feature is stabilized, `public` will not need to be `Option`
|
||||||
S: ser::Serializer,
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
{
|
public: Option<bool>,
|
||||||
let registry_id = self.registry_id();
|
|
||||||
SerializedDependency {
|
|
||||||
name: &*self.package_name(),
|
|
||||||
source: self.source_id(),
|
|
||||||
req: self.version_req().to_string(),
|
|
||||||
kind: self.kind(),
|
|
||||||
optional: self.is_optional(),
|
|
||||||
uses_default_features: self.uses_default_features(),
|
|
||||||
features: self.features(),
|
|
||||||
target: self.platform(),
|
|
||||||
rename: self.explicit_name_in_toml().map(|s| s.as_str()),
|
|
||||||
registry: registry_id.as_ref().map(|sid| sid.url().as_str()),
|
|
||||||
path: self.source_id().local_path(),
|
|
||||||
artifact: self.artifact(),
|
|
||||||
}
|
|
||||||
.serialize(s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Debug, Copy)]
|
#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Debug, Copy)]
|
||||||
@ -182,6 +164,34 @@ impl Dependency {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serialized(
|
||||||
|
&self,
|
||||||
|
unstable_flags: &CliUnstable,
|
||||||
|
features: &Features,
|
||||||
|
) -> SerializedDependency {
|
||||||
|
SerializedDependency {
|
||||||
|
name: self.package_name(),
|
||||||
|
source: self.source_id(),
|
||||||
|
req: self.version_req().to_string(),
|
||||||
|
kind: self.kind(),
|
||||||
|
optional: self.is_optional(),
|
||||||
|
uses_default_features: self.uses_default_features(),
|
||||||
|
features: self.features().to_vec(),
|
||||||
|
target: self.inner.platform.clone(),
|
||||||
|
rename: self.explicit_name_in_toml(),
|
||||||
|
registry: self.registry_id().as_ref().map(|sid| sid.url().to_string()),
|
||||||
|
path: self.source_id().local_path(),
|
||||||
|
artifact: self.inner.artifact.clone(),
|
||||||
|
public: if unstable_flags.public_dependency
|
||||||
|
|| features.is_enabled(Feature::public_dependency())
|
||||||
|
{
|
||||||
|
Some(self.inner.public)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn version_req(&self) -> &OptVersionReq {
|
pub fn version_req(&self) -> &OptVersionReq {
|
||||||
&self.inner.req
|
&self.inner.req
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
pub use self::dependency::Dependency;
|
pub use self::dependency::{Dependency, SerializedDependency};
|
||||||
pub use self::features::{CliUnstable, Edition, Feature, Features};
|
pub use self::features::{CliUnstable, Edition, Feature, Features};
|
||||||
pub use self::manifest::{EitherManifest, VirtualManifest};
|
pub use self::manifest::{EitherManifest, VirtualManifest};
|
||||||
pub use self::manifest::{Manifest, Target, TargetKind};
|
pub use self::manifest::{Manifest, Target, TargetKind};
|
||||||
|
@ -22,7 +22,10 @@ use crate::core::compiler::{CompileKind, RustcTargetData};
|
|||||||
use crate::core::dependency::DepKind;
|
use crate::core::dependency::DepKind;
|
||||||
use crate::core::resolver::features::ForceAllTargets;
|
use crate::core::resolver::features::ForceAllTargets;
|
||||||
use crate::core::resolver::{HasDevUnits, Resolve};
|
use crate::core::resolver::{HasDevUnits, Resolve};
|
||||||
use crate::core::{Dependency, Manifest, PackageId, PackageIdSpec, SourceId, Target};
|
use crate::core::{
|
||||||
|
CliUnstable, Dependency, Features, Manifest, PackageId, PackageIdSpec, SerializedDependency,
|
||||||
|
SourceId, Target,
|
||||||
|
};
|
||||||
use crate::core::{Summary, Workspace};
|
use crate::core::{Summary, Workspace};
|
||||||
use crate::sources::source::{MaybePackage, SourceMap};
|
use crate::sources::source::{MaybePackage, SourceMap};
|
||||||
use crate::util::cache_lock::{CacheLock, CacheLockMode};
|
use crate::util::cache_lock::{CacheLock, CacheLockMode};
|
||||||
@ -73,7 +76,7 @@ pub struct SerializedPackage {
|
|||||||
license_file: Option<String>,
|
license_file: Option<String>,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
source: SourceId,
|
source: SourceId,
|
||||||
dependencies: Vec<Dependency>,
|
dependencies: Vec<SerializedDependency>,
|
||||||
targets: Vec<Target>,
|
targets: Vec<Target>,
|
||||||
features: BTreeMap<InternedString, Vec<InternedString>>,
|
features: BTreeMap<InternedString, Vec<InternedString>>,
|
||||||
manifest_path: PathBuf,
|
manifest_path: PathBuf,
|
||||||
@ -188,7 +191,11 @@ impl Package {
|
|||||||
self.targets().iter().any(|t| t.is_example() || t.is_bin())
|
self.targets().iter().any(|t| t.is_example() || t.is_bin())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialized(&self) -> SerializedPackage {
|
pub fn serialized(
|
||||||
|
&self,
|
||||||
|
unstable_flags: &CliUnstable,
|
||||||
|
cargo_features: &Features,
|
||||||
|
) -> SerializedPackage {
|
||||||
let summary = self.manifest().summary();
|
let summary = self.manifest().summary();
|
||||||
let package_id = summary.package_id();
|
let package_id = summary.package_id();
|
||||||
let manmeta = self.manifest().metadata();
|
let manmeta = self.manifest().metadata();
|
||||||
@ -203,7 +210,7 @@ impl Package {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
// Convert Vec<FeatureValue> to Vec<InternedString>
|
// Convert Vec<FeatureValue> to Vec<InternedString>
|
||||||
let features = summary
|
let crate_features = summary
|
||||||
.features()
|
.features()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
@ -224,9 +231,13 @@ impl Package {
|
|||||||
license_file: manmeta.license_file.clone(),
|
license_file: manmeta.license_file.clone(),
|
||||||
description: manmeta.description.clone(),
|
description: manmeta.description.clone(),
|
||||||
source: summary.source_id(),
|
source: summary.source_id(),
|
||||||
dependencies: summary.dependencies().to_vec(),
|
dependencies: summary
|
||||||
|
.dependencies()
|
||||||
|
.iter()
|
||||||
|
.map(|dep| dep.serialized(unstable_flags, cargo_features))
|
||||||
|
.collect(),
|
||||||
targets,
|
targets,
|
||||||
features,
|
features: crate_features,
|
||||||
manifest_path: self.manifest_path().to_path_buf(),
|
manifest_path: self.manifest_path().to_path_buf(),
|
||||||
metadata: self.manifest().custom_metadata().cloned(),
|
metadata: self.manifest().custom_metadata().cloned(),
|
||||||
authors: manmeta.authors.clone(),
|
authors: manmeta.authors.clone(),
|
||||||
|
@ -33,7 +33,10 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let (packages, resolve) = if opt.no_deps {
|
let (packages, resolve) = if opt.no_deps {
|
||||||
let packages = ws.members().map(|pkg| pkg.serialized()).collect();
|
let packages = ws
|
||||||
|
.members()
|
||||||
|
.map(|pkg| pkg.serialized(ws.gctx().cli_unstable(), ws.unstable_features()))
|
||||||
|
.collect();
|
||||||
(packages, None)
|
(packages, None)
|
||||||
} else {
|
} else {
|
||||||
let (packages, resolve) = build_resolve_graph(ws, opt)?;
|
let (packages, resolve) = build_resolve_graph(ws, opt)?;
|
||||||
@ -178,7 +181,7 @@ fn build_resolve_graph(
|
|||||||
let actual_packages = package_map
|
let actual_packages = package_map
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg))
|
.filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg))
|
||||||
.map(|pkg| pkg.serialized())
|
.map(|pkg| pkg.serialized(ws.gctx().cli_unstable(), ws.unstable_features()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mr = MetadataResolve {
|
let mr = MetadataResolve {
|
||||||
|
@ -123,7 +123,12 @@ The JSON output has the following format:
|
|||||||
If not specified or null, the dependency is from the default
|
If not specified or null, the dependency is from the default
|
||||||
registry (crates.io).
|
registry (crates.io).
|
||||||
*/
|
*/
|
||||||
"registry": null
|
"registry": null,
|
||||||
|
/* (unstable) Boolean flag of whether or not this is a pulbic
|
||||||
|
dependency. This field is only present when
|
||||||
|
`-Zpublic-dependency` is enabled.
|
||||||
|
*/
|
||||||
|
"public": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
/* Array of Cargo targets. */
|
/* Array of Cargo targets. */
|
||||||
|
@ -119,7 +119,12 @@ OUTPUT FORMAT
|
|||||||
If not specified or null, the dependency is from the default
|
If not specified or null, the dependency is from the default
|
||||||
registry (crates.io).
|
registry (crates.io).
|
||||||
*/
|
*/
|
||||||
"registry": null
|
"registry": null,
|
||||||
|
/* (unstable) Boolean flag of whether or not this is a pulbic
|
||||||
|
dependency. This field is only present when
|
||||||
|
`-Zpublic-dependency` is enabled.
|
||||||
|
*/
|
||||||
|
"public": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
/* Array of Cargo targets. */
|
/* Array of Cargo targets. */
|
||||||
|
@ -123,7 +123,12 @@ The JSON output has the following format:
|
|||||||
If not specified or null, the dependency is from the default
|
If not specified or null, the dependency is from the default
|
||||||
registry (crates.io).
|
registry (crates.io).
|
||||||
*/
|
*/
|
||||||
"registry": null
|
"registry": null,
|
||||||
|
/* (unstable) Boolean flag of whether or not this is a pulbic
|
||||||
|
dependency. This field is only present when
|
||||||
|
`-Zpublic-dependency` is enabled.
|
||||||
|
*/
|
||||||
|
"public": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
/* Array of Cargo targets. */
|
/* Array of Cargo targets. */
|
||||||
|
@ -125,7 +125,12 @@ The JSON output has the following format:
|
|||||||
If not specified or null, the dependency is from the default
|
If not specified or null, the dependency is from the default
|
||||||
registry (crates.io).
|
registry (crates.io).
|
||||||
*/
|
*/
|
||||||
"registry": null
|
"registry": null,
|
||||||
|
/* (unstable) Boolean flag of whether or not this is a pulbic
|
||||||
|
dependency. This field is only present when
|
||||||
|
`\-Zpublic\-dependency` is enabled.
|
||||||
|
*/
|
||||||
|
"public": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
/* Array of Cargo targets. */
|
/* Array of Cargo targets. */
|
||||||
|
@ -627,6 +627,206 @@ fn cargo_metadata_with_deps_and_version() {
|
|||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The `public` field should not show up in `cargo metadata` output if `-Zpublic-dependency`
|
||||||
|
/// is not enabled
|
||||||
|
#[cargo_test]
|
||||||
|
fn cargo_metadata_public_private_dependencies_disabled() {
|
||||||
|
let p = project()
|
||||||
|
.file("src/foo.rs", "")
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.5.0"
|
||||||
|
authors = []
|
||||||
|
license = "MIT"
|
||||||
|
description = "foo"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bar = { version = "*", public = false }
|
||||||
|
foobar = { version = "*", public = true }
|
||||||
|
baz = "*"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
Package::new("bar", "0.0.1").publish();
|
||||||
|
Package::new("foobar", "0.0.2").publish();
|
||||||
|
Package::new("baz", "0.0.3").publish();
|
||||||
|
|
||||||
|
p.cargo("metadata -q --format-version 1")
|
||||||
|
.with_stdout_data(
|
||||||
|
str![[r#"
|
||||||
|
{
|
||||||
|
"metadata": null,
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"...": "{...}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "baz",
|
||||||
|
"...": "{...}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"features": [],
|
||||||
|
"kind": null,
|
||||||
|
"name": "bar",
|
||||||
|
"optional": false,
|
||||||
|
"registry": null,
|
||||||
|
"rename": null,
|
||||||
|
"req": "*",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"target": null,
|
||||||
|
"uses_default_features": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"features": [],
|
||||||
|
"kind": null,
|
||||||
|
"name": "baz",
|
||||||
|
"optional": false,
|
||||||
|
"registry": null,
|
||||||
|
"rename": null,
|
||||||
|
"req": "*",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"target": null,
|
||||||
|
"uses_default_features": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"features": [],
|
||||||
|
"kind": null,
|
||||||
|
"name": "foobar",
|
||||||
|
"optional": false,
|
||||||
|
"registry": null,
|
||||||
|
"rename": null,
|
||||||
|
"req": "*",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"target": null,
|
||||||
|
"uses_default_features": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"...": "{...}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foobar",
|
||||||
|
"...": "{...}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"...": "{...}"
|
||||||
|
}
|
||||||
|
"#]]
|
||||||
|
.is_json(),
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn cargo_metadata_public_private_dependencies_enabled() {
|
||||||
|
let p = project()
|
||||||
|
.file("src/foo.rs", "")
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.5.0"
|
||||||
|
authors = []
|
||||||
|
license = "MIT"
|
||||||
|
description = "foo"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bar = { version = "*", public = false }
|
||||||
|
foobar = { version = "*", public = true }
|
||||||
|
baz = "*"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
Package::new("bar", "0.0.1").publish();
|
||||||
|
Package::new("foobar", "0.0.2").publish();
|
||||||
|
Package::new("baz", "0.0.3").publish();
|
||||||
|
|
||||||
|
p.cargo("metadata -q --format-version 1 -Zpublic-dependency")
|
||||||
|
.masquerade_as_nightly_cargo(&["public-dependency"])
|
||||||
|
.with_stdout_data(
|
||||||
|
str![[r#"
|
||||||
|
{
|
||||||
|
"metadata": null,
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"...": "{...}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "baz",
|
||||||
|
"...": "{...}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"features": [],
|
||||||
|
"kind": null,
|
||||||
|
"name": "bar",
|
||||||
|
"optional": false,
|
||||||
|
"public": false,
|
||||||
|
"registry": null,
|
||||||
|
"rename": null,
|
||||||
|
"req": "*",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"target": null,
|
||||||
|
"uses_default_features": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"features": [],
|
||||||
|
"kind": null,
|
||||||
|
"name": "baz",
|
||||||
|
"optional": false,
|
||||||
|
"public": false,
|
||||||
|
"registry": null,
|
||||||
|
"rename": null,
|
||||||
|
"req": "*",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"target": null,
|
||||||
|
"uses_default_features": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"features": [],
|
||||||
|
"kind": null,
|
||||||
|
"name": "foobar",
|
||||||
|
"optional": false,
|
||||||
|
"public": true,
|
||||||
|
"registry": null,
|
||||||
|
"rename": null,
|
||||||
|
"req": "*",
|
||||||
|
"source": "registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"target": null,
|
||||||
|
"uses_default_features": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"...": "{...}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foobar",
|
||||||
|
"...": "{...}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"...": "{...}"
|
||||||
|
}
|
||||||
|
"#]]
|
||||||
|
.is_json(),
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn example() {
|
fn example() {
|
||||||
let p = project()
|
let p = project()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user