@@ -8,13 +8,18 @@ use syn::{parse_quote, DataStruct, Error, Ident};
88use crate :: {
99 attrs:: common:: ContainerAttributes ,
1010 codegen:: {
11- common:: { Container , ContainerInput , ContainerVersion , Item , VersionedContainer } ,
11+ common:: {
12+ Container , ContainerInput , ContainerVersion , Item , KubernetesOptions , VersionExt ,
13+ VersionedContainer ,
14+ } ,
1215 vstruct:: field:: VersionedField ,
1316 } ,
1417} ;
1518
1619pub ( crate ) mod field;
1720
21+ type GenerateVersionReturn = ( TokenStream , Option < ( TokenStream , ( Ident , String ) ) > ) ;
22+
1823/// Stores individual versions of a single struct. Each version tracks field
1924/// actions, which describe if the field was added, renamed or deprecated in
2025/// that version. Fields which are not versioned, are included in every
@@ -85,24 +90,30 @@ impl Container<DataStruct, VersionedField> for VersionedStruct {
8590 }
8691
8792 fn generate_tokens ( & self ) -> TokenStream {
88- let mut kubernetes_crd_fn_calls = TokenStream :: new ( ) ;
89- let mut container_definition = TokenStream :: new ( ) ;
93+ let mut tokens = TokenStream :: new ( ) ;
94+
95+ let mut enum_variants = Vec :: new ( ) ;
96+ let mut crd_fn_calls = Vec :: new ( ) ;
9097
9198 let mut versions = self . versions . iter ( ) . peekable ( ) ;
9299
93100 while let Some ( version) = versions. next ( ) {
94- container_definition. extend ( self . generate_version ( version, versions. peek ( ) . copied ( ) ) ) ;
95- kubernetes_crd_fn_calls. extend ( self . generate_kubernetes_crd_fn_call ( version) ) ;
101+ let ( container_definition, merged_crd) =
102+ self . generate_version ( version, versions. peek ( ) . copied ( ) ) ;
103+
104+ if let Some ( ( crd_fn_call, enum_variant) ) = merged_crd {
105+ enum_variants. push ( enum_variant) ;
106+ crd_fn_calls. push ( crd_fn_call) ;
107+ }
108+
109+ tokens. extend ( container_definition) ;
96110 }
97111
98- // If tokens for the 'crd()' function calls were generated, also generate
99- // the 'merge_crds' call.
100- if !kubernetes_crd_fn_calls. is_empty ( ) {
101- container_definition
102- . extend ( self . generate_kubernetes_merge_crds ( kubernetes_crd_fn_calls) ) ;
112+ if !crd_fn_calls. is_empty ( ) {
113+ tokens. extend ( self . generate_kubernetes_merge_crds ( crd_fn_calls, enum_variants) ) ;
103114 }
104115
105- container_definition
116+ tokens
106117 }
107118}
108119
@@ -112,7 +123,7 @@ impl VersionedStruct {
112123 & self ,
113124 version : & ContainerVersion ,
114125 next_version : Option < & ContainerVersion > ,
115- ) -> TokenStream {
126+ ) -> GenerateVersionReturn {
116127 let mut token_stream = TokenStream :: new ( ) ;
117128
118129 let original_attributes = & self . original_attributes ;
@@ -137,7 +148,27 @@ impl VersionedStruct {
137148 let version_specific_docs = self . generate_struct_docs ( version) ;
138149
139150 // Generate K8s specific code
140- let kubernetes_cr_derive = self . generate_kubernetes_cr_derive ( version) ;
151+ let ( kubernetes_cr_derive, merged_crd) = match & self . options . kubernetes_options {
152+ Some ( options) => {
153+ // Generate the CustomResource derive macro with the appropriate
154+ // attributes supplied using #[kube()].
155+ let cr_derive = self . generate_kubernetes_cr_derive ( version, options) ;
156+
157+ // Generate merged_crd specific code when not opted out.
158+ let merged_crd = if !options. skip_merged_crd {
159+ let crd_fn_call = self . generate_kubernetes_crd_fn_call ( version) ;
160+ let enum_variant = version. inner . as_variant_ident ( ) ;
161+ let enum_display = version. inner . to_string ( ) ;
162+
163+ Some ( ( crd_fn_call, ( enum_variant, enum_display) ) )
164+ } else {
165+ None
166+ } ;
167+
168+ ( Some ( cr_derive) , merged_crd)
169+ }
170+ None => ( None , None ) ,
171+ } ;
141172
142173 // Generate tokens for the module and the contained struct
143174 token_stream. extend ( quote ! {
@@ -160,7 +191,7 @@ impl VersionedStruct {
160191 token_stream. extend ( self . generate_from_impl ( version, next_version) ) ;
161192 }
162193
163- token_stream
194+ ( token_stream, merged_crd )
164195 }
165196
166197 /// Generates version specific doc comments for the struct.
@@ -251,63 +282,90 @@ impl VersionedStruct {
251282impl VersionedStruct {
252283 /// Generates the `kube::CustomResource` derive with the appropriate macro
253284 /// attributes.
254- fn generate_kubernetes_cr_derive ( & self , version : & ContainerVersion ) -> Option < TokenStream > {
255- if let Some ( kubernetes_options) = & self . options . kubernetes_options {
256- let group = & kubernetes_options. group ;
257- let version = version. inner . to_string ( ) ;
258- let kind = kubernetes_options
259- . kind
260- . as_ref ( )
261- . map_or ( self . idents . kubernetes . to_string ( ) , |kind| kind. clone ( ) ) ;
285+ fn generate_kubernetes_cr_derive (
286+ & self ,
287+ version : & ContainerVersion ,
288+ options : & KubernetesOptions ,
289+ ) -> TokenStream {
290+ let group = & options. group ;
291+ let version = version. inner . to_string ( ) ;
292+ let kind = options
293+ . kind
294+ . as_ref ( )
295+ . map_or ( self . idents . kubernetes . to_string ( ) , |kind| kind. clone ( ) ) ;
262296
263- return Some ( quote ! {
264- #[ derive( :: kube:: CustomResource ) ]
265- #[ kube( group = #group, version = #version, kind = #kind) ]
266- } ) ;
297+ quote ! {
298+ #[ derive( :: kube:: CustomResource ) ]
299+ #[ kube( group = #group, version = #version, kind = #kind) ]
267300 }
268-
269- None
270301 }
271302
272303 /// Generates the `merge_crds` function call.
273- fn generate_kubernetes_merge_crds ( & self , fn_calls : TokenStream ) -> TokenStream {
304+ fn generate_kubernetes_merge_crds (
305+ & self ,
306+ crd_fn_calls : Vec < TokenStream > ,
307+ enum_variants : Vec < ( Ident , String ) > ,
308+ ) -> TokenStream {
274309 let ident = & self . idents . kubernetes ;
275310
311+ let version_enum_definition = self . generate_kubernetes_version_enum ( enum_variants) ;
312+
276313 quote ! {
277314 #[ automatically_derived]
278315 pub struct #ident;
279316
317+ #version_enum_definition
318+
280319 #[ automatically_derived]
281320 impl #ident {
282321 /// Generates a merged CRD which contains all versions defined using the
283322 /// `#[versioned()]` macro.
284323 pub fn merged_crd(
285- stored_apiversion: & str
324+ stored_apiversion: Version
286325 ) -> :: std:: result:: Result <:: k8s_openapi:: apiextensions_apiserver:: pkg:: apis:: apiextensions:: v1:: CustomResourceDefinition , :: kube:: core:: crd:: MergeError > {
287- :: kube:: core:: crd:: merge_crds( vec![ #fn_calls ] , stored_apiversion)
326+ :: kube:: core:: crd:: merge_crds( vec![ #( #crd_fn_calls ) , * ] , & stored_apiversion. to_string ( ) )
288327 }
289328 }
290329 }
291330 }
292331
293332 /// Generates the inner `crd()` functions calls which get used in the
294333 /// `merge_crds` function.
295- fn generate_kubernetes_crd_fn_call ( & self , version : & ContainerVersion ) -> Option < TokenStream > {
296- if self
297- . options
298- . kubernetes_options
299- . as_ref ( )
300- . is_some_and ( |o| !o. skip_merged_crd )
301- {
302- let struct_ident = & self . idents . kubernetes ;
303- let version_ident = & version. ident ;
334+ fn generate_kubernetes_crd_fn_call ( & self , version : & ContainerVersion ) -> TokenStream {
335+ let struct_ident = & self . idents . kubernetes ;
336+ let version_ident = & version. ident ;
337+ let path: syn:: Path = parse_quote ! ( #version_ident:: #struct_ident) ;
304338
305- let path: syn:: Path = parse_quote ! ( #version_ident:: #struct_ident) ;
306- return Some ( quote ! {
307- <#path as :: kube:: CustomResourceExt >:: crd( ) ,
339+ quote ! {
340+ <#path as :: kube:: CustomResourceExt >:: crd( )
341+ }
342+ }
343+
344+ fn generate_kubernetes_version_enum ( & self , enum_variants : Vec < ( Ident , String ) > ) -> TokenStream {
345+ let mut enum_variant_matches = TokenStream :: new ( ) ;
346+ let mut enum_variant_idents = TokenStream :: new ( ) ;
347+
348+ for ( enum_variant_ident, enum_variant_display) in enum_variants {
349+ enum_variant_idents. extend ( quote ! { #enum_variant_ident, } ) ;
350+ enum_variant_matches. extend ( quote ! {
351+ Version :: #enum_variant_ident => f. write_str( #enum_variant_display) ,
308352 } ) ;
309353 }
310354
311- None
355+ quote ! {
356+ #[ automatically_derived]
357+ pub enum Version {
358+ #enum_variant_idents
359+ }
360+
361+ #[ automatically_derived]
362+ impl :: std:: fmt:: Display for Version {
363+ fn fmt( & self , f: & mut :: std:: fmt:: Formatter <' _>) -> :: std:: result:: Result <( ) , :: std:: fmt:: Error > {
364+ match self {
365+ #enum_variant_matches
366+ }
367+ }
368+ }
369+ }
312370 }
313371}
0 commit comments