@@ -8,13 +8,17 @@ use syn::{parse_quote, DataStruct, Error, Ident};
8
8
use crate :: {
9
9
attrs:: common:: ContainerAttributes ,
10
10
codegen:: {
11
- common:: { Container , ContainerInput , ContainerVersion , Item , VersionedContainer } ,
11
+ common:: {
12
+ Container , ContainerInput , ContainerVersion , Item , VersionExt , VersionedContainer ,
13
+ } ,
12
14
vstruct:: field:: VersionedField ,
13
15
} ,
14
16
} ;
15
17
16
18
pub ( crate ) mod field;
17
19
20
+ type GenerateVersionReturn = ( TokenStream , Option < ( TokenStream , ( Ident , String ) ) > ) ;
21
+
18
22
/// Stores individual versions of a single struct. Each version tracks field
19
23
/// actions, which describe if the field was added, renamed or deprecated in
20
24
/// that version. Fields which are not versioned, are included in every
@@ -85,24 +89,30 @@ impl Container<DataStruct, VersionedField> for VersionedStruct {
85
89
}
86
90
87
91
fn generate_tokens ( & self ) -> TokenStream {
88
- let mut kubernetes_crd_fn_calls = TokenStream :: new ( ) ;
89
- let mut container_definition = TokenStream :: new ( ) ;
92
+ let mut tokens = TokenStream :: new ( ) ;
93
+
94
+ let mut enum_variants = Vec :: new ( ) ;
95
+ let mut crd_fn_calls = Vec :: new ( ) ;
90
96
91
97
let mut versions = self . versions . iter ( ) . peekable ( ) ;
92
98
93
99
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) ) ;
100
+ let ( container_definition, merged_crd) =
101
+ self . generate_version ( version, versions. peek ( ) . copied ( ) ) ;
102
+
103
+ if let Some ( ( crd_fn_call, enum_variant) ) = merged_crd {
104
+ enum_variants. push ( enum_variant) ;
105
+ crd_fn_calls. push ( crd_fn_call) ;
106
+ }
107
+
108
+ tokens. extend ( container_definition) ;
96
109
}
97
110
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) ) ;
111
+ if !crd_fn_calls. is_empty ( ) {
112
+ tokens. extend ( self . generate_kubernetes_merge_crds ( crd_fn_calls, enum_variants) ) ;
103
113
}
104
114
105
- container_definition
115
+ tokens
106
116
}
107
117
}
108
118
@@ -112,7 +122,7 @@ impl VersionedStruct {
112
122
& self ,
113
123
version : & ContainerVersion ,
114
124
next_version : Option < & ContainerVersion > ,
115
- ) -> TokenStream {
125
+ ) -> GenerateVersionReturn {
116
126
let mut token_stream = TokenStream :: new ( ) ;
117
127
118
128
let original_attributes = & self . original_attributes ;
@@ -137,7 +147,27 @@ impl VersionedStruct {
137
147
let version_specific_docs = self . generate_struct_docs ( version) ;
138
148
139
149
// Generate K8s specific code
140
- let kubernetes_cr_derive = self . generate_kubernetes_cr_derive ( version) ;
150
+ let ( kubernetes_cr_derive, merged_crd) = match & self . options . kubernetes_options {
151
+ Some ( options) => {
152
+ // Generate the CustomResource derive macro with the appropriate
153
+ // attributes supplied using #[kube()].
154
+ let cr_derive = self . generate_kubernetes_cr_derive ( version) ;
155
+
156
+ // Generate merged_crd specific code when not opted out.
157
+ let merged_crd = if !options. skip_merged_crd {
158
+ let crd_fn_call = self . generate_kubernetes_crd_fn_call ( version) ;
159
+ let enum_variant = version. inner . as_variant_ident ( ) ;
160
+ let enum_display = version. inner . to_string ( ) ;
161
+
162
+ Some ( ( crd_fn_call, ( enum_variant, enum_display) ) )
163
+ } else {
164
+ None
165
+ } ;
166
+
167
+ ( Some ( cr_derive) , merged_crd)
168
+ }
169
+ None => ( None , None ) ,
170
+ } ;
141
171
142
172
// Generate tokens for the module and the contained struct
143
173
token_stream. extend ( quote ! {
@@ -160,7 +190,7 @@ impl VersionedStruct {
160
190
token_stream. extend ( self . generate_from_impl ( version, next_version) ) ;
161
191
}
162
192
163
- token_stream
193
+ ( token_stream, merged_crd )
164
194
}
165
195
166
196
/// Generates version specific doc comments for the struct.
@@ -284,44 +314,71 @@ impl VersionedStruct {
284
314
}
285
315
286
316
/// Generates the `merge_crds` function call.
287
- fn generate_kubernetes_merge_crds ( & self , fn_calls : TokenStream ) -> TokenStream {
317
+ fn generate_kubernetes_merge_crds (
318
+ & self ,
319
+ crd_fn_calls : Vec < TokenStream > ,
320
+ enum_variants : Vec < ( Ident , String ) > ,
321
+ ) -> TokenStream {
288
322
let ident = & self . idents . kubernetes ;
289
323
324
+ let version_enum_definition = self . generate_kubernetes_version_enum ( enum_variants) ;
325
+
290
326
quote ! {
291
327
#[ automatically_derived]
292
328
pub struct #ident;
293
329
330
+ #version_enum_definition
331
+
294
332
#[ automatically_derived]
295
333
impl #ident {
296
334
/// Generates a merged CRD which contains all versions defined using the
297
335
/// `#[versioned()]` macro.
298
336
pub fn merged_crd(
299
- stored_apiversion: & str
337
+ stored_apiversion: Version
300
338
) -> :: std:: result:: Result <:: k8s_openapi:: apiextensions_apiserver:: pkg:: apis:: apiextensions:: v1:: CustomResourceDefinition , :: kube:: core:: crd:: MergeError > {
301
- :: kube:: core:: crd:: merge_crds( vec![ #fn_calls ] , stored_apiversion)
339
+ :: kube:: core:: crd:: merge_crds( vec![ #( #crd_fn_calls ) , * ] , & stored_apiversion. to_string ( ) )
302
340
}
303
341
}
304
342
}
305
343
}
306
344
307
345
/// Generates the inner `crd()` functions calls which get used in the
308
346
/// `merge_crds` function.
309
- fn generate_kubernetes_crd_fn_call ( & self , version : & ContainerVersion ) -> Option < TokenStream > {
310
- if self
311
- . options
312
- . kubernetes_options
313
- . as_ref ( )
314
- . is_some_and ( |o| !o. skip_merged_crd )
315
- {
316
- let struct_ident = & self . idents . kubernetes ;
317
- let version_ident = & version. ident ;
318
-
319
- let path: syn:: Path = parse_quote ! ( #version_ident:: #struct_ident) ;
320
- return Some ( quote ! {
321
- <#path as :: kube:: CustomResourceExt >:: crd( ) ,
347
+ fn generate_kubernetes_crd_fn_call ( & self , version : & ContainerVersion ) -> TokenStream {
348
+ let struct_ident = & self . idents . kubernetes ;
349
+ let version_ident = & version. ident ;
350
+ let path: syn:: Path = parse_quote ! ( #version_ident:: #struct_ident) ;
351
+
352
+ quote ! {
353
+ <#path as :: kube:: CustomResourceExt >:: crd( )
354
+ }
355
+ }
356
+
357
+ fn generate_kubernetes_version_enum ( & self , enum_variants : Vec < ( Ident , String ) > ) -> TokenStream {
358
+ let mut enum_variant_matches = TokenStream :: new ( ) ;
359
+ let mut enum_variant_idents = TokenStream :: new ( ) ;
360
+
361
+ for ( enum_variant_ident, enum_variant_display) in enum_variants {
362
+ enum_variant_idents. extend ( quote ! { #enum_variant_ident, } ) ;
363
+ enum_variant_matches. extend ( quote ! {
364
+ Version :: #enum_variant_ident => f. write_str( #enum_variant_display) ,
322
365
} ) ;
323
366
}
324
367
325
- None
368
+ quote ! {
369
+ #[ automatically_derived]
370
+ pub enum Version {
371
+ #enum_variant_idents
372
+ }
373
+
374
+ #[ automatically_derived]
375
+ impl :: std:: fmt:: Display for Version {
376
+ fn fmt( & self , f: & mut :: std:: fmt:: Formatter <' _>) -> :: std:: result:: Result <( ) , :: std:: fmt:: Error > {
377
+ match self {
378
+ #enum_variant_matches
379
+ }
380
+ }
381
+ }
382
+ }
326
383
}
327
384
}
0 commit comments