1
- use darling:: FromDeriveInput ;
1
+ use darling:: { FromDeriveInput , FromMeta } ;
2
2
use proc_macro2:: { Ident , Span , TokenStream } ;
3
3
use syn:: { parse_quote, Data , DeriveInput , Path , Visibility } ;
4
4
@@ -24,6 +24,8 @@ struct KubeAttrs {
24
24
#[ darling( multiple, rename = "derive" ) ]
25
25
derives : Vec < String > ,
26
26
#[ darling( default ) ]
27
+ schema : Option < SchemaMode > ,
28
+ #[ darling( default ) ]
27
29
status : Option < String > ,
28
30
#[ darling( multiple, rename = "category" ) ]
29
31
categories : Vec < String > ,
@@ -33,35 +35,92 @@ struct KubeAttrs {
33
35
printcolums : Vec < String > ,
34
36
#[ darling( default ) ]
35
37
scale : Option < String > ,
36
- #[ darling( default = "default_kube_core" ) ]
38
+ #[ darling( default ) ]
39
+ crates : Crates ,
40
+ }
41
+
42
+ #[ derive( Debug , FromMeta ) ]
43
+ struct Crates {
44
+ #[ darling( default = "Self::default_kube_core" ) ]
37
45
kube_core : Path ,
38
- #[ darling( default = "default_k8s_openapi" ) ]
46
+ #[ darling( default = "Self:: default_k8s_openapi" ) ]
39
47
k8s_openapi : Path ,
40
- #[ darling( default = "default_schemars" ) ]
48
+ #[ darling( default = "Self:: default_schemars" ) ]
41
49
schemars : Path ,
42
- #[ darling( default = "default_serde" ) ]
50
+ #[ darling( default = "Self:: default_serde" ) ]
43
51
serde : Path ,
44
- #[ darling( default = "default_serde_json" ) ]
52
+ #[ darling( default = "Self:: default_serde_json" ) ]
45
53
serde_json : Path ,
46
54
}
47
55
48
- fn default_apiext ( ) -> String {
49
- "v1" . to_owned ( )
56
+ // Default is required when the subattribute isn't mentioned at all
57
+ // Delegate to darling rather than deriving, so that we can piggyback off the `#[darling(default)]` clauses
58
+ impl Default for Crates {
59
+ fn default ( ) -> Self {
60
+ Self :: from_list ( & [ ] ) . unwrap ( )
61
+ }
50
62
}
51
- fn default_kube_core ( ) -> Path {
52
- parse_quote ! { :: kube:: core } // by default must work well with people using facade crate
63
+
64
+ impl Crates {
65
+ fn default_kube_core ( ) -> Path {
66
+ parse_quote ! { :: kube:: core } // by default must work well with people using facade crate
67
+ }
68
+
69
+ fn default_k8s_openapi ( ) -> Path {
70
+ parse_quote ! { :: k8s_openapi }
71
+ }
72
+
73
+ fn default_schemars ( ) -> Path {
74
+ parse_quote ! { :: schemars }
75
+ }
76
+
77
+ fn default_serde ( ) -> Path {
78
+ parse_quote ! { :: serde }
79
+ }
80
+
81
+ fn default_serde_json ( ) -> Path {
82
+ parse_quote ! { :: serde_json }
83
+ }
53
84
}
54
- fn default_k8s_openapi ( ) -> Path {
55
- parse_quote ! { :: k8s_openapi }
85
+
86
+ fn default_apiext ( ) -> String {
87
+ "v1" . to_owned ( )
56
88
}
57
- fn default_schemars ( ) -> Path {
58
- parse_quote ! { :: schemars }
89
+
90
+ #[ derive( Debug , PartialEq , Eq , Clone , Copy ) ]
91
+ enum SchemaMode {
92
+ Disabled ,
93
+ Manual ,
94
+ Derived ,
59
95
}
60
- fn default_serde ( ) -> Path {
61
- parse_quote ! { :: serde }
96
+
97
+ impl SchemaMode {
98
+ fn derive ( self ) -> bool {
99
+ match self {
100
+ SchemaMode :: Disabled => false ,
101
+ SchemaMode :: Manual => false ,
102
+ SchemaMode :: Derived => true ,
103
+ }
104
+ }
105
+
106
+ fn use_in_crd ( self ) -> bool {
107
+ match self {
108
+ SchemaMode :: Disabled => false ,
109
+ SchemaMode :: Manual => true ,
110
+ SchemaMode :: Derived => true ,
111
+ }
112
+ }
62
113
}
63
- fn default_serde_json ( ) -> Path {
64
- parse_quote ! { :: serde_json }
114
+
115
+ impl FromMeta for SchemaMode {
116
+ fn from_string ( value : & str ) -> darling:: Result < Self > {
117
+ match value {
118
+ "disabled" => Ok ( SchemaMode :: Disabled ) ,
119
+ "manual" => Ok ( SchemaMode :: Manual ) ,
120
+ "derived" => Ok ( SchemaMode :: Derived ) ,
121
+ x => Err ( darling:: Error :: unknown_value ( x) ) ,
122
+ }
123
+ }
65
124
}
66
125
67
126
pub ( crate ) fn derive ( input : proc_macro2:: TokenStream ) -> proc_macro2:: TokenStream {
@@ -92,6 +151,7 @@ pub(crate) fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStrea
92
151
version,
93
152
namespaced,
94
153
derives,
154
+ schema : schema_mode,
95
155
status,
96
156
plural,
97
157
singular,
@@ -100,11 +160,14 @@ pub(crate) fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStrea
100
160
printcolums,
101
161
apiextensions,
102
162
scale,
103
- kube_core,
104
- k8s_openapi,
105
- schemars,
106
- serde,
107
- serde_json,
163
+ crates :
164
+ Crates {
165
+ kube_core,
166
+ k8s_openapi,
167
+ schemars,
168
+ serde,
169
+ serde_json,
170
+ } ,
108
171
} = kube_attrs;
109
172
110
173
let struct_name = kind_struct. unwrap_or_else ( || kind. clone ( ) ) ;
@@ -152,18 +215,21 @@ pub(crate) fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStrea
152
215
}
153
216
}
154
217
155
- // Schema generation is always enabled for v1 because it's mandatory.
156
- // TODO Enable schema generation for v1beta1 if the spec derives `JsonSchema`.
157
- let schema_gen_enabled = apiextensions == "v1" && cfg ! ( feature = "schema" ) ;
218
+ // Enable schema generation by default for v1 because it's mandatory.
219
+ let schema_mode = schema_mode. unwrap_or ( if apiextensions == "v1" {
220
+ SchemaMode :: Derived
221
+ } else {
222
+ SchemaMode :: Disabled
223
+ } ) ;
158
224
// We exclude fields `apiVersion`, `kind`, and `metadata` from our schema because
159
225
// these are validated by the API server implicitly. Also, we can't generate the
160
226
// schema for `metadata` (`ObjectMeta`) because it doesn't implement `JsonSchema`.
161
- let schemars_skip = if schema_gen_enabled {
227
+ let schemars_skip = if schema_mode . derive ( ) {
162
228
quote ! { #[ schemars( skip) ] }
163
229
} else {
164
230
quote ! { }
165
231
} ;
166
- if schema_gen_enabled {
232
+ if schema_mode . derive ( ) {
167
233
derive_paths. push ( syn:: parse_quote! { #schemars:: JsonSchema } ) ;
168
234
}
169
235
@@ -289,7 +355,7 @@ pub(crate) fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStrea
289
355
let crd_meta_name = format ! ( "{}.{}" , plural, group) ;
290
356
let crd_meta = quote ! { { "name" : #crd_meta_name } } ;
291
357
292
- let schemagen = if schema_gen_enabled {
358
+ let schemagen = if schema_mode . use_in_crd ( ) {
293
359
quote ! {
294
360
// Don't use definitions and don't include `$schema` because these are not allowed.
295
361
let gen = #schemars:: gen :: SchemaSettings :: openapi3( ) . with( |s| {
0 commit comments