1use std::str::FromStr;
3
4use crate::TypeMeta;
5use k8s_openapi::{api::core::v1::ObjectReference, apimachinery::pkg::apis::meta::v1::OwnerReference};
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9#[derive(Debug, Error)]
10#[error("failed to parse group version: {0}")]
11pub struct ParseGroupVersionError(pub String);
13
14#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)]
16pub struct GroupVersionKind {
17 pub group: String,
19 pub version: String,
21 pub kind: String,
23}
24
25impl GroupVersionKind {
26 pub fn gvk(group_: &str, version_: &str, kind_: &str) -> Self {
28 let version = version_.to_string();
29 let group = group_.to_string();
30 let kind = kind_.to_string();
31
32 Self { group, version, kind }
33 }
34}
35
36impl TryFrom<&TypeMeta> for GroupVersionKind {
37 type Error = ParseGroupVersionError;
38
39 fn try_from(tm: &TypeMeta) -> Result<Self, Self::Error> {
40 Ok(GroupVersion::from_str(&tm.api_version)?.with_kind(&tm.kind))
41 }
42}
43impl TryFrom<TypeMeta> for GroupVersionKind {
44 type Error = ParseGroupVersionError;
45
46 fn try_from(tm: TypeMeta) -> Result<Self, Self::Error> {
47 Ok(GroupVersion::from_str(&tm.api_version)?.with_kind(&tm.kind))
48 }
49}
50
51impl From<OwnerReference> for GroupVersionKind {
52 fn from(value: OwnerReference) -> Self {
53 let (group, version) = match value.api_version.split_once("/") {
54 Some((group, version)) => (group, version),
55 None => ("", value.api_version.as_str()),
56 };
57 Self {
58 group: group.into(),
59 version: version.into(),
60 kind: value.kind,
61 }
62 }
63}
64
65impl From<ObjectReference> for GroupVersionKind {
66 fn from(value: ObjectReference) -> Self {
67 let api_version = value.api_version.unwrap_or_default();
68 let (group, version) = match api_version.split_once("/") {
69 Some((group, version)) => (group, version),
70 None => ("", api_version.as_str()),
71 };
72 Self {
73 group: group.into(),
74 version: version.into(),
75 kind: value.kind.unwrap_or_default(),
76 }
77 }
78}
79
80#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)]
82pub struct GroupVersion {
83 pub group: String,
85 pub version: String,
87}
88
89impl GroupVersion {
90 pub fn gv(group_: &str, version_: &str) -> Self {
92 let version = version_.to_string();
93 let group = group_.to_string();
94 Self { group, version }
95 }
96
97 pub fn with_kind(self, kind: &str) -> GroupVersionKind {
99 GroupVersionKind {
100 group: self.group,
101 version: self.version,
102 kind: kind.into(),
103 }
104 }
105}
106
107impl FromStr for GroupVersion {
108 type Err = ParseGroupVersionError;
109
110 fn from_str(gv: &str) -> Result<Self, Self::Err> {
111 let gvsplit = gv.splitn(2, '/').collect::<Vec<_>>();
112 let (group, version) = match *gvsplit.as_slice() {
113 [g, v] => (g.to_string(), v.to_string()), [v] => ("".to_string(), v.to_string()), _ => return Err(ParseGroupVersionError(gv.into())),
116 };
117 Ok(Self { group, version })
118 }
119}
120
121impl GroupVersion {
122 pub fn api_version(&self) -> String {
124 if self.group.is_empty() {
125 self.version.clone()
126 } else {
127 format!("{}/{}", self.group, self.version)
128 }
129 }
130}
131impl GroupVersionKind {
132 pub fn api_version(&self) -> String {
134 if self.group.is_empty() {
135 self.version.clone()
136 } else {
137 format!("{}/{}", self.group, self.version)
138 }
139 }
140}
141
142#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)]
144pub struct GroupVersionResource {
145 pub group: String,
147 pub version: String,
149 pub resource: String,
151 #[serde(default)]
153 api_version: String,
154}
155
156impl GroupVersionResource {
157 pub fn gvr(group_: &str, version_: &str, resource_: &str) -> Self {
159 let version = version_.to_string();
160 let group = group_.to_string();
161 let resource = resource_.to_string();
162 let api_version = if group.is_empty() {
163 version.to_string()
164 } else {
165 format!("{group}/{version}")
166 };
167
168 Self {
169 group,
170 version,
171 resource,
172 api_version,
173 }
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 #[test]
180 fn gvk_yaml() {
181 use crate::{GroupVersionKind, TypeMeta};
182 let input = r#"---
183apiVersion: kube.rs/v1
184kind: Example
185metadata:
186 name: doc1
187"#;
188 let tm: TypeMeta = serde_yaml::from_str(input).unwrap();
189 let gvk = GroupVersionKind::try_from(&tm).unwrap(); let gvk2: GroupVersionKind = tm.try_into().unwrap(); assert_eq!(gvk.kind, "Example");
192 assert_eq!(gvk.group, "kube.rs");
193 assert_eq!(gvk.version, "v1");
194 assert_eq!(gvk.kind, gvk2.kind);
195 }
196}