1515 */
1616package io .fabric8 .crd .generator ;
1717
18+ import io .fabric8 .crd .generator .AbstractJsonSchema .AnnotationMetadata ;
19+ import io .fabric8 .crd .generator .annotation .PrinterColumn ;
1820import io .fabric8 .crd .generator .decorator .Decorator ;
19- import io .fabric8 .crd .generator .visitor .*;
2021import io .fabric8 .kubernetes .client .utils .Utils ;
21- import io .sundr .builder .Visitor ;
22- import io .sundr .model .AnnotationRef ;
23- import io .sundr .model .Property ;
24- import io .sundr .model .TypeDef ;
25- import io .sundr .model .TypeDefBuilder ;
2622
27- import java .util .ArrayList ;
28- import java .util .Collections ;
29- import java .util .HashMap ;
30- import java .util .List ;
3123import java .util .Map ;
32- import java .util .Optional ;
33- import java .util .concurrent .CompletableFuture ;
34- import java .util .concurrent .ExecutionException ;
35- import java .util .concurrent .ExecutorService ;
36- import java .util .concurrent .Executors ;
37- import java .util .stream .Collectors ;
3824
3925/**
4026 * This class encapsulates the common behavior between v1beta1 and v1 CRD generation logic. The
4329public abstract class AbstractCustomResourceHandler {
4430
4531 protected final Resources resources ;
46- private final boolean parallel ;
4732
48- protected AbstractCustomResourceHandler (Resources resources , boolean parallel ) {
33+ protected AbstractCustomResourceHandler (Resources resources ) {
4934 this .resources = resources ;
50- this .parallel = parallel ;
5135 }
5236
53- public void handle (CustomResourceInfo config ) {
54- final String name = config .crdName ();
55- final String version = config .version ();
37+ public abstract void handle (CustomResourceInfo config );
5638
57- TypeDef def = config .definition ();
58-
59- SpecReplicasPathDetector specReplicasPathDetector = new SpecReplicasPathDetector ();
60- StatusReplicasPathDetector statusReplicasPathDetector = new StatusReplicasPathDetector ();
61- LabelSelectorPathDetector labelSelectorPathDetector = new LabelSelectorPathDetector ();
62- AdditionalPrinterColumnDetector additionalPrinterColumnDetector = new AdditionalPrinterColumnDetector ();
63-
64- ClassDependenciesVisitor traversedClassesVisitor = new ClassDependenciesVisitor (config .crClassName (), name );
65-
66- List <Visitor <TypeDefBuilder >> visitors = new ArrayList <>();
67- if (config .specClassName ().isPresent ()) {
68- visitors .add (specReplicasPathDetector );
69- }
70- if (config .statusClassName ().isPresent ()) {
71- visitors .add (statusReplicasPathDetector );
72- }
73- visitors .add (labelSelectorPathDetector );
74- visitors .add (additionalPrinterColumnDetector );
75- visitors .add (traversedClassesVisitor );
76-
77- visitTypeDef (def , visitors );
78-
79- addDecorators (config , def , specReplicasPathDetector .getPath (),
80- statusReplicasPathDetector .getPath (), labelSelectorPathDetector .getPath ());
81-
82- Map <String , Property > additionalPrinterColumns = new HashMap <>(additionalPrinterColumnDetector .getProperties ());
39+ protected void handlePrinterColumns (String name , String version , Map <String , AnnotationMetadata > additionalPrinterColumns ) {
8340 additionalPrinterColumns .forEach ((path , property ) -> {
84- Map <String , Object > parameters = property .getAnnotations ().stream ()
85- .filter (a -> a .getClassRef ().getName ().equals ("PrinterColumn" )).map (AnnotationRef ::getParameters )
86- .findFirst ().orElse (Collections .emptyMap ());
87- String type = AbstractJsonSchema .getSchemaTypeFor (property .getTypeRef ());
88- String column = (String ) parameters .get ("name" );
41+ PrinterColumn printerColumn = ((PrinterColumn )property .annotation );
42+ String column = printerColumn .name ();
8943 if (Utils .isNullOrEmpty (column )) {
90- column = property . getName (). toUpperCase ( );
44+ column = path . substring ( path . lastIndexOf ( "." ) );
9145 }
92- String description = property .getComments ().stream ().filter (l -> !l .trim ().startsWith ("@" ))
93- .collect (Collectors .joining (" " )).trim ();
94- String format = (String ) parameters .get ("format" );
95- int priority = (int ) parameters .getOrDefault ("priority" , 0 );
46+ String format = printerColumn .format ();
47+ int priority = printerColumn .priority ();
48+
49+ // TODO: add description to the annotation? The previous logic considered the comments, which are not available here
50+ String description = property .description ;
9651
9752 resources .decorate (
98- getPrinterColumnDecorator (name , version , path , type , column , description , format , priority ));
53+ getPrinterColumnDecorator (name , version , path , property . type , column , description , format , priority ));
9954 });
10055 }
10156
102- private TypeDef visitTypeDef (TypeDef def , List <Visitor <TypeDefBuilder >> visitors ) {
103- if (visitors .isEmpty ()) {
104- return def ;
105- }
106- if (parallel ) {
107- return visitTypeDefInParallel (def , visitors );
108- } else {
109- return visitTypeDefSequentially (def , visitors );
110- }
111- }
112-
113- private TypeDef visitTypeDefSequentially (TypeDef def , List <Visitor <TypeDefBuilder >> visitors ) {
114- TypeDefBuilder builder = new TypeDefBuilder (def );
115- for (Visitor <TypeDefBuilder > visitor : visitors ) {
116- builder .accept (visitor );
117- }
118- return builder .build ();
119- }
120-
121- private TypeDef visitTypeDefInParallel (TypeDef def , List <Visitor <TypeDefBuilder >> visitors ) {
122- final ExecutorService executorService = Executors .newFixedThreadPool (
123- Math .min (visitors .size (), Runtime .getRuntime ().availableProcessors ()));
124- try {
125- List <CompletableFuture <Void >> futures = new ArrayList <>();
126- for (Visitor <TypeDefBuilder > visitor : visitors ) {
127- futures .add (CompletableFuture .runAsync (() -> {
128- // in this case we're not building a new typedef,
129- // instead we just need to traverse the object graph.
130- TypeDefBuilder builder = new TypeDefBuilder (def );
131- builder .accept (visitor );
132- }, executorService ));
133- }
134- try {
135- CompletableFuture .allOf (futures .toArray (new CompletableFuture [0 ])).get ();
136- } catch (InterruptedException interruptedException ) {
137- Thread .currentThread ().interrupt ();
138- } catch (ExecutionException ex ) {
139- if (ex .getCause () instanceof RuntimeException ) {
140- throw (RuntimeException ) ex .getCause ();
141- }
142- throw new RuntimeException (ex .getCause ());
143- }
144- } finally {
145- executorService .shutdown ();
146- }
147- return def ;
148- }
149-
15057 /**
15158 * Provides the decorator implementation associated with the CRD generation version.
15259 *
@@ -162,19 +69,4 @@ private TypeDef visitTypeDefInParallel(TypeDef def, List<Visitor<TypeDefBuilder>
16269 protected abstract Decorator <?> getPrinterColumnDecorator (String name , String version , String path ,
16370 String type , String column , String description , String format , int priority );
16471
165- /**
166- * Adds all the necessary decorators to build the specific CRD version. For optional paths, see
167- * https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#customresourcesubresourcescale-v1-apiextensions-k8s-io
168- * These paths
169- *
170- * @param config the gathered {@link CustomResourceInfo} used as basis for the CRD generation
171- * @param def the {@link TypeDef} associated with the {@link io.fabric8.kubernetes.client.CustomResource} from which the CRD
172- * is generated
173- * @param specReplicasPath an optionally detected path of field defining spec replicas
174- * @param statusReplicasPath an optionally detected path of field defining status replicas
175- * @param labelSelectorPath an optionally detected path of field defining `status.selector`
176- */
177- protected abstract void addDecorators (CustomResourceInfo config , TypeDef def ,
178- Optional <String > specReplicasPath , Optional <String > statusReplicasPath ,
179- Optional <String > labelSelectorPath );
18072}
0 commit comments