Skip to content

Commit

Permalink
Merge pull request #248 from sorcio/add_worskpace_default_members
Browse files Browse the repository at this point in the history
Add `workspace_default_members` field
  • Loading branch information
oli-obk authored Sep 6, 2023
2 parents 04930e3 + b181569 commit fd72a0b
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 13 deletions.
52 changes: 52 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ pub struct Metadata {
pub packages: Vec<Package>,
/// A list of all workspace members
pub workspace_members: Vec<PackageId>,
/// The list of default workspace members
///
/// This not available if running with a version of Cargo older than 1.71.
#[serde(skip_serializing_if = "workspace_default_members_is_missing")]
pub workspace_default_members: WorkspaceDefaultMembers,
/// Dependencies graph
pub resolve: Option<Resolve>,
/// Workspace root
Expand Down Expand Up @@ -190,6 +195,18 @@ impl Metadata {
.filter(|&p| self.workspace_members.contains(&p.id))
.collect()
}

/// Get the workspace default packages.
///
/// # Panics
///
/// This will panic if running with a version of Cargo older than 1.71.
pub fn workspace_default_packages(&self) -> Vec<&Package> {
self.packages
.iter()
.filter(|&p| self.workspace_default_members.contains(&p.id))
.collect()
}
}

impl<'a> std::ops::Index<&'a PackageId> for Metadata {
Expand All @@ -203,6 +220,41 @@ impl<'a> std::ops::Index<&'a PackageId> for Metadata {
}
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(transparent)]
/// A list of default workspace members.
///
/// See [`Metadata::workspace_default_members`].
///
/// It is only available if running a version of Cargo of 1.71 or newer.
///
/// # Panics
///
/// Dereferencing when running an older version of Cargo will panic.
pub struct WorkspaceDefaultMembers(Option<Vec<PackageId>>);

impl core::ops::Deref for WorkspaceDefaultMembers {
type Target = [PackageId];

fn deref(&self) -> &Self::Target {
self.0
.as_ref()
.expect("WorkspaceDefaultMembers should only be dereferenced on Cargo versions >= 1.71")
}
}

/// Return true if a valid value for [`WorkspaceDefaultMembers`] is missing, and
/// dereferencing it would panic.
///
/// Internal helper for `skip_serializing_if` and test code. Might be removed in
/// the future.
#[doc(hidden)]
pub fn workspace_default_members_is_missing(
workspace_default_members: &WorkspaceDefaultMembers,
) -> bool {
workspace_default_members.0.is_none()
}

#[derive(Clone, Serialize, Deserialize, Debug)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[non_exhaustive]
Expand Down
17 changes: 17 additions & 0 deletions tests/selftest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,20 @@ fn metadata_deps() {
assert!(serde.req.matches(&Version::parse("1.99.99").unwrap()));
assert!(!serde.req.matches(&Version::parse("2.0.0").unwrap()));
}

#[test]
fn workspace_default_packages() {
use cargo_metadata::workspace_default_members_is_missing;

let metadata = MetadataCommand::new()
.manifest_path("Cargo.toml")
.exec()
.unwrap();
let workspace_packages = metadata.workspace_packages();
// this will only trigger on cargo versions that expose
// workspace_default_members (that is, cargo >= 1.71)
if !workspace_default_members_is_missing(&metadata.workspace_default_members) {
let default_packages = metadata.workspace_default_packages();
assert_eq!(default_packages, workspace_packages);
}
}
61 changes: 48 additions & 13 deletions tests/test_samples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ extern crate serde_json;

use camino::Utf8PathBuf;
use cargo_metadata::{
ArtifactDebuginfo, CargoOpt, DependencyKind, Edition, Message, Metadata, MetadataCommand,
workspace_default_members_is_missing, ArtifactDebuginfo, CargoOpt, DependencyKind, Edition,
Message, Metadata, MetadataCommand,
};

#[test]
fn old_minimal() {
// Output from oldest supported version (1.24).
// This intentionally has as many null fields as possible.
// 1.8 is when metadata was introduced.
// Older versions not supported because the following are required:
// - `workspace_members` added in 1.13
// - `target_directory` added in 1.19
// - `workspace_root` added in 1.24
let json = r#"
/// Output from oldest version ever supported (1.24).
///
/// This intentionally has as many null fields as possible.
/// 1.8 is when metadata was introduced.
/// Older versions not supported because the following are required:
/// - `workspace_members` added in 1.13
/// - `target_directory` added in 1.19
/// - `workspace_root` added in 1.24
const JSON_OLD_MINIMAL: &str = r#"
{
"packages": [
{
Expand Down Expand Up @@ -65,7 +65,10 @@ fn old_minimal() {
"workspace_root": "/foo"
}
"#;
let meta: Metadata = serde_json::from_str(json).unwrap();

#[test]
fn old_minimal() {
let meta: Metadata = serde_json::from_str(JSON_OLD_MINIMAL).unwrap();
assert_eq!(meta.packages.len(), 1);
let pkg = &meta.packages[0];
assert_eq!(pkg.name, "foo");
Expand Down Expand Up @@ -121,6 +124,15 @@ fn old_minimal() {
assert_eq!(meta.workspace_root, "/foo");
assert_eq!(meta.workspace_metadata, serde_json::Value::Null);
assert_eq!(meta.target_directory, "/foo/target");

assert!(workspace_default_members_is_missing(
&meta.workspace_default_members
));
let serialized = serde_json::to_value(meta).unwrap();
assert!(!serialized
.as_object()
.unwrap()
.contains_key("workspace_default_members"));
}

macro_rules! sorted {
Expand Down Expand Up @@ -178,6 +190,7 @@ fn all_the_fields() {
// path added in 1.51
// default_run added in 1.55
// rust_version added in 1.58
// workspace_default_members added in 1.71
eprintln!("Skipping all_the_fields test, cargo {} is too old.", ver);
return;
}
Expand All @@ -187,7 +200,7 @@ fn all_the_fields() {
.unwrap();
assert_eq!(meta.workspace_root.file_name().unwrap(), "all");
assert_eq!(
serde_json::from_value::<WorkspaceMetadata>(meta.workspace_metadata).unwrap(),
serde_json::from_value::<WorkspaceMetadata>(meta.workspace_metadata.clone()).unwrap(),
WorkspaceMetadata {
testobject: TestObject {
myvalue: "abc".to_string()
Expand All @@ -196,6 +209,9 @@ fn all_the_fields() {
);
assert_eq!(meta.workspace_members.len(), 1);
assert!(meta.workspace_members[0].to_string().starts_with("all"));
if ver >= semver::Version::parse("1.71.0").unwrap() {
assert_eq!(&*meta.workspace_default_members, &meta.workspace_members);
}

assert_eq!(meta.packages.len(), 9);
let all = meta.packages.iter().find(|p| p.name == "all").unwrap();
Expand Down Expand Up @@ -450,6 +466,18 @@ fn all_the_fields() {
kind.target.as_ref().map(|x| x.to_string()),
Some("cfg(windows)".to_string())
);

let serialized = serde_json::to_value(meta).unwrap();
if ver >= semver::Version::parse("1.71.0").unwrap() {
assert!(serialized.as_object().unwrap()["workspace_default_members"]
.as_array()
.is_some());
} else {
assert!(!serialized
.as_object()
.unwrap()
.contains_key("workspace_default_members"));
}
}

#[test]
Expand Down Expand Up @@ -690,3 +718,10 @@ fn debuginfo_variants() {
}
}
}

#[test]
#[should_panic = "WorkspaceDefaultMembers should only be dereferenced on Cargo versions >= 1.71"]
fn missing_workspace_default_members() {
let meta: Metadata = serde_json::from_str(JSON_OLD_MINIMAL).unwrap();
let _ = &*meta.workspace_default_members;
}

0 comments on commit fd72a0b

Please sign in to comment.