in dev/tools/controllerbuilder/pkg/commands/generatetypes/generatetypescommand.go [91:193]
func RunGenerateCRD(ctx context.Context, o *GenerateCRDOptions) error {
log := klog.FromContext(ctx)
gv, err := schema.ParseGroupVersion(o.APIVersion)
if err != nil {
return fmt.Errorf("APIVersion %q is not valid: %w", o.APIVersion, err)
}
api, err := protoapi.LoadProto(o.GenerateOptions.ProtoSourcePath)
if err != nil {
return fmt.Errorf("loading proto: %w", err)
}
goPackage := strings.TrimSuffix(gv.Group, ".cnrm.cloud.google.com") + "/" + gv.Version
scaffolder := &scaffold.APIScaffolder{
BaseDir: o.OutputAPIDirectory,
GoPackage: goPackage,
Group: gv.Group,
Version: gv.Version,
PackageProtoTag: o.ServiceName,
}
if scaffolder.DocFileNotExist() {
if err := scaffolder.AddDocFile(); err != nil {
return fmt.Errorf("add doc.go file: %w", err)
}
}
if scaffolder.GroupVersionFileNotExist() {
if err := scaffolder.AddGroupVersionFile(); err != nil {
return fmt.Errorf("add groupversion_info.go file: %w", err)
}
}
typeGenerator := codegen.NewTypeGenerator(goPackage, o.OutputAPIDirectory, api)
resourceAnnotations := make([]string, 0, len(o.Resources))
for _, resource := range o.Resources {
resourceProtoFullName := resource.ProtoMessageFullName(o.ServiceName)
log.Info("visiting proto", "name", resourceProtoFullName)
if err := typeGenerator.VisitProto(resourceProtoFullName); err != nil {
return err
}
resourceAnnotations = append(resourceAnnotations, fmt.Sprintf("%s:%s", resource.Kind, resource.ProtoName))
}
generatedFileAnnotation := &annotations.FileAnnotation{
Key: "+generated:types",
Attributes: map[string][]string{
"proto.service": {o.ServiceName},
"krm.group": {gv.Group},
"krm.version": {gv.Version},
"resource": resourceAnnotations,
},
}
typeGenerator = typeGenerator.WithGeneratedFileAnnotation(generatedFileAnnotation)
if err := typeGenerator.WriteVisitedMessages(); err != nil {
return err
}
if err := typeGenerator.WriteOutputMessages(); err != nil {
return err
}
for _, resource := range o.Resources { // A separate loop is needed to scaffold files AFTER all the visited messages have been generated.
skipScaffold := o.SkipScaffoldFiles || resource.SkipScaffoldFiles
if skipScaffold {
log.Info("skipping scaffolding type, refs and identity files", "resource", resource.ProtoName)
} else {
if scaffolder.TypeFileExists(resource) {
fmt.Printf("file %s already exists, skipping\n", scaffolder.PathToTypeFile(resource))
} else {
err := scaffolder.AddTypeFile(resource)
if err != nil {
return fmt.Errorf("add type file %s: %w", scaffolder.PathToTypeFile(resource), err)
}
}
if scaffolder.RefsFileExist(resource) {
fmt.Printf("file %s already exists, skipping\n", scaffolder.PathToRefsFile(resource))
} else {
err := scaffolder.AddRefsFile(resource)
if err != nil {
return fmt.Errorf("add refs file %s: %w", scaffolder.PathToRefsFile(resource), err)
}
}
if scaffolder.IdentityFileExist(resource) {
fmt.Printf("file %s already exists, skipping\n", scaffolder.PathToIdentityFile(resource))
} else {
err := scaffolder.AddIdentityFile(resource)
if err != nil {
return fmt.Errorf("add identity file %s: %w", scaffolder.PathToIdentityFile(resource), err)
}
}
}
}
addCopyright := true
if err := typeGenerator.WriteFiles(addCopyright); err != nil {
return err
}
return nil
}