github.com/cilium/cilium@v1.16.2/tools/crdlistgen/main.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package main
     5  
     6  import (
     7  	"bufio"
     8  	"errors"
     9  	"fmt"
    10  	"io/fs"
    11  	"log/slog"
    12  	"os"
    13  	"path/filepath"
    14  	"sort"
    15  	"strings"
    16  
    17  	"github.com/cilium/hive/cell"
    18  
    19  	operatorServer "github.com/cilium/cilium/api/v1/operator/server"
    20  	"github.com/cilium/cilium/pkg/hive"
    21  	"github.com/cilium/cilium/pkg/k8s/apis/cilium.io/client"
    22  )
    23  
    24  var (
    25  	MainCell = cell.Module(
    26  		"main",
    27  		"Main module for generating CRD Lists",
    28  		cell.Invoke(printCRDList),
    29  	)
    30  
    31  	Hive = hive.New(
    32  		operatorServer.SpecCell,
    33  		MainCell,
    34  	)
    35  )
    36  
    37  var ErrorBreakEarly = fmt.Errorf("break early")
    38  
    39  func printCRDList(
    40  	opSpec *operatorServer.Spec,
    41  	shutdown hive.Shutdowner,
    42  ) error {
    43  	list := client.CustomResourceDefinitionList()
    44  
    45  	crdlist := []string{}
    46  
    47  	for _, crd := range list {
    48  		crdlist = append(crdlist, cleanupCRDName(crd.Name))
    49  	}
    50  
    51  	// Sort the list
    52  	sort.Strings(crdlist)
    53  
    54  	for idx, name := range crdlist {
    55  		// We need to walk ../../Documentation rst files to look and see if the CRD name is a header in the format of `.. _ <name>:`, if so
    56  		// add `ref:` to the name so it will link to the CRD in the docs.
    57  		err := filepath.WalkDir("./Documentation", func(path string, d fs.DirEntry, err error) error {
    58  			if err != nil {
    59  				return err
    60  			}
    61  
    62  			if filepath.Ext(path) == ".rst" {
    63  				match, err := grepFile(path, ".. _"+name+":")
    64  				if err != nil {
    65  					return err
    66  				}
    67  				// We can stop walking the documentation as we already know there is a match, so we send an ErrorBreakEarly and ignore that on the other side
    68  				// as WalkDir will keep running until it returns an error or there are no more files to walk.
    69  				if match {
    70  					// Change the name to a ref also specifically override the link text, as a couple headers add " CRD" to the text which causes the link to not be uniform.
    71  					crdlist[idx] = ":ref:`" + name + "<" + name + ">`"
    72  					return ErrorBreakEarly
    73  				}
    74  			}
    75  
    76  			return nil
    77  		})
    78  		if err != nil && !errors.Is(err, ErrorBreakEarly) {
    79  			return err
    80  		}
    81  	}
    82  
    83  	f, err := os.Create("Documentation/crdlist.rst")
    84  	if err != nil {
    85  		return err
    86  	}
    87  	defer f.Close()
    88  
    89  	for _, name := range crdlist {
    90  		_, err := f.WriteString(fmt.Sprintf("- %s\n", name))
    91  		if err != nil {
    92  			return err
    93  		}
    94  	}
    95  
    96  	shutdown.Shutdown()
    97  	return nil
    98  }
    99  
   100  // Scan file for string
   101  func grepFile(path, search string) (bool, error) {
   102  	//fmt.Printf("searching %s for %s\n", path, search)
   103  	f, err := os.Open(path)
   104  	if err != nil {
   105  		return false, err
   106  	}
   107  	defer f.Close()
   108  
   109  	scanner := bufio.NewScanner(f)
   110  	for scanner.Scan() {
   111  		if strings.Contains(scanner.Text(), search) {
   112  			return true, nil
   113  		}
   114  	}
   115  
   116  	return false, scanner.Err()
   117  }
   118  
   119  // Remove the /(version) portion from the CRD Name
   120  func cleanupCRDName(name string) string {
   121  	return strings.Split(name, "/")[0]
   122  }
   123  
   124  func main() {
   125  	Hive.Run(slog.Default())
   126  }