4
4
using System ;
5
5
using System . Collections . Generic ;
6
6
using System . Collections . ObjectModel ;
7
+ using System . Diagnostics ;
7
8
using System . IO ;
8
9
using System . Linq ;
9
10
using System . Net . Http ;
@@ -13,7 +14,11 @@ namespace KubernetesWatchGenerator
13
14
{
14
15
class Program
15
16
{
17
+ private static HashSet < string > _classesWithValidation ;
16
18
static readonly Dictionary < string , string > ClassNameMap = new Dictionary < string , string > ( ) ;
19
+ private static Dictionary < JsonSchema4 , string > _schemaToNameMap ;
20
+ private static HashSet < string > _schemaDefinitionsInMultipleGroups ;
21
+ private static Dictionary < string , string > _classNameToPluralMap ;
17
22
18
23
static async Task Main ( string [ ] args )
19
24
{
@@ -45,17 +50,47 @@ static async Task Main(string[] args)
45
50
46
51
// gen project removed all watch operations, so here we switch back to unprocessed version
47
52
swagger = await SwaggerDocument . FromFileAsync ( Path . Combine ( args [ 1 ] , "swagger.json.unprocessed" ) ) ;
53
+ _schemaToNameMap = swagger . Definitions . ToDictionary ( x => x . Value , x => x . Key ) ;
54
+ _schemaDefinitionsInMultipleGroups = _schemaToNameMap . Values . Select ( x =>
55
+ {
56
+ var parts = x . Split ( "." ) ;
57
+ return new { FullName = x , Name = parts [ parts . Length - 1 ] , Version = parts [ parts . Length - 2 ] , Group = parts [ parts . Length - 3 ] } ;
58
+ } )
59
+ . GroupBy ( x => new { x . Name , x . Version } )
60
+ . Where ( x => x . Count ( ) > 1 )
61
+ . SelectMany ( x => x )
62
+ . Select ( x => x . FullName )
63
+ . ToHashSet ( ) ;
64
+
65
+ _classNameToPluralMap = swagger . Operations
66
+ . Where ( x => x . Operation . OperationId . StartsWith ( "list" ) )
67
+ . Select ( x => { return new { PluralName = x . Path . Split ( "/" ) . Last ( ) , ClassName = GetClassNameForSchemaDefinition ( x . Operation . Responses [ "200" ] . ActualResponseSchema ) } ; } )
68
+ . Distinct ( )
69
+ . ToDictionary ( x => x . ClassName , x => x . PluralName ) ;
70
+
71
+ // dictionary only contains "list" plural maps. assign the same plural names to entities those lists support
72
+ _classNameToPluralMap = _classNameToPluralMap
73
+ . Where ( x => x . Key . EndsWith ( "List" ) )
74
+ . Select ( x =>
75
+ new { ClassName = x . Key . Remove ( x . Key . Length - 4 ) , PluralName = x . Value } )
76
+ . ToDictionary ( x => x . ClassName , x => x . PluralName )
77
+ . Union ( _classNameToPluralMap )
78
+ . ToDictionary ( x => x . Key , x => x . Value ) ;
79
+
80
+
48
81
49
82
// Register helpers used in the templating.
50
83
Helpers . Register ( nameof ( ToXmlDoc ) , ToXmlDoc ) ;
51
84
Helpers . Register ( nameof ( GetClassName ) , GetClassName ) ;
85
+ Helpers . Register ( nameof ( GetInterfaceName ) , GetInterfaceName ) ;
52
86
Helpers . Register ( nameof ( GetMethodName ) , GetMethodName ) ;
53
87
Helpers . Register ( nameof ( GetDotNetName ) , GetDotNetName ) ;
54
88
Helpers . Register ( nameof ( GetDotNetType ) , GetDotNetType ) ;
55
89
Helpers . Register ( nameof ( GetPathExpression ) , GetPathExpression ) ;
56
90
Helpers . Register ( nameof ( GetGroup ) , GetGroup ) ;
57
91
Helpers . Register ( nameof ( GetApiVersion ) , GetApiVersion ) ;
58
92
Helpers . Register ( nameof ( GetKind ) , GetKind ) ;
93
+ Helpers . Register ( nameof ( GetPlural ) , GetPlural ) ;
59
94
60
95
// Generate the Watcher operations
61
96
// We skip operations where the name of the class in the C# client could not be determined correctly.
@@ -85,6 +120,13 @@ static async Task Main(string[] args)
85
120
&& d . ExtensionData . ContainsKey ( "x-kubernetes-group-version-kind" )
86
121
&& ! skippedTypes . Contains ( GetClassName ( d ) ) ) ;
87
122
123
+ var modelsDir = Path . Combine ( outputDirectory , "Models" ) ;
124
+ _classesWithValidation = Directory . EnumerateFiles ( modelsDir )
125
+ . Select ( x => new { Class = Path . GetFileNameWithoutExtension ( x ) , Content = File . ReadAllText ( x ) } )
126
+ . Where ( x => x . Content . Contains ( "public virtual void Validate()" ) )
127
+ . Select ( x => x . Class )
128
+ . ToHashSet ( ) ;
129
+
88
130
Render . FileToFile ( "ModelExtensions.cs.template" , definitions , Path . Combine ( outputDirectory , "ModelExtensions.cs" ) ) ;
89
131
}
90
132
@@ -148,6 +190,66 @@ private static string GetClassName(JsonSchema4 definition)
148
190
149
191
return GetClassName ( groupVersionKind ) ;
150
192
}
193
+ private static void GetInterfaceName ( RenderContext context , IList < object > arguments , IDictionary < string , object > options , RenderBlock fn , RenderBlock inverse )
194
+ {
195
+
196
+ if ( arguments != null && arguments . Count > 0 && arguments [ 0 ] != null && arguments [ 0 ] is JsonSchema4 )
197
+ {
198
+ context . Write ( GetInterfaceName ( arguments [ 0 ] as JsonSchema4 ) ) ;
199
+ }
200
+
201
+ }
202
+
203
+ static string GetClassNameForSchemaDefinition ( JsonSchema4 definition )
204
+ {
205
+ if ( definition . ExtensionData != null && definition . ExtensionData . ContainsKey ( "x-kubernetes-group-version-kind" ) )
206
+ return GetClassName ( definition ) ;
207
+
208
+ var schemaName = _schemaToNameMap [ definition ] ;
209
+
210
+ var parts = schemaName . Split ( "." ) ;
211
+ var group = parts [ parts . Length - 3 ] ;
212
+ var version = parts [ parts . Length - 2 ] ;
213
+ var entityName = parts [ parts . Length - 1 ] ;
214
+ if ( ! _schemaDefinitionsInMultipleGroups . Contains ( schemaName ) )
215
+ group = null ;
216
+ var className = ToPascalCase ( $ "{ group } { version } { entityName } ") ;
217
+ return className ;
218
+
219
+ }
220
+ static string GetInterfaceName ( JsonSchema4 definition )
221
+ {
222
+ var groupVersionKindElements = ( object [ ] ) definition . ExtensionData [ "x-kubernetes-group-version-kind" ] ;
223
+ var groupVersionKind = ( Dictionary < string , object > ) groupVersionKindElements [ 0 ] ;
224
+
225
+ var group = groupVersionKind [ "group" ] as string ;
226
+ var version = groupVersionKind [ "version" ] as string ;
227
+ var kind = groupVersionKind [ "kind" ] as string ;
228
+ var className = GetClassName ( definition ) ;
229
+ var interfaces = new List < string > ( ) ;
230
+ interfaces . Add ( "IKubernetesObject" ) ;
231
+ if ( definition . Properties . TryGetValue ( "metadata" , out var metadataProperty ) )
232
+ {
233
+ interfaces . Add ( $ "IMetadata<{ GetClassNameForSchemaDefinition ( metadataProperty . Reference ) } >") ;
234
+ }
235
+
236
+ if ( definition . Properties . TryGetValue ( "items" , out var itemsProperty ) )
237
+ {
238
+ var schema = itemsProperty . Type == JsonObjectType . Object ? itemsProperty . Reference : itemsProperty . Item . Reference ;
239
+ interfaces . Add ( $ "IItems<{ GetClassNameForSchemaDefinition ( schema ) } >") ;
240
+ }
241
+
242
+ if ( definition . Properties . TryGetValue ( "spec" , out var specProperty ) )
243
+ {
244
+ interfaces . Add ( $ "ISpec<{ GetClassNameForSchemaDefinition ( specProperty . Reference ) } >") ;
245
+ }
246
+
247
+ if ( _classesWithValidation . Contains ( className ) )
248
+ interfaces . Add ( "IValidate" ) ;
249
+ var result = string . Join ( ", " , interfaces ) ;
250
+ return result ;
251
+ }
252
+
151
253
152
254
static void GetKind ( RenderContext context , IList < object > arguments , IDictionary < string , object > options , RenderBlock fn , RenderBlock inverse )
153
255
{
@@ -165,6 +267,24 @@ private static string GetKind(JsonSchema4 definition)
165
267
return groupVersionKind [ "kind" ] as string ;
166
268
}
167
269
270
+ static void GetPlural ( RenderContext context , IList < object > arguments , IDictionary < string , object > options , RenderBlock fn , RenderBlock inverse )
271
+ {
272
+ if ( arguments != null && arguments . Count > 0 && arguments [ 0 ] != null && arguments [ 0 ] is JsonSchema4 )
273
+ {
274
+ var plural = GetPlural ( arguments [ 0 ] as JsonSchema4 ) ;
275
+ if ( plural != null )
276
+ context . Write ( $ "\" { plural } \" ") ;
277
+ else
278
+ context . Write ( "null" ) ;
279
+ }
280
+ }
281
+
282
+ private static string GetPlural ( JsonSchema4 definition )
283
+ {
284
+ var className = GetClassNameForSchemaDefinition ( definition ) ;
285
+ return _classNameToPluralMap . GetValueOrDefault ( className , null ) ;
286
+ }
287
+
168
288
static void GetGroup ( RenderContext context , IList < object > arguments , IDictionary < string , object > options , RenderBlock fn , RenderBlock inverse )
169
289
{
170
290
if ( arguments != null && arguments . Count > 0 && arguments [ 0 ] != null && arguments [ 0 ] is JsonSchema4 )
0 commit comments