Skip to content

Commit cdf4223

Browse files
committed
Add methods is_available and is_missing to WorkspaceDefaultMembers
This method checks whether the called cargo-metadata supports reading the workspace default members, which is false for versions of Cargo prior to 1.71
1 parent d6b186c commit cdf4223

File tree

3 files changed

+189
-22
lines changed

3 files changed

+189
-22
lines changed

src/lib.rs

+31-14
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,11 @@ pub struct Metadata {
157157
pub workspace_members: Vec<PackageId>,
158158
/// The list of default workspace members
159159
///
160-
/// This not available if running with a version of Cargo older than 1.71.
161-
#[serde(default, skip_serializing_if = "workspace_default_members_is_missing")]
160+
/// This is not available if running with a version of Cargo older than 1.71.
161+
///
162+
/// You can check whether it is available or missing using respectively
163+
/// [`WorkspaceDefaultMembers::is_available`] and [`WorkspaceDefaultMembers::is_missing`].
164+
#[serde(default, skip_serializing_if = "WorkspaceDefaultMembers::is_missing")]
162165
pub workspace_default_members: WorkspaceDefaultMembers,
163166
/// Dependencies graph
164167
pub resolve: Option<Resolve>,
@@ -237,6 +240,32 @@ impl<'a> std::ops::Index<&'a PackageId> for Metadata {
237240
/// Dereferencing when running an older version of Cargo will panic.
238241
pub struct WorkspaceDefaultMembers(Option<Vec<PackageId>>);
239242

243+
impl WorkspaceDefaultMembers {
244+
/// Return `true` if the list of workspace default members is supported by
245+
/// the called cargo-metadata version and `false` otherwise.
246+
///
247+
/// In particular useful when parsing the output of `cargo-metadata` for
248+
/// versions of Cargo < 1.71, as dereferencing [`WorkspaceDefaultMembers`]
249+
/// for these versions will panic.
250+
///
251+
/// Opposite of [`WorkspaceDefaultMembers::is_missing`].
252+
pub fn is_available(&self) -> bool {
253+
self.0.is_some()
254+
}
255+
256+
/// Return `false` if the list of workspace default members is supported by
257+
/// the called cargo-metadata version and `true` otherwise.
258+
///
259+
/// In particular useful when parsing the output of `cargo-metadata` for
260+
/// versions of Cargo < 1.71, as dereferencing [`WorkspaceDefaultMembers`]
261+
/// for these versions will panic.
262+
///
263+
/// Opposite of [`WorkspaceDefaultMembers::is_available`].
264+
pub fn is_missing(&self) -> bool {
265+
self.0.is_none()
266+
}
267+
}
268+
240269
impl core::ops::Deref for WorkspaceDefaultMembers {
241270
type Target = [PackageId];
242271

@@ -247,18 +276,6 @@ impl core::ops::Deref for WorkspaceDefaultMembers {
247276
}
248277
}
249278

250-
/// Return true if a valid value for [`WorkspaceDefaultMembers`] is missing, and
251-
/// dereferencing it would panic.
252-
///
253-
/// Internal helper for `skip_serializing_if` and test code. Might be removed in
254-
/// the future.
255-
#[doc(hidden)]
256-
pub fn workspace_default_members_is_missing(
257-
workspace_default_members: &WorkspaceDefaultMembers,
258-
) -> bool {
259-
workspace_default_members.0.is_none()
260-
}
261-
262279
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
263280
#[cfg_attr(feature = "builder", derive(Builder))]
264281
#[non_exhaustive]

tests/selftest.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,14 @@ fn metadata_deps() {
164164

165165
#[test]
166166
fn workspace_default_packages() {
167-
use cargo_metadata::workspace_default_members_is_missing;
168-
169167
let metadata = MetadataCommand::new()
170168
.manifest_path("Cargo.toml")
171169
.exec()
172170
.unwrap();
173171
let workspace_packages = metadata.workspace_packages();
174172
// this will only trigger on cargo versions that expose
175173
// workspace_default_members (that is, cargo >= 1.71)
176-
if !workspace_default_members_is_missing(&metadata.workspace_default_members) {
174+
if metadata.workspace_default_members.is_available() {
177175
let default_packages = metadata.workspace_default_packages();
178176
assert_eq!(default_packages, workspace_packages);
179177
}

tests/test_samples.rs

+157-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ extern crate serde_json;
55

66
use camino::Utf8PathBuf;
77
use cargo_metadata::{
8-
workspace_default_members_is_missing, ArtifactDebuginfo, CargoOpt, DependencyKind, Edition,
9-
Message, Metadata, MetadataCommand,
8+
ArtifactDebuginfo, CargoOpt, DependencyKind, Edition, Message, Metadata, MetadataCommand,
109
};
1110

1211
/// Output from oldest version ever supported (1.24).
@@ -125,9 +124,9 @@ fn old_minimal() {
125124
assert_eq!(meta.workspace_metadata, serde_json::Value::Null);
126125
assert_eq!(meta.target_directory, "/foo/target");
127126

128-
assert!(workspace_default_members_is_missing(
129-
&meta.workspace_default_members
130-
));
127+
assert!(!meta.workspace_default_members.is_available());
128+
assert!(meta.workspace_default_members.is_missing());
129+
131130
let serialized = serde_json::to_value(meta).unwrap();
132131
assert!(!serialized
133132
.as_object()
@@ -724,6 +723,159 @@ fn missing_workspace_default_members() {
724723
let _ = &*meta.workspace_default_members;
725724
}
726725

726+
#[test]
727+
fn workspace_default_members_is_available() {
728+
// generated with cargo +1.71.0 metadata --format-version 1
729+
let json = r#"
730+
{
731+
"packages": [
732+
{
733+
"name": "basic",
734+
"version": "0.1.0",
735+
"id": "basic 0.1.0 (path+file:///example)",
736+
"license": null,
737+
"license_file": null,
738+
"description": null,
739+
"source": null,
740+
"dependencies": [],
741+
"targets": [
742+
{
743+
"kind": [
744+
"lib"
745+
],
746+
"crate_types": [
747+
"lib"
748+
],
749+
"name": "basic",
750+
"src_path": "/example/src/lib.rs",
751+
"edition": "2021",
752+
"doc": true,
753+
"doctest": true,
754+
"test": true
755+
}
756+
],
757+
"features": {},
758+
"manifest_path": "/example/Cargo.toml",
759+
"metadata": null,
760+
"publish": null,
761+
"authors": [],
762+
"categories": [],
763+
"keywords": [],
764+
"readme": null,
765+
"repository": null,
766+
"homepage": null,
767+
"documentation": null,
768+
"edition": "2021",
769+
"links": null,
770+
"default_run": null,
771+
"rust_version": null
772+
}
773+
],
774+
"workspace_members": [
775+
"basic 0.1.0 (path+file:///example)"
776+
],
777+
"workspace_default_members": [
778+
"basic 0.1.0 (path+file:///example)"
779+
],
780+
"resolve": {
781+
"nodes": [
782+
{
783+
"id": "basic 0.1.0 (path+file:///example)",
784+
"dependencies": [],
785+
"deps": [],
786+
"features": []
787+
}
788+
],
789+
"root": "basic 0.1.0 (path+file:///example)"
790+
},
791+
"target_directory": "/example/target",
792+
"version": 1,
793+
"workspace_root": "/example",
794+
"metadata": null
795+
}
796+
"#;
797+
798+
let meta: Metadata = serde_json::from_str(json).unwrap();
799+
800+
assert!(meta.workspace_default_members.is_available());
801+
assert!(!meta.workspace_default_members.is_missing());
802+
}
803+
804+
#[test]
805+
fn workspace_default_members_is_missing() {
806+
// generated with cargo +1.70.0 metadata --format-version 1
807+
let json = r#"
808+
{
809+
"packages": [
810+
{
811+
"name": "basic",
812+
"version": "0.1.0",
813+
"id": "basic 0.1.0 (path+file:///example)",
814+
"license": null,
815+
"license_file": null,
816+
"description": null,
817+
"source": null,
818+
"dependencies": [],
819+
"targets": [
820+
{
821+
"kind": [
822+
"lib"
823+
],
824+
"crate_types": [
825+
"lib"
826+
],
827+
"name": "basic",
828+
"src_path": "/example/src/lib.rs",
829+
"edition": "2021",
830+
"doc": true,
831+
"doctest": true,
832+
"test": true
833+
}
834+
],
835+
"features": {},
836+
"manifest_path": "/example/Cargo.toml",
837+
"metadata": null,
838+
"publish": null,
839+
"authors": [],
840+
"categories": [],
841+
"keywords": [],
842+
"readme": null,
843+
"repository": null,
844+
"homepage": null,
845+
"documentation": null,
846+
"edition": "2021",
847+
"links": null,
848+
"default_run": null,
849+
"rust_version": null
850+
}
851+
],
852+
"workspace_members": [
853+
"basic 0.1.0 (path+file:///example)"
854+
],
855+
"resolve": {
856+
"nodes": [
857+
{
858+
"id": "basic 0.1.0 (path+file:///example)",
859+
"dependencies": [],
860+
"deps": [],
861+
"features": []
862+
}
863+
],
864+
"root": "basic 0.1.0 (path+file:///example)"
865+
},
866+
"target_directory": "/example/target",
867+
"version": 1,
868+
"workspace_root": "/example",
869+
"metadata": null
870+
}
871+
"#;
872+
873+
let meta: Metadata = serde_json::from_str(json).unwrap();
874+
875+
assert!(!meta.workspace_default_members.is_available());
876+
assert!(meta.workspace_default_members.is_missing());
877+
}
878+
727879
#[test]
728880
fn test_unknown_target_kind_and_crate_type() {
729881
// Both kind and crate_type set to a type not yet known

0 commit comments

Comments
 (0)