This is an automated email from the ASF dual-hosted git repository.
zhongxjian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git
The following commit(s) were added to refs/heads/master by this push:
new cc12f6c9 Migrate tools (#883)
cc12f6c9 is described below
commit cc12f6c925278d4878a0274b6ee3a3f5054f3e96
Author: Joe Zhong <[email protected]>
AuthorDate: Tue Mar 24 20:08:52 2026 +0800
Migrate tools (#883)
* Update README
* Migrate tools
---
tools/annotations_prep/main.go | 501 ----------
tools/build-tools/docker/Dockerfile | 148 ---
tools/cmd/kubetype-gen/boilerplate.go.txt | 15 -
tools/cmd/kubetype-gen/generators/naming.go | 50 -
tools/cmd/kubetype-gen/generators/package.go | 58 --
tools/cmd/kubetype-gen/generators/register.go | 135 ---
tools/cmd/kubetype-gen/generators/types.go | 141 ---
tools/cmd/kubetype-gen/main.go | 48 -
tools/cmd/kubetype-gen/metadata/metadata.go | 224 -----
tools/cmd/kubetype-gen/scanner/scanner.go | 243 -----
tools/cmd/protoc-gen-crd/main.go | 101 --
tools/cmd/protoc-gen-crd/openapiGenerator.go | 1025 --------------------
tools/cmd/protoc-gen-crd/pkg/protocgen/generate.go | 62 --
.../cmd/protoc-gen-crd/pkg/protomodel/baseDesc.go | 125 ---
.../pkg/protomodel/enumDescriptor.go | 63 --
.../pkg/protomodel/fileDescriptor.go | 97 --
.../protoc-gen-crd/pkg/protomodel/frontMatter.go | 116 ---
.../pkg/protomodel/locationDescriptor.go | 33 -
.../pkg/protomodel/messageDescriptor.go | 80 --
tools/cmd/protoc-gen-crd/pkg/protomodel/model.go | 180 ----
.../pkg/protomodel/packageDescriptor.go | 73 --
.../protoc-gen-crd/pkg/protomodel/pathVector.go | 64 --
.../pkg/protomodel/serviceDescriptor.go | 57 --
tools/scripts/run.sh | 43 -
tools/scripts/setup_env.sh | 130 ---
tools/scripts/update_crds.sh | 6 -
26 files changed, 3818 deletions(-)
diff --git a/tools/annotations_prep/main.go b/tools/annotations_prep/main.go
deleted file mode 100644
index a3643275..00000000
--- a/tools/annotations_prep/main.go
+++ /dev/null
@@ -1,501 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "bytes"
- "flag"
- "fmt"
- "log"
- "os"
- "path/filepath"
- "regexp"
- "sort"
- "strings"
- "text/template"
-
- "github.com/gomarkdown/markdown"
- "github.com/gomarkdown/markdown/html"
- "github.com/gomarkdown/markdown/parser"
- "github.com/spf13/cobra"
- "sigs.k8s.io/yaml"
-)
-
-const (
- outputTemplate = `
-// GENERATED FILE -- DO NOT EDIT
-
-package {{ .Package }}
-
-type FeatureStatus int
-
-const (
- Alpha FeatureStatus = iota
- Beta
- Stable
-)
-
-func (s FeatureStatus) String() string {
- switch s {
- case Alpha:
- return "Alpha"
- case Beta:
- return "Beta"
- case Stable:
- return "Stable"
- }
- return "Unknown"
-}
-
-type ResourceTypes int
-
-const (
- Unknown ResourceTypes = iota
- {{- range .KnownTypes }}
- {{ . }}
- {{- end }}
-)
-
-func (r ResourceTypes) String() string {
- switch r {
- {{- range $i, $t := .KnownTypes }}
- case {{ add $i 1 }}:
- return "{{$t}}"
- {{- end }}
- }
- return "Unknown"
-}
-
-// Instance describes a single resource {{ .Collection.NameLowercase }}
-type Instance struct {
- // The name of the {{ .Collection.NameLowercase }}.
- Name string
-
- // Description of the {{ .Collection.NameLowercase }}.
- Description string
-
- // FeatureStatus of this {{ .Collection.NameLowercase }}.
- FeatureStatus FeatureStatus
-
- // Hide the existence of this {{ .Collection.NameLowercase }} when
outputting usage information.
- Hidden bool
-
- // Mark this {{ .Collection.NameLowercase }} as deprecated when
generating usage information.
- Deprecated bool
-
- // The types of resources this {{ .Collection.NameLowercase }} applies
to.
- Resources []ResourceTypes
-}
-
-var (
-{{ range .Variables }}
- {{ .GoName }} = Instance {
- Name: "{{ .Name }}",
- Description: {{ processGoDescription .Description 24 }},
- FeatureStatus: {{ .FeatureStatus }},
- Hidden: {{ .Hidden }},
- Deprecated: {{ .Deprecated }},
- Resources: []ResourceTypes{
- {{- range .Resources }}
- {{ . }},
- {{- end }}
- },
- }
-{{ end }}
-)
-
-func AllResource{{ .Collection.NamePlural }}() []*Instance {
- return []*Instance {
- {{- range .Variables }}
- &{{ .GoName }},
- {{- end }}
- }
-}
-
-func AllResourceTypes() []string {
- return []string {
- {{- range .KnownTypes }}
- "{{ . }}",
- {{- end }}
- }
-}
-`
-)
-
-type FeatureStatus string
-
-const (
- Alpha FeatureStatus = "Alpha"
- Beta FeatureStatus = "Beta"
- Stable FeatureStatus = "Stable"
-)
-
-type Collection struct {
- Name string
- NamePlural string
- NameLowercase string
- NameLowercasePlural string
- ConceptLink string
-}
-
-var (
- annotations = Collection{
- Name: "Annotation",
- NamePlural: "Annotations",
- NameLowercase: "annotation",
- NameLowercasePlural: "annotations",
- ConceptLink:
"https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/",
- }
-
- labels = Collection{
- Name: "Label",
- NamePlural: "Labels",
- NameLowercase: "label",
- NameLowercasePlural: "labels",
- ConceptLink:
"https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/",
- }
-)
-
-func collectionForType(typ string) (Collection, error) {
- switch typ {
- case annotations.NameLowercase:
- return annotations, nil
- case labels.NameLowercase:
- return labels, nil
- default:
- return Collection{}, fmt.Errorf("unrecognized variable_type:
%s", typ)
- }
-}
-
-var (
- input string
- output string
- collectionType string
- collection Collection
-
- nameSeparator = regexp.MustCompile(`[._\-]`)
-
- rootCmd = cobra.Command{
- Use: "metadata",
- Short: "Generates a Go source file and HTML file containing
annotations/labels.",
- Long: "Generates a Go source file and HTML file containing
annotation/label definitions based " +
- "on an input YAML file.",
- Run: func(cmd *cobra.Command, args []string) {
- processFlags()
- yamlContent, err := os.ReadFile(input)
- if err != nil {
- log.Fatalf("unable to read input YAML file:
%v", err)
- }
-
- // Unmarshal the file.
- var variables []Variable
- switch collectionType {
- case annotations.NameLowercase:
- var cfg AnnotationConfiguration
- if err = yaml.Unmarshal(yamlContent, &cfg); err
!= nil {
- log.Fatalf("error parsing input YAML
file: %v", err)
- }
- variables = cfg.Variables
- case labels.NameLowercase:
- var cfg LabelConfiguration
- if err = yaml.Unmarshal(yamlContent, &cfg); err
!= nil {
- log.Fatalf("error parsing input YAML
file: %v", err)
- }
- variables = cfg.Variables
- default:
- log.Fatalf("invalid value for collection_type:
%s", collectionType)
- }
-
- // Find all the known resource types
- m := make(map[string]bool)
- for _, a := range variables {
- for _, r := range a.Resources {
- m[r] = true
- }
- }
- knownTypes := make([]string, 0, len(m))
- for k := range m {
- knownTypes = append(knownTypes, k)
- }
- sort.Strings(knownTypes)
-
- // Process/cleanup the values read in from YAML.
- for i := range variables {
- if variables[i].Name == "" {
- log.Fatalf("variable %d in input YAML
file missing name", i)
- }
-
- // Generate sensible defaults for values if not
provided in the yaml.
- variables[i].GoName =
generateVariableName(variables[i])
- variables[i].FeatureStatus =
generateFeatureStatus(variables[i])
- }
-
- // sort by name
- sort.Slice(variables, func(i, j int) bool {
- return strings.Compare(variables[i].Name,
variables[j].Name) < 0
- })
-
- // Create the output file template.
- t, err :=
template.New("varTemplate").Funcs(template.FuncMap{
- "processGoDescription": processGoDescription,
"add": add,
- }).Parse(outputTemplate)
- if err != nil {
- log.Fatalf("failed parsing variable template:
%v", err)
- }
-
- // Generate the Go source.
- var goSource bytes.Buffer
- if err := t.Execute(&goSource, map[string]interface{}{
- "Package": getPackage(),
- "KnownTypes": knownTypes,
- "Variables": variables,
- "Collection": collection,
- }); err != nil {
- log.Fatalf("failed generating output Go source
code %s: %v", output, err)
- }
-
- if err := os.WriteFile(output, goSource.Bytes(),
0o666); err != nil {
- log.Fatalf("Failed writing to output file %s:
%v", output, err)
- }
- },
- }
-)
-
-func init() {
- rootCmd.PersistentFlags().StringVar(&input, "input", "",
- "Input YAML file to be parsed.")
- rootCmd.PersistentFlags().StringVar(&output, "output", "",
- "Output Go file to be generated.")
- rootCmd.PersistentFlags().StringVar(&collectionType, "collection_type",
annotations.NameLowercase,
- fmt.Sprintf("Output type for the generated collection. Allowed
values are '%s' or '%s'.",
- annotations.NameLowercase, labels.NameLowercase))
- flag.CommandLine.VisitAll(func(gf *flag.Flag) {
- rootCmd.PersistentFlags().AddGoFlag(gf)
- })
-}
-
-func processFlags() {
- var err error
- collection, err = collectionForType(collectionType)
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func main() {
- if err := rootCmd.Execute(); err != nil {
- os.Exit(-1)
- }
-}
-
-type Variable struct {
- // The name of the generated golang variable.
- GoName string `json:"variableName"`
-
- // The name of the collection variable.
- Name string `json:"name"`
-
- // FeatureStatus of the collection variable.
- FeatureStatus string `json:"featureStatus"`
-
- // Description of the collection variable.
- Description string `json:"description"`
-
- // Hide the existence of this collection variable when outputting usage
information.
- Hidden bool `json:"hidden"`
-
- // Mark this annotation as deprecated when generating usage information.
- Deprecated bool `json:"deprecated"`
-
- // Indicates the types of resources this collection variable can be
applied to.
- Resources []string `json:"resources"`
-}
-
-type AnnotationConfiguration struct {
- Variables []Variable `json:"annotations"`
-}
-
-type LabelConfiguration struct {
- Variables []Variable `json:"labels"`
-}
-
-func getPackage() string {
- path, _ := filepath.Abs(output)
- return filepath.Base(filepath.Dir(path))
-}
-
-func generateVariableName(v Variable) string {
- if len(v.GoName) > 0 {
- return v.GoName
- }
-
- // Split the annotation name to separate the namespace/name portions.
- parts := strings.Split(v.Name, "/")
- ns := parts[0]
- name := parts[1]
-
- // First, process the namespace portion ...
-
- // Strip .dubbo.apache.org from the namespace portion of the annotation
name.
- ns = strings.TrimSuffix(ns, ".dubbo.apache.org")
-
- // Separate the words by spaces and capitalize each word.
- ns = strings.ReplaceAll(ns, ".", " ")
- // nolint: staticcheck
- ns = strings.Title(ns)
-
- // Reverse the namespace words so that they increase in specificity
from left to right.
- nsParts := strings.Split(ns, " ")
- ns = ""
- for i := len(nsParts) - 1; i >= 0; i-- {
- ns += nsParts[i]
- }
-
- // Now, process the name portion ...
-
- // Separate the words with spaces and capitalize each word.
- name = nameSeparator.ReplaceAllString(name, " ")
- // nolint: staticcheck
- name = strings.Title(name)
-
- // Remove the spaces to generate a camel case variable name.
- name = strings.ReplaceAll(name, " ", "")
-
- // Concatenate the names together.
- return ns + name
-}
-
-func getFeatureStatus(fs string) (FeatureStatus, error) {
- // nolint: staticcheck
- asTitle := strings.Title(fs)
- switch FeatureStatus(asTitle) {
- case Alpha:
- return Alpha, nil
- case Beta:
- return Beta, nil
- case Stable:
- return Stable, nil
- }
- return "", fmt.Errorf("invalid feature status string: `%s`
(stings.Title=`%s`)", fs, asTitle)
-}
-
-func generateFeatureStatus(v Variable) string {
- if len(v.FeatureStatus) > 0 {
- fs, err := getFeatureStatus(v.FeatureStatus)
- if err != nil {
- log.Fatal(err)
- }
- return string(fs)
- }
-
- // If the name begins with the feature status, use it.
- firstPart := strings.Split(v.Name, ".")
- fs, err := getFeatureStatus(firstPart[0])
- if err == nil {
- return string(fs)
- }
-
- // Default to Alpha
- return string(Alpha)
-}
-
-func processHTMLDescription(in string) string {
- // In most cases, the description is a single line in Markdown format.
- // Convert it to HTML with a Markdown parser, this will give us a
better looking output.
- return string(mdToHTML([]byte(in)))
-}
-
-func processGoDescription(in string, indent int) string {
- if strings.Contains(in, "\n") {
- return lineWrap(in)
- }
- return wordWrap(in, indent)
-}
-
-func wordWrap(in string, indent int) string {
- // We use double quotes (") around each line, so replace any double
quotes embedded
- // in the string with back ticks (`).
- in = strings.ReplaceAll(in, "\"", "`")
-
- indentPrefix := strings.Repeat(" ", indent)
- words := strings.Split(in, " ")
-
- maxLineLength := 80
-
- out := ""
- line := ""
- for len(words) > 0 {
- // Take the next word.
- word := words[0]
- words = words[1:]
-
- if indent+len(line)+len(word) > maxLineLength {
- // Need to word wrap - emit the current line.
- out += "\"" + line + " \""
- line = ""
-
- // Wrap to the start of the next line.
- out += "+\n" + indentPrefix
- }
-
- // Add the word to the current line.
- if len(line) > 0 {
- line += " "
- }
- line += word
- }
-
- // Emit the final line
- out += "\"" + line + "\""
-
- return out
-}
-
-func lineWrap(in string) string {
- // We use back tick (`) around the entire string, so replace any back
ticks embedded
- // in the string with double quotes (").
- in = strings.ReplaceAll(in, "`", "\"")
-
- lines := strings.Split(in, "\n")
- out := "`"
- for i, line := range lines {
- out += line
- if i < len(lines)-1 {
- out += "\n"
- }
- }
- out += "`"
- return out
-}
-
-func add(x, y int) int {
- return x + y
-}
-
-func mdToHTML(md []byte) []byte {
- // create markdown parser with extensions
- extensions := parser.CommonExtensions | parser.AutoHeadingIDs |
parser.NoEmptyLineBeforeBlock
- p := parser.NewWithExtensions(extensions)
- doc := p.Parse(md)
-
- // create HTML renderer with extensions
- htmlFlags := html.CommonFlags | html.HrefTargetBlank
- opts := html.RendererOptions{Flags: htmlFlags}
- renderer := html.NewRenderer(opts)
-
- return markdown.Render(doc, renderer)
-}
diff --git a/tools/build-tools/docker/Dockerfile
b/tools/build-tools/docker/Dockerfile
deleted file mode 100644
index 94c06ca7..00000000
--- a/tools/build-tools/docker/Dockerfile
+++ /dev/null
@@ -1,148 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# hadolint global ignore=SC2086
-
-ARG GOLANG_IMAGE=golang:1.24-bookworm
-# hadolint ignore=DL3006
-FROM ${GOLANG_IMAGE} AS binary_tools_context_base
-# TARGETARCH is an automatic platform ARG enabled by Docker BuildKit.
-ARG TARGETARCH
-
-# Dubbo Kubernetes version/SHA for kubetype-gen
-ARG DUBBO_KUBERNETES_VERSION=main
-
-# Pinned versions for code generators
-ENV K8S_CODE_GENERATOR_VERSION=1.29.4
-
-ENV GO111MODULE=on
-ENV GOPROXY=https://proxy.golang.org
-
-WORKDIR /tmp
-ENV GOPATH=/tmp/go
-# Avoid any attempts to automatically download a new Go version
-ENV GOTOOLCHAIN=local
-
-ENV OUTDIR=/out
-RUN mkdir -p ${OUTDIR}/usr/bin
-RUN mkdir -p ${OUTDIR}/usr/local
-
-# Update distro and install dependencies
-# hadolint ignore=DL3042
-RUN --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
- --mount=type=cache,target=/var/cache/apt,sharing=locked \
- rm -f /etc/apt/apt.conf.d/docker-clean \
- && apt-get update \
- && apt-get -y --no-install-recommends install \
- build-essential \
- ca-certificates \
- curl \
- git \
- unzip \
- xz-utils
-
-# Cleanup stuff we don't need in the final image
-RUN rm -fr /usr/local/go/doc
-RUN rm -fr /usr/local/go/test
-RUN rm -fr /usr/local/go/api
-RUN rm -fr /usr/local/go/bin/godoc
-RUN rm -fr /usr/local/go/bin/gofmt
-
-FROM binary_tools_context_base AS go_tools_1
-
-# Build and install Kubernetes code generators
-RUN --mount=type=cache,target=/tmp/go/pkg/mod \
- --mount=type=cache,target=/root/.cache/go-build \
- CGO_ENABLED=0 go install -ldflags="-extldflags -static -s -w" \
-
k8s.io/code-generator/cmd/applyconfiguration-gen@kubernetes-${K8S_CODE_GENERATOR_VERSION}
\
-
k8s.io/code-generator/cmd/defaulter-gen@kubernetes-${K8S_CODE_GENERATOR_VERSION}
\
-
k8s.io/code-generator/cmd/client-gen@kubernetes-${K8S_CODE_GENERATOR_VERSION} \
-
k8s.io/code-generator/cmd/lister-gen@kubernetes-${K8S_CODE_GENERATOR_VERSION} \
-
k8s.io/code-generator/cmd/informer-gen@kubernetes-${K8S_CODE_GENERATOR_VERSION}
\
-
k8s.io/code-generator/cmd/deepcopy-gen@kubernetes-${K8S_CODE_GENERATOR_VERSION}
\
-
k8s.io/code-generator/cmd/go-to-protobuf@kubernetes-${K8S_CODE_GENERATOR_VERSION}
-
-FROM binary_tools_context_base AS go_tools_2
-
-# Build Dubbo Kubernetes kubetype-gen and protoc-gen-crd tool from source.
-# Copy pre-built kubetype-gen binary from project root
-COPY --chmod=755 ./tools/cmd/bin/kubetype-gen /tmp/go/bin/kubetype-gen
-COPY --chmod=755 ./tools/cmd/bin/protoc-gen-crd /tmp/go/bin/protoc-gen-crd
-
-FROM ubuntu:noble AS base_os_context
-
-ENV DEBIAN_FRONTEND=noninteractive
-ENV OUTDIR=/out
-
-# Install minimal dependencies for code generation
-# hadolint ignore=DL3008
-RUN --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
- --mount=type=cache,target=/var/cache/apt,sharing=locked \
- rm -f /etc/apt/apt.conf.d/docker-clean \
- && apt-get update && apt-get install -y --no-install-recommends \
- ca-certificates \
- git \
- make
-
-# Clean up stuff we don't need in the final image
-RUN rm -rf /var/lib/apt/lists/* \
- && rm -fr /usr/share/doc \
- && rm -fr /usr/share/man \
- && rm -fr /tmp/*
-
-FROM scratch AS build_tools
-
-# Version from build arguments
-ARG VERSION
-
-# Labels used by Docker
-LABEL "org.apache.dubbo.repo"="https://github.com/apache/dubbo-kubernetes"
-LABEL "org.apache.dubbo.version"="${VERSION}"
-
-# General
-ENV HOME=/home
-ENV LANG=C.UTF-8
-
-# Go support
-ENV GO111MODULE=on
-# Avoid any attempts to automatically download a new Go version
-ENV GOTOOLCHAIN=local
-ENV GOPROXY=https://proxy.golang.org
-ENV GOSUMDB=sum.golang.org
-ENV GOROOT=/usr/local/go
-ENV GOPATH=/go
-ENV GOCACHE=/gocache
-ENV GOBIN=/gobin
-ENV PATH=/usr/local/go/bin:/gobin:/usr/bin:$PATH
-
-# Create the file system
-COPY --link --from=base_os_context / /
-COPY --link --from=binary_tools_context_base /out/ /
-COPY --link --from=binary_tools_context_base /usr/local/go /usr/local/go
-COPY --link --from=go_tools_1 /tmp/go/bin/* /usr/bin/
-COPY --link --from=go_tools_2 /tmp/go/bin/* /usr/bin/
-
-# Create mountpoints
-RUN mkdir -p /go && \
- mkdir -p /gocache && \
- mkdir -p /gobin && \
- mkdir -p /home/.cache
-
-RUN chmod -R 777 /go && \
- chmod -R 777 /gocache && \
- chmod -R 777 /gobin && \
- chmod -R 777 /home/.cache
-
-WORKDIR /
diff --git a/tools/cmd/kubetype-gen/boilerplate.go.txt
b/tools/cmd/kubetype-gen/boilerplate.go.txt
deleted file mode 100644
index 4f8c0261..00000000
--- a/tools/cmd/kubetype-gen/boilerplate.go.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
diff --git a/tools/cmd/kubetype-gen/generators/naming.go
b/tools/cmd/kubetype-gen/generators/naming.go
deleted file mode 100644
index e6c7e9ca..00000000
--- a/tools/cmd/kubetype-gen/generators/naming.go
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package generators
-
-import (
- "strings"
-
- "k8s.io/gengo/namer"
-)
-
-// NameSystems used by the kubetype generator
-func NameSystems(generatedPackage string, tracker namer.ImportTracker)
namer.NameSystems {
- return namer.NameSystems{
- "public": namer.NewPublicNamer(0),
- "raw": namer.NewRawNamer(generatedPackage, tracker),
- "publicPlural": namer.NewPublicPluralNamer(map[string]string{}),
- "lower": newLowerCaseNamer(0),
- }
-}
-
-// DefaultNameSystem to use if none is specified
-func DefaultNameSystem() string {
- return "public"
-}
-
-func newLowerCaseNamer(prependPackageNames int, ignoreWords ...string)
*namer.NameStrategy {
- n := &namer.NameStrategy{
- Join: namer.Joiner(namer.IL, strings.ToLower),
- IgnoreWords: map[string]bool{},
- PrependPackageNames: prependPackageNames,
- }
- for _, w := range ignoreWords {
- n.IgnoreWords[w] = true
- }
- return n
-}
diff --git a/tools/cmd/kubetype-gen/generators/package.go
b/tools/cmd/kubetype-gen/generators/package.go
deleted file mode 100644
index d1b17537..00000000
--- a/tools/cmd/kubetype-gen/generators/package.go
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package generators
-
-import (
- "fmt"
-
- "k8s.io/gengo/generator"
- "k8s.io/gengo/types"
-
- "github.com/apache/dubbo-kubernetes/tools/cmd/kubetype-gen/metadata"
-)
-
-// NewPackageGenerator generates source for a scanned package, specifically
k8s styled doc.go, types.go and register.go files
-func NewPackageGenerator(source metadata.PackageMetadata, boilerplate []byte)
generator.Package {
- return &generator.DefaultPackage{
- PackageName: source.TargetPackage().Name,
- PackagePath: source.TargetPackage().Path,
- HeaderText: boilerplate,
- PackageDocumentation: []byte(fmt.Sprintf(`
-// Package has auto-generated kube type wrappers for raw types.
-// +k8s:openapi-gen=true
-// +k8s:deepcopy-gen=package
-// +groupName=%s
-`, source.GroupVersion().Group)),
- FilterFunc: func(c *generator.Context, t *types.Type) bool {
- for _, it := range source.RawTypes() {
- if t == it {
- return true
- }
- }
- return false
- },
- GeneratorList: []generator.Generator{
- // generate types.go
- NewTypesGenerator(source),
- // generate register.go
- NewRegisterGenerator(source),
- generator.DefaultGen{
- OptionalName: "doc",
- },
- },
- }
-}
diff --git a/tools/cmd/kubetype-gen/generators/register.go
b/tools/cmd/kubetype-gen/generators/register.go
deleted file mode 100644
index 1b673247..00000000
--- a/tools/cmd/kubetype-gen/generators/register.go
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package generators
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
-
- "k8s.io/gengo/generator"
- "k8s.io/gengo/namer"
- "k8s.io/gengo/types"
-
- "github.com/apache/dubbo-kubernetes/tools/cmd/kubetype-gen/metadata"
-)
-
-type registerGenerator struct {
- generator.DefaultGen
- source metadata.PackageMetadata
- imports namer.ImportTracker
-}
-
-// NewRegisterGenerator creates a new generator for creating k8s style
register.go files
-func NewRegisterGenerator(source metadata.PackageMetadata) generator.Generator
{
- return ®isterGenerator{
- DefaultGen: generator.DefaultGen{
- OptionalName: "register",
- },
- source: source,
- imports: generator.NewImportTracker(),
- }
-}
-
-func (g *registerGenerator) Namers(c *generator.Context) namer.NameSystems {
- return NameSystems(g.source.TargetPackage().Path, g.imports)
-}
-
-func (g *registerGenerator) PackageConsts(c *generator.Context) []string {
- return []string{
- fmt.Sprintf("GroupName = \"%s\"",
g.source.GroupVersion().Group),
- }
-}
-
-func (g *registerGenerator) PackageVars(c *generator.Context) []string {
- schemeBuilder := bytes.Buffer{}
- w := bufio.NewWriter(&schemeBuilder)
- sw := generator.NewSnippetWriter(w, c, "$", "$")
- m := map[string]interface{}{
- "NewSchemeBuilder": c.Universe.Function(types.Name{Name:
"NewSchemeBuilder", Package: "k8s.io/apimachinery/pkg/runtime"}),
- }
- sw.Do("SchemeBuilder = $.NewSchemeBuilder|raw$(addKnownTypes)", m)
- w.Flush()
- return []string{
- fmt.Sprintf("SchemeGroupVersion = schema.GroupVersion{Group:
GroupName, Version: \"%s\"}", g.source.GroupVersion().Version),
- schemeBuilder.String(),
- "localSchemeBuilder = &SchemeBuilder",
- "AddToScheme = localSchemeBuilder.AddToScheme",
- }
-}
-
-func (g *registerGenerator) Imports(c *generator.Context) []string {
- return g.imports.ImportLines()
-}
-
-func (g registerGenerator) Finalize(c *generator.Context, w io.Writer) error {
- sw := generator.NewSnippetWriter(w, c, "$", "$")
- var lowerCaseSchemeKubeTypes, camelCaseSchemeKubeTypes
[]metadata.KubeType
- for _, k := range g.source.AllKubeTypes() {
- if isLowerCaseScheme(k.Tags()) {
- lowerCaseSchemeKubeTypes =
append(lowerCaseSchemeKubeTypes, k)
- } else {
- camelCaseSchemeKubeTypes =
append(camelCaseSchemeKubeTypes, k)
- }
- }
- m := map[string]interface{}{
- "GroupResource": c.Universe.Type(types.Name{Name:
"GroupResource", Package: "k8s.io/apimachinery/pkg/runtime/schema"}),
- "Scheme": c.Universe.Type(types.Name{Name:
"Scheme", Package: "k8s.io/apimachinery/pkg/runtime"}),
- "AddToGroupVersion":
c.Universe.Function(types.Name{Name: "AddToGroupVersion", Package:
"k8s.io/apimachinery/pkg/apis/meta/v1"}),
- "CamelCaseSchemeKubeTypes": camelCaseSchemeKubeTypes,
- "LowerCaseSchemeKubeTypes": lowerCaseSchemeKubeTypes,
- }
- sw.Do(resourceFuncTemplate, m)
- sw.Do(addKnownTypesFuncTemplate, m)
-
- return sw.Error()
-}
-
-// isLowerCaseScheme checks if the kubetype is reflected as lower case in
Kubernetes scheme.
-// This is a workaround as Dubbo CRDs should have CamelCase scheme in
Kubernetes, e.g. `VirtualService` instead of `virtualservice`
-func isLowerCaseScheme(tags []string) bool {
- for _, s := range tags {
- if s == "kubetype-gen:lowerCaseScheme" {
- return true
- }
- }
- return false
-}
-
-const resourceFuncTemplate = `
-func Resource(resource string) $.GroupResource|raw$ {
- return SchemeGroupVersion.WithResource(resource).GroupResource()
-}
-`
-
-const addKnownTypesFuncTemplate = `
-func addKnownTypes(scheme *$.Scheme|raw$) error {
- scheme.AddKnownTypes(SchemeGroupVersion,
- $- range .CamelCaseSchemeKubeTypes $
- &$ .Type|raw ${},
- &$ .Type|raw $List{},
- $- end $
- )
- $- range .LowerCaseSchemeKubeTypes $
- scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("$ .Type|lower
$"), &$ .Type|raw ${})
- scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("$ .Type|lower
$List"), &$ .Type|raw $List{})
- $- end $
- $.AddToGroupVersion|raw$(scheme, SchemeGroupVersion)
- return nil
-}
-`
diff --git a/tools/cmd/kubetype-gen/generators/types.go
b/tools/cmd/kubetype-gen/generators/types.go
deleted file mode 100644
index 0c714fed..00000000
--- a/tools/cmd/kubetype-gen/generators/types.go
+++ /dev/null
@@ -1,141 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package generators
-
-import (
- "io"
- "slices"
- "strings"
-
- "k8s.io/gengo/generator"
- "k8s.io/gengo/namer"
- "k8s.io/gengo/types"
-
- "github.com/apache/dubbo-kubernetes/tools/cmd/kubetype-gen/metadata"
-)
-
-type typesGenerator struct {
- generator.DefaultGen
- source metadata.PackageMetadata
- imports namer.ImportTracker
-}
-
-// NewTypesGenerator creates a new generator for creating k8s style types.go
files
-func NewTypesGenerator(source metadata.PackageMetadata) generator.Generator {
- return &typesGenerator{
- DefaultGen: generator.DefaultGen{
- OptionalName: "types",
- },
- source: source,
- imports: generator.NewImportTracker(),
- }
-}
-
-func (g *typesGenerator) Namers(c *generator.Context) namer.NameSystems {
- return NameSystems(g.source.TargetPackage().Path, g.imports)
-}
-
-func (g *typesGenerator) Imports(c *generator.Context) []string {
- return g.imports.ImportLines()
-}
-
-// extracts values for Name and Package from "dubbostatus-override" in the
comments
-func statusOverrideFromComments(commentLines []string) (string, string, bool) {
- // ServiceEntry has a unique status type which includes addresses for
auto allocated IPs, substitute DubboServiceEntryStatus
- // for DubboStatus when type is ServiceEntry
- if index := slices.IndexFunc(commentLines, func(comment string) bool {
- return strings.Contains(comment, dubboStatusOveride)
- }); index != -1 {
- statusOverrideLine := commentLines[index]
- statusOverridSplit := strings.Split(statusOverrideLine, ":")
- if len(statusOverridSplit) == 2 {
- overrideName := statusOverridSplit[1]
- return strings.TrimSpace(overrideName),
"github.com/kdubbo/api/meta/v1alpha1", true
- } else if len(statusOverridSplit) == 3 {
- overrideName := statusOverridSplit[1]
- overridePackage := statusOverridSplit[2]
- return strings.TrimSpace(overrideName),
strings.TrimSpace(overridePackage), true
- }
- }
- return "", "", false
-}
-
-func (g *typesGenerator) GenerateType(c *generator.Context, t *types.Type, w
io.Writer) error {
- kubeTypes := g.source.KubeTypes(t)
- sw := generator.NewSnippetWriter(w, c, "$", "$")
- m := map[string]interface{}{
- "KubeType": nil,
- "RawType": t,
- "TypeMeta": c.Universe.Type(types.Name{Name: "TypeMeta",
Package: "k8s.io/apimachinery/pkg/apis/meta/v1"}),
- "ObjectMeta": c.Universe.Type(types.Name{Name: "ObjectMeta",
Package: "k8s.io/apimachinery/pkg/apis/meta/v1"}),
- "ListMeta": c.Universe.Type(types.Name{Name: "ListMeta",
Package: "k8s.io/apimachinery/pkg/apis/meta/v1"}),
- "DubboStatus": c.Universe.Type(types.Name{Name: "DubboStatus",
Package: "github.com/kdubbo/api/meta/v1alpha1"}),
- }
- for _, kubeType := range kubeTypes {
- localM := m
- // name, package, found :=
typeFromComments(kubeType.RawType().CommentLines)
- if name, packageName, found :=
statusOverrideFromComments(kubeType.RawType().CommentLines); found {
- localM["DubboStatus"] =
c.Universe.Type(types.Name{Name: name, Package: packageName})
- }
-
- // make sure local types get imports generated for them to
prevent reusing their local name for real imports,
- // e.g. generating into package v1alpha1, while also importing
from another package ending with v1alpha1.
- // adding the import here will ensure the imports will be
something like, precedingpathv1alpha1.
- g.imports.AddType(kubeType.Type())
- localM["KubeType"] = kubeType
- sw.Do(kubeTypeTemplate, localM)
- }
- return sw.Error()
-}
-
-const (
- dubboStatusOveride = `dubbostatus-override:`
- kubeTypeTemplate = `
-$- range .RawType.SecondClosestCommentLines $
-// $ . $
-$- end $
-$- range .KubeType.Tags $
-// +$ . $
-$- end $
-// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
-
-$ range .RawType.CommentLines $
-// $ . $
-$- end $
-type $.KubeType.Type|public$ struct {
- $.TypeMeta|raw$ ` + "`" + `json:",inline"` + "`" + `
- // +optional
- $.ObjectMeta|raw$ ` + "`" + `json:"metadata,omitempty"
protobuf:"bytes,1,opt,name=metadata"` + "`" + `
-
- // Spec defines the implementation of this definition.
- // +optional
- Spec $.RawType|raw$ ` + "`" + `json:"spec,omitempty"
protobuf:"bytes,2,opt,name=spec"` + "`" + `
-
- Status $.DubboStatus|raw$ ` + "`" + `json:"status,omitempty"` + "`" + `
-}
-
-// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
-
-// $.KubeType.Type|public$List is a collection of
$.KubeType.Type|publicPlural$.
-type $.KubeType.Type|public$List struct {
- $.TypeMeta|raw$ ` + "`" + `json:",inline"` + "`" + `
- // +optional
- $.ListMeta|raw$ ` + "`" + `json:"metadata,omitempty"
protobuf:"bytes,1,opt,name=metadata"` + "`" + `
- Items []*$.KubeType.Type|raw$ ` + "`" + `json:"items"
protobuf:"bytes,2,rep,name=items"` + "`" + `
-}
-`
-)
diff --git a/tools/cmd/kubetype-gen/main.go b/tools/cmd/kubetype-gen/main.go
deleted file mode 100644
index 4b42d19f..00000000
--- a/tools/cmd/kubetype-gen/main.go
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "os"
-
- "github.com/golang/glog"
- "k8s.io/gengo/args"
-
- "github.com/apache/dubbo-kubernetes/tools/cmd/kubetype-gen/generators"
- "github.com/apache/dubbo-kubernetes/tools/cmd/kubetype-gen/scanner"
-)
-
-func main() {
- arguments := args.Default()
-
- arguments.GeneratedByCommentTemplate = "// Code generated by
kubetype-gen. DO NOT EDIT."
-
- // Don't default the file header
- // arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(),
"github.com/apache/dubbo-kubernetes/tools/cmd/kubetype-gen/boilerplate.go.txt")
-
- scanner := scanner.Scanner{}
-
- if err := arguments.Execute(
- generators.NameSystems("", nil),
- generators.DefaultNameSystem(),
- scanner.Scan,
- ); err != nil {
- glog.Errorf("Error: %v", err)
- os.Exit(1)
- }
- glog.V(2).Info("Completed successfully.")
-}
diff --git a/tools/cmd/kubetype-gen/metadata/metadata.go
b/tools/cmd/kubetype-gen/metadata/metadata.go
deleted file mode 100644
index 56e5607d..00000000
--- a/tools/cmd/kubetype-gen/metadata/metadata.go
+++ /dev/null
@@ -1,224 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package metadata
-
-import (
- "fmt"
- "path/filepath"
- "sort"
- "strings"
-
- "github.com/golang/glog"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/gengo/types"
-)
-
-// KubeType is the interface representing a type to be generated.
-type KubeType interface {
- RawType() *types.Type
- Type() *types.Type
- Tags() []string
-}
-
-// PackageMetadata is the interface used to provide source data used by the
package generators.
-type PackageMetadata interface {
- // GroupVersion is the k8s Group/Version to use for the generated types.
- GroupVersion() *schema.GroupVersion
-
- // TargetPackage is the package into which the k8s types will be
generated.
- TargetPackage() *types.Package
-
- // RawTypes is the list of types for which k8s types should be
generated.
- RawTypes() []*types.Type
-
- // KubeTypes is the list of k8s types to be generated for the given
rawType.
- KubeTypes(rawType *types.Type) []KubeType
-
- // AllKubeTypes is the list of all k8s types to be generated
- AllKubeTypes() []KubeType
-
- // AddMetadata is used to add metadata collected by the scanner.
- AddMetadataForType(rawType *types.Type, kubeTypes ...KubeType) error
-
- // Validate is used to validate the metadata prior to generation
- Validate() []error
-}
-
-// Store is used to store/access the source metadata collected by the scanner
-type Store interface {
- // MetadataForGV returns the package metadata associated with the
Group/Version
- MetadataForGV(gv *schema.GroupVersion) PackageMetadata
-
- // AllMetadata returns the source metadata.
- AllMetadata() []PackageMetadata
-
- // Validate is used to validate the metadata prior to generation
- Validate() []error
-}
-
-type kubeTypeMetadata struct {
- rawType *types.Type
- kubeType *types.Type
- tags []string
-}
-
-type packageMetadata struct {
- groupVersion *schema.GroupVersion
- targetPackage *types.Package
- rawTypes []*types.Type
- allKubeTypes []KubeType
- kubeTypesForRawType map[*types.Type][]KubeType
-}
-
-type metadataStore struct {
- baseOutputPackage *types.Package
- universe *types.Universe
- metadataForGV map[string]PackageMetadata
- metadata []PackageMetadata
-}
-
-// NewMetadataStore returns a new store used for collecting source metadata
used by the generator.
-func NewMetadataStore(baseOutputPackage *types.Package, universe
*types.Universe) Store {
- return &metadataStore{
- baseOutputPackage: baseOutputPackage,
- universe: universe,
- metadataForGV: map[string]PackageMetadata{},
- metadata: []PackageMetadata{},
- }
-}
-
-func (s *metadataStore) MetadataForGV(gv *schema.GroupVersion) PackageMetadata
{
- simpleGV := schema.GroupVersion{Group: strings.SplitN(gv.Group, ".",
2)[0], Version: gv.Version}
- existing := s.metadataForGV[simpleGV.String()]
- if existing == nil {
- glog.V(5).Infof("Creating new PackageMetadata for
Group/Version %s", gv)
- existing = &packageMetadata{
- groupVersion: gv,
- targetPackage: s.createTargetPackage(gv),
- rawTypes: []*types.Type{},
- allKubeTypes: []KubeType{},
- kubeTypesForRawType: map[*types.Type][]KubeType{},
- }
- s.metadataForGV[simpleGV.String()] = existing
- s.metadata = append(s.metadata, existing)
- } else if gv.Group != existing.GroupVersion().Group {
- glog.Errorf("Overlapping packages for Group/Versions %s and
%s", gv, existing.GroupVersion())
- return nil
- }
- return existing
-}
-
-func (s *metadataStore) AllMetadata() []PackageMetadata {
- return s.metadata
-}
-
-func (s *metadataStore) Validate() []error {
- errorSlice := []error{}
- for _, pm := range s.metadata {
- errorSlice = append(errorSlice, pm.Validate()...)
- }
- return errorSlice
-}
-
-func (s *metadataStore) createTargetPackage(gv *schema.GroupVersion)
*types.Package {
- groupPath := strings.SplitN(gv.Group, ".", 2)
- targetPackage :=
s.universe.Package(filepath.Join(s.baseOutputPackage.Path, groupPath[0],
gv.Version))
- targetPackage.Name = gv.Version
- return targetPackage
-}
-
-func (m *packageMetadata) GroupVersion() *schema.GroupVersion {
- return m.groupVersion
-}
-
-func (m *packageMetadata) TargetPackage() *types.Package {
- return m.targetPackage
-}
-
-func (m *packageMetadata) RawTypes() []*types.Type {
- return m.rawTypes
-}
-
-func (m *packageMetadata) KubeTypes(rawType *types.Type) []KubeType {
- return m.kubeTypesForRawType[rawType]
-}
-
-func (m *packageMetadata) AllKubeTypes() []KubeType {
- return m.allKubeTypes
-}
-
-func (m *packageMetadata) AddMetadataForType(rawType *types.Type, kubeTypes
...KubeType) error {
- if _, exists := m.kubeTypesForRawType[rawType]; exists {
- // we should never get here. this means we've scanned a type
twice
- return fmt.Errorf("type %s already added to scanned metadata",
rawType)
- }
-
- m.rawTypes = append(m.rawTypes, rawType)
- m.kubeTypesForRawType[rawType] = kubeTypes
- m.allKubeTypes = append(m.allKubeTypes, kubeTypes...)
-
- return nil
-}
-
-func (m *packageMetadata) Validate() []error {
- duplicates := map[*types.Type][]*types.Type{}
-
- // check for duplicates
- sort.Slice(m.allKubeTypes, func(i, j int) bool {
- comp := strings.Compare(m.allKubeTypes[i].Type().Name.Name,
m.allKubeTypes[j].Type().Name.Name)
- if comp == 0 {
- if sources, exists :=
duplicates[m.allKubeTypes[i].Type()]; exists {
- duplicates[m.allKubeTypes[i].Type()] =
append(sources, m.allKubeTypes[i].RawType())
- } else {
- duplicates[m.allKubeTypes[i].Type()] =
[]*types.Type{m.allKubeTypes[j].RawType(), m.allKubeTypes[i].RawType()}
- }
- return false
- }
- return comp < 0
- })
- if len(duplicates) > 0 {
- errorSlice := make([]error, 0, len(duplicates))
- for kubeType, rawTypes := range duplicates {
- errorSlice = append(errorSlice, fmt.Errorf("duplicate
kube types specified for %s. duplicated by: %v", kubeType, rawTypes))
- }
- return errorSlice
- }
- return []error{}
-}
-
-// NewKubeType returns a new KubeType object representing the source type, the
target type and its comment tags
-func NewKubeType(rawType *types.Type, kubeType *types.Type, tags []string)
KubeType {
- return &kubeTypeMetadata{
- rawType: rawType,
- kubeType: kubeType,
- tags: tags,
- }
-}
-
-func (k *kubeTypeMetadata) RawType() *types.Type {
- return k.rawType
-}
-
-func (k *kubeTypeMetadata) Type() *types.Type {
- return k.kubeType
-}
-
-func (k *kubeTypeMetadata) Tags() []string {
- return k.tags
-}
-
-func (k *kubeTypeMetadata) String() string {
- return fmt.Sprintf("%s => %s%s", k.rawType, k.kubeType, k.tags)
-}
diff --git a/tools/cmd/kubetype-gen/scanner/scanner.go
b/tools/cmd/kubetype-gen/scanner/scanner.go
deleted file mode 100644
index 9252b0f7..00000000
--- a/tools/cmd/kubetype-gen/scanner/scanner.go
+++ /dev/null
@@ -1,243 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package scanner
-
-import (
- "fmt"
- "strings"
-
- "github.com/golang/glog"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/gengo/args"
- "k8s.io/gengo/generator"
- "k8s.io/gengo/types"
-
- "github.com/apache/dubbo-kubernetes/tools/cmd/kubetype-gen/generators"
- "github.com/apache/dubbo-kubernetes/tools/cmd/kubetype-gen/metadata"
-)
-
-const (
- // enabledTagName is the root tag used to identify types that need a
corresponding kube type generated
- enabledTagName = "kubetype-gen"
-
- // groupVersionTagName is the tag used to identify the k8s
group/version associated with the generated types.
- groupVersionTagName = enabledTagName + ":groupVersion"
-
- // kubeTypeTagName is used to identify the name(s) of the types to be
generated from the type with this tag.
- // If this tag is not present, the k8s type will have the same name as
the source type. If this tag is specified
- // multiple times, a k8s type will be generated for each value.
- kubeTypeTagName = enabledTagName + ":kubeType"
-
- // kubeTagsTagTemplate is used to identify a comment tag that should be
added to the generated kubeType. This
- // allows different sets of tags to be used when a single type is the
source for multiple kube types (e.g. where one
- // is namespaced and another is not). The tag should not be prefixed
with '+', as this will be added by the
- // generator. This may be specified multiple times, once for each tag
to be added to the generated type.
- kubeTagsTagTemplate = enabledTagName + ":%s:tag"
-)
-
-// Scanner is used to scan input packages for types with kubetype-gen tags
-type Scanner struct {
- arguments *args.GeneratorArgs
- context *generator.Context
-}
-
-// Scan the input packages for types with kubetype-gen tags
-func (s *Scanner) Scan(c *generator.Context, arguments *args.GeneratorArgs)
generator.Packages {
- s.arguments = arguments
- s.context = c
-
- boilerplate, err := arguments.LoadGoBoilerplate()
- if err != nil {
- glog.Fatalf("Failed loading boilerplate: %v", err)
- }
-
- // scan input packages for kubetype-gen
- metadataStore := metadata.NewMetadataStore(s.getBaseOutputPackage(),
&c.Universe)
- fail := false
-
- glog.V(5).Info("Scanning input packages")
- for _, input := range c.Inputs {
- glog.V(5).Infof("Scanning package %s", input)
- pkg := c.Universe[input]
- if pkg == nil {
- glog.Warningf("Package not found: %s", input)
- continue
- }
- if strings.HasPrefix(arguments.OutputPackagePath, pkg.Path) {
- glog.Warningf("Ignoring package %s as it is located in
the output package %s", pkg.Path, arguments.OutputPackagePath)
- continue
- }
-
- pkgTags := types.ExtractCommentTags("+", pkg.DocComments)
-
- // group/version for generated types from this package
- defaultGV, err := s.getGroupVersion(pkgTags, nil)
- if err != nil {
- glog.Errorf("Could not calculate Group/Version for
package %s: %v", pkg.Path, err)
- fail = true
- } else if defaultGV != nil {
- if len(defaultGV.Group) == 0 {
- glog.Errorf("Invalid Group/Version for package
%s, Group not specified for Group/Version: %v", pkg.Path, defaultGV)
- fail = true
- } else {
- glog.V(5).Infof("Default Group/Version for
package: %s", defaultGV)
- }
- }
-
- // scan package for types that need kube types generated
- for _, t := range pkg.Types {
- comments := make([]string, 0,
len(t.CommentLines)+len(t.SecondClosestCommentLines))
- comments = append(comments, t.CommentLines...)
- comments = append(comments,
t.SecondClosestCommentLines...)
- typeTags := types.ExtractCommentTags("+", comments)
- if _, exists := typeTags[enabledTagName]; exists {
- var gv *schema.GroupVersion
- gv, err = s.getGroupVersion(typeTags, defaultGV)
- if err != nil {
- glog.Errorf("Could not calculate
Group/Version for type %s: %v", t, err)
- fail = true
- continue
- } else if gv == nil || len(gv.Group) == 0 {
- glog.Errorf("Invalid Group/Version for
type %s: %s", t, gv)
- fail = true
- continue
- }
- versions := extractVersions(comments)
- // The kubegen doesn't natively handle type
aliases we use, so hack it in
- for _, v := range versions {
- gv := *gv
- gv.Version = v
- packageMetadata :=
metadataStore.MetadataForGV(&gv)
- if packageMetadata == nil {
- glog.Errorf("Could not create
metadata for type: %s", t)
- fail = true
- continue
- }
-
- kubeTypes :=
s.createKubeTypesForType(t, packageMetadata.TargetPackage())
- glog.V(5).Infof("Kube types %v will be
generated with Group/Version %s, for raw type in %s", kubeTypes, gv, t)
- err =
packageMetadata.AddMetadataForType(t, kubeTypes...)
- if err != nil {
- glog.Errorf("Error adding
metadata source for %s: %v", t, err)
- fail = true
- }
- }
- }
- }
- }
-
- glog.V(5).Info("Finished scanning input packages")
-
- validationErrors := metadataStore.Validate()
- if len(validationErrors) > 0 {
- for _, validationErr := range validationErrors {
- glog.Error(validationErr)
- }
- fail = true
- }
- if fail {
- glog.Exit("Errors occurred while scanning input. See previous
output for details.")
- }
-
- generatorPackages := []generator.Package{}
- for _, source := range metadataStore.AllMetadata() {
- if len(source.RawTypes()) == 0 {
- glog.Warningf("Skipping generation of %s, no types to
generate", source.GroupVersion())
- continue
- }
- glog.V(2).Infof("Adding package generator for %s.",
source.GroupVersion())
- generatorPackages = append(generatorPackages,
generators.NewPackageGenerator(source, boilerplate))
- }
- return generatorPackages
-}
-
-func extractVersions(comments []string) []string {
- var versions []string
- for _, line := range comments {
- // Looking for something like
'+cue-gen:Simple:versions:v1,v1alpha'
- if strings.HasPrefix(line, "+cue-gen:") {
- items := strings.Split(line, ":")
- if len(items) != 4 {
- continue
- }
- if items[2] == "versions" {
- versions = append(versions,
strings.Split(items[3], ",")...)
- }
- }
- }
- return versions
-}
-
-func (s *Scanner) getGroupVersion(tags map[string][]string, defaultGV
*schema.GroupVersion) (*schema.GroupVersion, error) {
- if value, exists := tags[groupVersionTagName]; exists && len(value) > 0
{
- gv, err := schema.ParseGroupVersion(value[0])
- if err == nil {
- return &gv, nil
- }
- return nil, fmt.Errorf("invalid group version '%s' specified:
%v", value[0], err)
- }
- return defaultGV, nil
-}
-
-func (s *Scanner) getBaseOutputPackage() *types.Package {
- return s.context.Universe.Package(s.arguments.OutputPackagePath)
-}
-
-func (s *Scanner) createKubeTypesForType(t *types.Type, outputPackage
*types.Package) []metadata.KubeType {
- namesForType := s.kubeTypeNamesForType(t)
- newKubeTypes := make([]metadata.KubeType, 0, len(namesForType))
- for _, name := range namesForType {
- tags := s.getTagsForKubeType(t, name)
- newKubeTypes = append(newKubeTypes, metadata.NewKubeType(t,
s.context.Universe.Type(types.Name{Name: name, Package: outputPackage.Path}),
tags))
- }
- return newKubeTypes
-}
-
-func (s *Scanner) kubeTypeNamesForType(t *types.Type) []string {
- names := []string{}
- comments := make([]string, 0,
len(t.CommentLines)+len(t.SecondClosestCommentLines))
- comments = append(comments, t.CommentLines...)
- comments = append(comments, t.SecondClosestCommentLines...)
- tags := types.ExtractCommentTags("+", comments)
- if value, exists := tags[kubeTypeTagName]; exists {
- if len(value) == 0 || len(value[0]) == 0 {
- glog.Errorf("Invalid value specified for +%s in type
%s. Using default name %s.", kubeTypeTagName, t, t.Name.Name)
- names = append(names, t.Name.Name)
- } else {
- for _, name := range value {
- if len(name) > 0 {
- names = append(names, name)
- }
- }
- }
- } else {
- names = append(names, t.Name.Name)
- }
- return names
-}
-
-func (s *Scanner) getTagsForKubeType(t *types.Type, name string) []string {
- tagName := fmt.Sprintf(kubeTagsTagTemplate, name)
- comments := make([]string, 0,
len(t.CommentLines)+len(t.SecondClosestCommentLines))
- comments = append(comments, t.CommentLines...)
- comments = append(comments, t.SecondClosestCommentLines...)
- tags := types.ExtractCommentTags("+", comments)
- if value, exists := tags[tagName]; exists {
- return value
- }
- return []string{}
-}
diff --git a/tools/cmd/protoc-gen-crd/main.go b/tools/cmd/protoc-gen-crd/main.go
deleted file mode 100644
index 619151f5..00000000
--- a/tools/cmd/protoc-gen-crd/main.go
+++ /dev/null
@@ -1,101 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "fmt"
- "strings"
-
- plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
-
-
"github.com/apache/dubbo-kubernetes/tools/cmd/protoc-gen-crd/pkg/protocgen"
-
"github.com/apache/dubbo-kubernetes/tools/cmd/protoc-gen-crd/pkg/protomodel"
-)
-
-// Breaks the comma-separated list of key=value pairs
-// in the parameter string into an easy to use map.
-func extractParams(parameter string) map[string]string {
- m := make(map[string]string)
- for _, p := range strings.Split(parameter, ",") {
- if p == "" {
- continue
- }
-
- if i := strings.Index(p, "="); i < 0 {
- m[p] = ""
- } else {
- m[p[0:i]] = p[i+1:]
- }
- }
-
- return m
-}
-
-func generate(request *plugin.CodeGeneratorRequest)
(*plugin.CodeGeneratorResponse, error) {
- includeDescription := true
- enumAsIntOrString := false
-
- p := extractParams(request.GetParameter())
- for k, v := range p {
- if k == "include_description" {
- switch strings.ToLower(v) {
- case "true":
- includeDescription = true
- case "false":
- includeDescription = false
- default:
- return nil, fmt.Errorf("unknown value '%s' for
include_description", v)
- }
- } else if k == "enum_as_int_or_string" {
- switch strings.ToLower(v) {
- case "true":
- enumAsIntOrString = true
- case "false":
- enumAsIntOrString = false
- default:
- return nil, fmt.Errorf("unknown value '%s' for
enum_as_int_or_string", v)
- }
- } else {
- return nil, fmt.Errorf("unknown argument '%s'
specified", k)
- }
- }
-
- m := protomodel.NewModel(request, true)
-
- filesToGen := make(map[*protomodel.FileDescriptor]bool)
- for _, fileName := range request.FileToGenerate {
- fd := m.AllFilesByName[fileName]
- if fd == nil {
- return nil, fmt.Errorf("unable to find %s",
request.FileToGenerate)
- }
- filesToGen[fd] = true
- }
-
- descriptionConfiguration := &DescriptionConfiguration{
- IncludeDescriptionInSchema: includeDescription,
- }
-
- g := newOpenAPIGenerator(
- m,
- descriptionConfiguration,
- enumAsIntOrString)
- return g.generateOutput(filesToGen)
-}
-
-func main() {
- protocgen.Generate(generate)
-}
diff --git a/tools/cmd/protoc-gen-crd/openapiGenerator.go
b/tools/cmd/protoc-gen-crd/openapiGenerator.go
deleted file mode 100644
index 01e1fe42..00000000
--- a/tools/cmd/protoc-gen-crd/openapiGenerator.go
+++ /dev/null
@@ -1,1025 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "log"
- "math"
- "slices"
- "strings"
-
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
- plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
- "github.com/howardjohn/celpp"
- "github.com/howardjohn/celpp/macros"
- "golang.org/x/exp/maps"
- "google.golang.org/genproto/googleapis/api/annotations"
- "google.golang.org/protobuf/proto"
- apiextinternal "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
- apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
- structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/sets"
- "sigs.k8s.io/controller-tools/pkg/crd"
- crdmarkers "sigs.k8s.io/controller-tools/pkg/crd/markers"
- "sigs.k8s.io/controller-tools/pkg/markers"
- "sigs.k8s.io/yaml"
-
-
"github.com/apache/dubbo-kubernetes/tools/cmd/protoc-gen-crd/pkg/protomodel"
-)
-
-// Some special types with predefined schemas.
-// Normally these would result in stack-overflow errors when generating the
open api schema
-// The imperfect solution, is to just generate an empty object for these types
-var specialTypes = map[string]*apiext.JSONSchemaProps{
- "google.protobuf.ListValue": {
- Items: &apiext.JSONSchemaPropsOrArray{Schema:
&apiext.JSONSchemaProps{Type: "object"}},
- },
- "google.protobuf.Struct": {
- Type: "object",
- XPreserveUnknownFields: Ptr(true),
- },
- "google.protobuf.Any": {
- Type: "object",
- XPreserveUnknownFields: Ptr(true),
- },
- "google.protobuf.Value": {
- XPreserveUnknownFields: Ptr(true),
- },
- "google.protobuf.BoolValue": {
- Type: "boolean",
- Nullable: true,
- },
- "google.protobuf.StringValue": {
- Type: "string",
- Nullable: true,
- },
- "google.protobuf.DoubleValue": {
- Type: "number",
- Format: "double",
- Nullable: true,
- },
- "google.protobuf.Int32Value": {
- Type: "integer",
- Format: "int32",
- Nullable: true,
- },
- "google.protobuf.Int64Value": {
- Type: "integer",
- Format: "int64",
- Nullable: true,
- },
- "google.protobuf.UInt32Value": {
- Type: "integer",
- Minimum: Ptr(float64(0)),
- Maximum: Ptr(float64(math.MaxUint32)),
- Nullable: true,
- },
- "google.protobuf.UInt64Value": {
- Type: "integer",
- Minimum: Ptr(float64(0)),
- // TODO: this overflows Kubernetes
- // schema.Maximum = Ptr(float64(uint64(math.MaxUint64)))
- Nullable: true,
- },
- "google.protobuf.FloatValue": {
- Type: "number",
- Format: "double",
- Nullable: true,
- },
- "google.protobuf.Duration": {
- Type: "string",
- XValidations: []apiext.ValidationRule{
- {
- Rule: "duration(self) >= duration('1ms')",
- Message: "must be a valid duration greater than
1ms",
- },
- },
- },
- "google.protobuf.Empty": {
- Type: "object",
- MaxProperties: Ptr(int64(0)),
- },
- "google.protobuf.Timestamp": {
- Type: "string",
- Format: "date-time",
- },
-}
-
-type openapiGenerator struct {
- model *protomodel.Model
-
- // transient state as individual files are processed
- currentPackage *protomodel.PackageDescriptor
-
- messages map[string]*protomodel.MessageDescriptor
-
- descriptionConfiguration *DescriptionConfiguration
- enumAsIntOrString bool
- customSchemasByMessageName map[string]*apiext.JSONSchemaProps
-}
-
-type DescriptionConfiguration struct {
- // Whether or not to include a description in the generated open api
schema
- IncludeDescriptionInSchema bool
-}
-
-func newOpenAPIGenerator(
- model *protomodel.Model,
- descriptionConfiguration *DescriptionConfiguration,
- enumAsIntOrString bool,
-) *openapiGenerator {
- return &openapiGenerator{
- model: model,
- descriptionConfiguration: descriptionConfiguration,
- enumAsIntOrString: enumAsIntOrString,
- customSchemasByMessageName: buildCustomSchemasByMessageName(),
- }
-}
-
-// buildCustomSchemasByMessageName name returns a mapping of message name to a
pre-defined openapi schema
-// It includes:
-// 1. `specialTypes`, a set of pre-defined schemas
-func buildCustomSchemasByMessageName() map[string]*apiext.JSONSchemaProps {
- schemasByMessageName := make(map[string]*apiext.JSONSchemaProps)
-
- // Initialize the hard-coded values
- for name, schema := range specialTypes {
- schemasByMessageName[name] = schema
- }
-
- return schemasByMessageName
-}
-
-func (g *openapiGenerator) generateOutput(filesToGen
map[*protomodel.FileDescriptor]bool) (*plugin.CodeGeneratorResponse, error) {
- response := plugin.CodeGeneratorResponse{}
-
- g.generateSingleFileOutput(filesToGen, &response)
-
- return &response, nil
-}
-
-func (g *openapiGenerator) getFileContents(
- file *protomodel.FileDescriptor,
- messages map[string]*protomodel.MessageDescriptor,
- enums map[string]*protomodel.EnumDescriptor,
- descriptions map[string]string,
-) {
- for _, m := range file.AllMessages {
- messages[g.relativeName(m)] = m
- }
-
- for _, e := range file.AllEnums {
- enums[g.relativeName(e)] = e
- }
- for _, v := range file.Matter.Extra {
- if _, n, f := strings.Cut(v, "schema: "); f {
- descriptions[n] = fmt.Sprintf("%v See more details at:
%v", file.Matter.Description, file.Matter.HomeLocation)
- }
- }
-}
-
-func (g *openapiGenerator) generateSingleFileOutput(filesToGen
map[*protomodel.FileDescriptor]bool, response *plugin.CodeGeneratorResponse) {
- messages := make(map[string]*protomodel.MessageDescriptor)
- enums := make(map[string]*protomodel.EnumDescriptor)
- descriptions := make(map[string]string)
-
- for file, ok := range filesToGen {
- if ok {
- g.getFileContents(file, messages, enums, descriptions)
- }
- }
-
- rf := g.generateFile("kubernetes/customresourcedefinitions.gen.yaml",
messages, enums, descriptions)
- response.File = []*plugin.CodeGeneratorResponse_File{&rf}
-}
-
-const (
- enableCRDGenTag = "+cue-gen"
-)
-
-func cleanComments(lines []string) []string {
- out := []string{}
- var prevLine string
- for _, line := range lines {
- line = strings.Trim(line, " ")
-
- if line == "-->" {
- out = append(out, prevLine)
- prevLine = ""
- continue
- }
-
- if !strings.HasPrefix(line, enableCRDGenTag) {
- if prevLine != "" && len(line) != 0 {
- prevLine += " " + line
- }
- continue
- }
-
- out = append(out, prevLine)
-
- prevLine = line
-
- }
- if prevLine != "" {
- out = append(out, prevLine)
- }
- return out
-}
-
-func parseGenTags(s string) map[string]string {
- lines := cleanComments(strings.Split(s, "\n"))
- res := map[string]string{}
- for _, line := range lines {
- if len(line) == 0 {
- continue
- }
- _, contents, f := strings.Cut(line, enableCRDGenTag)
- if !f {
- continue
- }
- spl := strings.SplitN(contents[1:], ":", 3)
- if len(spl) < 2 {
- log.Fatalf("invalid tag: %v", line)
- }
- val := ""
- if len(spl) > 2 {
- val = spl[2]
- }
- if _, f := res[spl[1]]; f {
- res[spl[1]] += ";;" + val
- } else {
- res[spl[1]] = val
- }
- }
- if len(res) == 0 {
- return nil
- }
- return res
-}
-
-// Generate an OpenAPI spec for a collection of cross-linked files.
-func (g *openapiGenerator) generateFile(
- name string,
- messages map[string]*protomodel.MessageDescriptor,
- enums map[string]*protomodel.EnumDescriptor,
- descriptions map[string]string,
-) plugin.CodeGeneratorResponse_File {
- g.messages = messages
-
- allSchemas := make(map[string]*apiext.JSONSchemaProps)
-
- // Type --> Key --> Value
- genTags := map[string]map[string]string{}
-
- for _, message := range messages {
- // we generate the top-level messages here and the nested
messages are generated
- // inside each top-level message.
- if message.Parent == nil {
- g.generateMessage(message, allSchemas)
- }
- if gt := parseGenTags(message.Location().GetLeadingComments());
gt != nil {
- genTags[g.absoluteName(message)] = gt
- }
- }
-
- for _, enum := range enums {
- // when there is no parent to the enum.
- if len(enum.QualifiedName()) == 1 {
- g.generateEnum(enum, allSchemas)
- }
- }
-
- // Name -> CRD
- crds := map[string]*apiext.CustomResourceDefinition{}
-
- for name, cfg := range genTags {
- log.Println("Generating", name)
- group := cfg["groupName"]
-
- versionsString := cfg["versions"]
- versions := strings.Split(versionsString, ",")
- var storageVersion string
- if version := cfg["version"]; version != "" {
- if len(versions) == 0 {
- log.Fatal("can only set versions or version")
- }
- if _, f := cfg["storageVersion"]; f {
- // Old way: single version specifies explicitly
- storageVersion = version
- }
- versions = []string{version}
- } else {
- // New way: first one is the storage version
- storageVersion = versions[0]
- }
- kind := name[strings.LastIndex(name, ".")+1:]
- singular := strings.ToLower(kind)
- plural := singular + "s"
- spec := *allSchemas[name]
- if d, f := descriptions[name]; f {
- spec.Description = d
- }
- schema := &apiext.JSONSchemaProps{
- Type: "object",
- Properties: map[string]apiext.JSONSchemaProps{
- "spec": spec,
- },
- }
- names := apiext.CustomResourceDefinitionNames{
- Kind: kind,
- ListKind: kind + "List",
- Plural: plural,
- Singular: singular,
- }
-
- if res, f := cfg["resource"]; f {
- for n, m := range extractKeyValue(res) {
- switch n {
- case "categories":
- names.Categories =
mergeSlices(names.Categories, strings.Split(m, ","))
- case "plural":
- names.Plural = m
- case "kind":
- names.Kind = m
- case "shortNames":
- names.ShortNames =
mergeSlices(names.ShortNames, strings.Split(m, ","))
- case "singular":
- names.Singular = m
- case "listKind":
- names.ListKind = m
- }
- }
- }
- name := names.Plural + "." + group
- for _, version := range versions {
- ver := apiext.CustomResourceDefinitionVersion{
- Name: version,
- Served: true,
- Schema: &apiext.CustomResourceValidation{
- OpenAPIV3Schema: schema.DeepCopy(),
- },
- }
- if pk, f := cfg["printerColumn"]; f {
- pcs := strings.Split(pk, ";;")
- for _, pc := range pcs {
- if pc == "" {
- continue
- }
- column :=
apiext.CustomResourceColumnDefinition{}
- for n, m := range extractKeyValue(pc) {
- switch n {
- case "name":
- column.Name = m
- case "type":
- column.Type = m
- case "description":
- column.Description = m
- case "JSONPath":
- column.JSONPath = m
- }
- }
- ver.AdditionalPrinterColumns =
append(ver.AdditionalPrinterColumns, column)
- }
- }
- if sr, f := cfg["subresource"]; f {
- k, v, ok := strings.Cut(sr, "=")
- if !ok {
- k = sr
- }
- if k == "status" {
- if v == "" {
- // Back compat
- v =
"dubbo.meta.v1alpha1.DubboStatus"
- }
- ver.Subresources =
&apiext.CustomResourceSubresources{Status:
&apiext.CustomResourceSubresourceStatus{}}
- status, f := allSchemas[v]
- if !f {
- log.Fatalf("Schema %v not
found", v)
- }
- // Because status can be written by
arbitrary third party controllers, allow unknown fields.
- // These really should be using
`conditions`, which is an unstructured list, but they may not be.
- // For backwards compat, we make this
allow unknown fields.
- schema := *status.DeepCopy()
- alwaysTrue := true
- schema.XPreserveUnknownFields =
&alwaysTrue
-
ver.Schema.OpenAPIV3Schema.Properties["status"] = schema
- }
- }
- if sr, f := cfg["spec"]; f {
- if sr == "required" {
- ver.Schema.OpenAPIV3Schema.Required =
append(ver.Schema.OpenAPIV3Schema.Required, "spec")
- }
- }
- if version == storageVersion {
- ver.Storage = true
- }
- if r, f := cfg["deprecationReplacement"]; f {
- msg := fmt.Sprintf("%v version %q is
deprecated, use %q", name, ver.Name, r)
- ver.Deprecated = true
- ver.DeprecationWarning = &msg
- }
- if err :=
validateStructural(ver.Schema.OpenAPIV3Schema); err != nil {
- log.Fatalf("failed to validate %v as
structural: %v", kind, err)
- }
-
- crd, f := crds[name]
- if !f {
- crd = &apiext.CustomResourceDefinition{
- TypeMeta: metav1.TypeMeta{
- APIVersion:
"apiextensions.k8s.io/v1",
- Kind:
"CustomResourceDefinition",
- },
- ObjectMeta: metav1.ObjectMeta{
- Annotations:
extractKeyValue(cfg["annotations"]),
- Labels:
extractKeyValue(cfg["labels"]),
- Name: name,
- },
- Spec:
apiext.CustomResourceDefinitionSpec{
- Group: group,
- Names: names,
- Scope: apiext.NamespaceScoped,
- },
- Status:
apiext.CustomResourceDefinitionStatus{},
- }
- }
-
- crd.Spec.Versions = append(crd.Spec.Versions, ver)
- crds[name] = crd
- slices.SortFunc(crd.Spec.Versions, func(a, b
apiext.CustomResourceDefinitionVersion) int {
- if a.Name == b.Name {
- log.Fatalf("%v has the version %v
twice", name, a.Name)
- }
- if a.Name < b.Name {
- return -1
- }
- return 1
- })
- }
- }
-
- // sort the configs so that the order is deterministic.
- keys := maps.Keys(crds)
- slices.SortFunc(keys, func(a, b string) int {
- if crds[a].Spec.Group+a < crds[b].Spec.Group+b {
- return -1
- }
- return 1
- })
-
- bb := &bytes.Buffer{}
- bb.WriteString("# DO NOT EDIT - Generated by Cue OpenAPI generator
based on Dubbo APIs.\n")
- for i, crdName := range keys {
- crd := crds[crdName]
- b, err := yaml.Marshal(crd)
- if err != nil {
- log.Fatalf("unable to marshall the output of %v to
yaml", name)
- }
- b = fixupYaml(b)
- bb.Write(b)
- if i != len(crds)-1 {
- bb.WriteString("---\n")
- }
- }
-
- return plugin.CodeGeneratorResponse_File{
- Name: proto.String(name),
- Content: proto.String(bb.String()),
- }
-}
-
-func mergeSlices(a []string, b []string) []string {
- have := sets.New(a...)
- for _, bb := range b {
- if !have.Has(bb) {
- a = append(a, bb)
- }
- }
- return a
-}
-
-// extractKeyValue extracts a string to key value pairs
-// e.g. a=b,b=c to map[a:b b:c]
-// and a=b,c,d,e=f to map[a:b,c,d e:f]
-func extractKeyValue(s string) map[string]string {
- out := map[string]string{}
- if s == "" {
- return out
- }
- splits := strings.Split(s, "=")
- if len(splits) == 1 {
- out[splits[0]] = ""
- }
- if strings.Contains(splits[0], ",") {
- log.Fatalf("cannot parse %v to key value pairs", s)
- }
- nextkey := splits[0]
- for i := 1; i < len(splits); i++ {
- if splits[i] == "" || splits[i] == "," {
- log.Fatalf("cannot parse %v to key value paris, invalid
value", s)
- }
- if !strings.Contains(splits[i], ",") && i != len(splits)-1 {
- log.Fatalf("cannot parse %v to key value pairs, missing
separator", s)
- }
- if i == len(splits)-1 {
- out[nextkey] = strings.Trim(splits[i], "\"'`")
- continue
- }
- index := strings.LastIndex(splits[i], ",")
- out[nextkey] = strings.Trim(splits[i][:index], "\"'`")
- nextkey = splits[i][index+1:]
- if nextkey == "" {
- log.Fatalf("cannot parse %v to key value pairs, missing
key", s)
- }
- }
- return out
-}
-
-const (
- statusOutput = `
-status:
- acceptedNames:
- kind: ""
- plural: ""
- conditions: null
- storedVersions: null`
-
- creationTimestampOutput = `
- creationTimestamp: null`
-)
-
-func fixupYaml(y []byte) []byte {
- // remove the status and creationTimestamp fields from the output.
Ideally we could use OrderedMap to remove those.
- y = bytes.ReplaceAll(y, []byte(statusOutput), []byte(""))
- y = bytes.ReplaceAll(y, []byte(creationTimestampOutput), []byte(""))
- // keep the quotes in the output which is required by helm.
- y = bytes.ReplaceAll(y, []byte("helm.sh/resource-policy: keep"),
[]byte(`"helm.sh/resource-policy": keep`))
- return y
-}
-
-func (g *openapiGenerator) generateMessage(message
*protomodel.MessageDescriptor, allSchemas map[string]*apiext.JSONSchemaProps) {
- if o := g.generateMessageSchema(message); o != nil {
- allSchemas[g.absoluteName(message)] = o
- }
-}
-
-func (g *openapiGenerator) generateCustomMessageSchema(message
*protomodel.MessageDescriptor, customSchema *apiext.JSONSchemaProps)
*apiext.JSONSchemaProps {
- o := customSchema
- o.Description = g.generateDescription(message)
-
- return o
-}
-
-func (g *openapiGenerator) generateMessageSchema(message
*protomodel.MessageDescriptor) *apiext.JSONSchemaProps {
- // skip MapEntry message because we handle map using the map's repeated
field.
- if message.GetOptions().GetMapEntry() {
- return nil
- }
- o := &apiext.JSONSchemaProps{
- Type: "object",
- Properties: make(map[string]apiext.JSONSchemaProps),
- }
- o.Description = g.generateDescription(message)
-
- const CELOneOf = false
-
- for _, field := range message.Fields {
- fn := g.fieldName(field)
- sr := g.fieldType(field)
- o.Properties[fn] = *sr
-
- if isRequired(field) {
- o.Required = append(o.Required, fn)
- }
-
- // Hack: allow "alt names"
- for _, an := range g.fieldAltNames(field) {
- o.Properties[an] = *sr
- }
- }
-
- // Generate OneOf
- // CEL can do this very cleanly but breaks in K8s:
https://github.com/kubernetes/kubernetes/issues/120973
- // OpenAPI can do it with OneOf, but it gets a bit gross to represent
"allow none set" as well.
- // Many oneOfs do end up requiring at least one to be set, though
-- perhaps we can simplify these cases.
- if CELOneOf {
- oneOfs := make([][]string, len(message.OneofDecl))
- for _, field := range message.Fields {
- // Record any oneOfs
- if field.OneofIndex != nil {
- oneOfs[*field.OneofIndex] =
append(oneOfs[*field.OneofIndex], g.fieldName(field))
- }
- }
- for _, oo := range oneOfs {
- o.XValidations = append(o.XValidations,
apiext.ValidationRule{
- Rule: buildCELOneOf(oo),
- Message: fmt.Sprintf("At most one of %v should
be set", oo),
- })
- }
- } else {
- oneOfs := make([]apiext.JSONSchemaProps, len(message.OneofDecl))
- for _, field := range message.Fields {
- // Record any oneOfs
- if field.OneofIndex != nil {
- oneOfs[*field.OneofIndex].OneOf =
append(oneOfs[*field.OneofIndex].OneOf, apiext.JSONSchemaProps{Required:
[]string{g.fieldName(field)}})
- }
- }
- for i, oo := range oneOfs {
- oo.OneOf = append([]apiext.JSONSchemaProps{{Not:
&apiext.JSONSchemaProps{AnyOf: oo.OneOf}}}, oo.OneOf...)
- oneOfs[i] = oo
- }
- switch len(oneOfs) {
- case 0:
- case 1:
- o.OneOf = oneOfs[0].OneOf
- default:
- o.AllOf = oneOfs
- }
- }
-
- applyExtraValidations(o, message, markers.DescribesType)
-
- return o
-}
-
-func isRequired(fd *protomodel.FieldDescriptor) bool {
- if fd.Options == nil {
- return false
- }
- if !proto.HasExtension(fd.Options, annotations.E_FieldBehavior) {
- return false
- }
- ext := proto.GetExtension(fd.Options, annotations.E_FieldBehavior)
- opts, ok := ext.([]annotations.FieldBehavior)
- if !ok {
- return false
- }
- for _, o := range opts {
- if o == annotations.FieldBehavior_REQUIRED {
- return true
- }
- }
- return false
-}
-
-// buildCELOneOf builds a CEL expression to select oneOf the fields below
-// Ex: (has(self.a) ? 1 : 0) + (has(self.b) ? 1 : 0) <= 1
-func buildCELOneOf(names []string) string {
- clauses := []string{}
- for _, n := range names {
- // For each name, count how many are set
- clauses = append(clauses, fmt.Sprintf("(has(self.%v)?1:0)", n))
- }
- // We should have 0 or 1 set.
- return strings.Join(clauses, "+") + "<=1"
-}
-
-func (g *openapiGenerator) generateEnum(enum *protomodel.EnumDescriptor,
allSchemas map[string]*apiext.JSONSchemaProps) {
- o := g.generateEnumSchema(enum)
- allSchemas[g.absoluteName(enum)] = o
-}
-
-func (g *openapiGenerator) generateEnumSchema(enum *protomodel.EnumDescriptor)
*apiext.JSONSchemaProps {
- o := &apiext.JSONSchemaProps{Type: "string"}
- // Enum description is not used in Kubernetes
- // o.Description = g.generateDescription(enum)
-
- // If the schema should be int or string, mark it as such
- if g.enumAsIntOrString {
- o.XIntOrString = true
- return o
- }
-
- // otherwise, return define the expected string values
- values := enum.GetValue()
- for _, v := range values {
- b, _ := json.Marshal(v.GetName())
- o.Enum = append(o.Enum, apiext.JSON{Raw: b})
- }
- o.Type = "string"
-
- return o
-}
-
-func (g *openapiGenerator) absoluteName(desc protomodel.CoreDesc) string {
- typeName := protomodel.DottedName(desc)
- return desc.PackageDesc().Name + "." + typeName
-}
-
-// converts the first section of the leading comment or the description of the
proto
-// to a single line of description.
-func (g *openapiGenerator) generateDescription(desc protomodel.CoreDesc)
string {
- if !g.descriptionConfiguration.IncludeDescriptionInSchema {
- return ""
- }
-
- c := strings.TrimSpace(desc.Location().GetLeadingComments())
- if strings.Contains(c, "$hide_from_docs") {
- return ""
- }
- words := strings.Fields(c)
- for i, w := range words {
- if strings.HasSuffix(w, ".") {
- return strings.Join(words[:i+1], " ")
- }
- }
- return ""
-}
-
-func (g *openapiGenerator) fieldType(field *protomodel.FieldDescriptor)
*apiext.JSONSchemaProps {
- schema := &apiext.JSONSchemaProps{}
- var isMap bool
- switch *field.Type {
- case descriptor.FieldDescriptorProto_TYPE_FLOAT,
descriptor.FieldDescriptorProto_TYPE_DOUBLE:
- schema.Type = "number"
- schema.Format = "double"
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_INT32,
descriptor.FieldDescriptorProto_TYPE_SINT32,
descriptor.FieldDescriptorProto_TYPE_SFIXED32:
- schema.Type = "integer"
- schema.Format = "int32"
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_INT64,
descriptor.FieldDescriptorProto_TYPE_SINT64,
descriptor.FieldDescriptorProto_TYPE_SFIXED64:
- schema.Type = "integer"
- schema.Format = "int64"
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_UINT64,
descriptor.FieldDescriptorProto_TYPE_FIXED64:
- schema.Type = "integer"
- schema.Minimum = Ptr(float64(0))
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_UINT32,
descriptor.FieldDescriptorProto_TYPE_FIXED32:
- schema.Type = "integer"
- schema.Minimum = Ptr(float64(0))
- schema.Maximum = Ptr(float64(math.MaxUint32))
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_BOOL:
- schema.Type = "boolean"
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_STRING:
- schema.Type = "string"
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
- msg := field.FieldType.(*protomodel.MessageDescriptor)
- if customSchema, ok :=
g.customSchemasByMessageName[g.absoluteName(msg)]; ok {
- // Deep copy since it is a shared type we may modify
later
- schema = g.generateCustomMessageSchema(msg,
customSchema.DeepCopy())
- } else if msg.GetOptions().GetMapEntry() {
- isMap = true
- sr := g.fieldType(msg.Fields[1])
- schema = sr
- schema = &apiext.JSONSchemaProps{
- Type: "object",
- AdditionalProperties:
&apiext.JSONSchemaPropsOrBool{Schema: schema},
- }
-
- } else {
- schema = g.generateMessageSchema(msg)
- }
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_BYTES:
- schema.Type = "string"
- schema.Format = "byte"
- schema.Description = g.generateDescription(field)
-
- case descriptor.FieldDescriptorProto_TYPE_ENUM:
- enum := field.FieldType.(*protomodel.EnumDescriptor)
- schema = g.generateEnumSchema(enum)
- desc := g.generateDescription(field)
- // Add all options to the description
- valid := []string{}
- for i, v := range enum.Values {
- n := v.GetName()
- // Allow skipping the default value if its a bogus
value.
- if i == 0 && (strings.Contains(n, "UNSPECIFIED") ||
- strings.Contains(n, "UNSET") ||
- strings.Contains(n, "UNDEFINED") ||
- strings.Contains(n, "INVALID")) {
- continue
- }
- valid = append(valid, n)
- }
- schema.Description = desc + fmt.Sprintf("\n\nValid Options:
%v", strings.Join(valid, ", "))
- }
-
- if field.IsRepeated() && !isMap {
- schema = &apiext.JSONSchemaProps{
- // Format: "array",
- Type: "array",
- Items: &apiext.JSONSchemaPropsOrArray{Schema: schema},
- }
- schema.Description = schema.Items.Schema.Description
- schema.Items.Schema.Description = ""
- }
-
- applyExtraValidations(schema, field, markers.DescribesField)
-
- return schema
-}
-
-type SchemaApplier interface {
- ApplyToSchema(schema *apiext.JSONSchemaProps) error
-}
-
-const (
- KubeBuilderValidationPrefix = "+kubebuilder:validation:"
- ProtocGenValidationPrefix = "+protoc-gen-crd:"
- MapValidationPrefix = "+protoc-gen-crd:map-value-validation:"
- ListValidationPrefix = "+protoc-gen-crd:list-value-validation:"
- DurationValidationPrefix = "+protoc-gen-crd:duration-validation:"
- IntOrStringValidation = "+protoc-gen-crd:validation:XIntOrString"
- // IgnoreSubValidation is a custom validation allowing to refer to a
type, but remove some validation
- // This is useful when we are embedding a different type in a different
context.
- IgnoreSubValidation = "+protoc-gen-crd:validation:IgnoreSubValidation:"
-)
-
-var Celpp = func() *celpp.Preprocessor {
- p, err := celpp.New(macros.All...)
- if err != nil {
- log.Fatalf("failed to build cel preprocessor: %v", err)
- }
- return p
-}()
-
-func applyExtraValidations(schema *apiext.JSONSchemaProps, m
protomodel.CoreDesc, t markers.TargetType) {
- for _, line := range strings.Split(m.Location().GetLeadingComments(),
"\n") {
- line = strings.TrimSpace(line)
- if !strings.Contains(line, KubeBuilderValidationPrefix) &&
- !strings.Contains(line, "+list") &&
- !strings.Contains(line, ProtocGenValidationPrefix) {
- continue
- }
- schema := schema
-
- // Custom logic to apply validations to map values. In go, they
just make a type alias and apply policy there; proto cannot do that.
- if strings.Contains(line, MapValidationPrefix) {
- schema = schema.AdditionalProperties.Schema
- line = strings.ReplaceAll(line, MapValidationPrefix,
KubeBuilderValidationPrefix)
- }
- if strings.Contains(line, ListValidationPrefix) {
- schema = schema.Items.Schema
- line = strings.ReplaceAll(line, ListValidationPrefix,
KubeBuilderValidationPrefix)
- }
- // This is a hack to allow a certain field to opt-out of the
default "Duration must be non-zero"
- if strings.Contains(line, DurationValidationPrefix+"none") {
- schema.XValidations = nil
- return
- }
- // Kubernetes is very particular about the format for
XIntOrString, must match exactly this
- if strings.Contains(line, IntOrStringValidation) {
- schema.Format = ""
- schema.Type = ""
- schema.AnyOf = []apiext.JSONSchemaProps{
- {Type: "integer"},
- {Type: "string"},
- }
- line = strings.ReplaceAll(line,
ProtocGenValidationPrefix+"validation:", KubeBuilderValidationPrefix)
- }
-
- if strings.Contains(line, IgnoreSubValidation) {
- li := strings.TrimPrefix(line, IgnoreSubValidation)
- items := []string{}
- if err := json.Unmarshal([]byte(li), &items); err !=
nil {
- log.Fatalf("invalid %v %v: %v",
IgnoreSubValidation, line, err)
- }
- recursivelyStripValidation(schema, items)
- continue
- }
- if strings.Contains(line,
"+kubebuilder:validation:XValidation:") {
- left, right, ok := strings.Cut(line, ",rule=")
- if !ok {
- log.Fatalf("failed to parse marker %v", line)
- }
- expr := right[1 : len(right)-1]
- nexpr, err := Celpp.Process(expr)
- if err != nil {
- log.Fatalf("failed to pre-process %v: %v",
expr, err)
- }
- line = left + ",rule=" + fmt.Sprintf("%q", nexpr)
- }
-
- def := markerRegistry.Lookup(line, t)
- if def == nil {
- log.Fatalf("unknown validation: %v", line)
- }
- a, err := def.Parse(line)
- if err != nil {
- log.Fatalf("failed to parse: %v", line)
- }
- if err := a.(SchemaApplier).ApplyToSchema(schema); err != nil {
- log.Fatalf("failed to apply schema %q: %v",
schema.Description, err)
- }
- }
-}
-
-type stripVisitor struct {
- removeMessages sets.Set[string]
-}
-
-func (s stripVisitor) Visit(schema *apiext.JSONSchemaProps) crd.SchemaVisitor {
- if schema != nil && schema.XValidations != nil {
- schema.XValidations = FilterInPlace(schema.XValidations,
func(rule apiext.ValidationRule) bool {
- return !s.removeMessages.Has(rule.Message)
- })
- }
- return s
-}
-
-func recursivelyStripValidation(schema *apiext.JSONSchemaProps, items
[]string) {
- crd.EditSchema(schema, stripVisitor{sets.New(items...)})
-}
-
-func FilterInPlace[E any](s []E, f func(E) bool) []E {
- n := 0
- for _, val := range s {
- if f(val) {
- s[n] = val
- n++
- }
- }
-
- // If those elements contain pointers you might consider zeroing those
elements
- // so that objects they reference can be garbage collected."
- var empty E
- for i := n; i < len(s); i++ {
- s[i] = empty
- }
-
- s = s[:n]
- return s
-}
-
-func (g *openapiGenerator) fieldName(field *protomodel.FieldDescriptor) string
{
- return field.GetJsonName()
-}
-
-func (g *openapiGenerator) fieldAltNames(field *protomodel.FieldDescriptor)
[]string {
- _, an, f := strings.Cut(field.Location().GetLeadingComments(),
"+kubebuilder:altName=")
- if f {
- return []string{strings.Fields(an)[0]}
- }
- return nil
-}
-
-func (g *openapiGenerator) relativeName(desc protomodel.CoreDesc) string {
- typeName := protomodel.DottedName(desc)
- if desc.PackageDesc() == g.currentPackage {
- return typeName
- }
-
- return desc.PackageDesc().Name + "." + typeName
-}
-
-func Ptr[T any](t T) *T {
- return &t
-}
-
-func validateStructural(s *apiext.JSONSchemaProps) error {
- out := &apiextinternal.JSONSchemaProps{}
- if err :=
apiext.Convert_v1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(s, out,
nil); err != nil {
- return fmt.Errorf("cannot convert v1 JSONSchemaProps to
JSONSchemaProps: %v", err)
- }
- r, err := structuralschema.NewStructural(out)
- if err != nil {
- return fmt.Errorf("cannot convert to a structural schema: %v",
err)
- }
-
- if errs := structuralschema.ValidateStructural(nil, r); len(errs) != 0 {
- b, _ := yaml.Marshal(s)
- return fmt.Errorf("schema is not structural: %v (%+v)",
errs.ToAggregate().Error(), string(b))
- }
-
- return nil
-}
-
-var markerRegistry = func() *markers.Registry {
- registry := &markers.Registry{}
- if err := crdmarkers.Register(registry); err != nil {
- log.Fatal(err)
- }
- return registry
-}()
diff --git a/tools/cmd/protoc-gen-crd/pkg/protocgen/generate.go
b/tools/cmd/protoc-gen-crd/pkg/protocgen/generate.go
deleted file mode 100644
index e267e15d..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protocgen/generate.go
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protocgen
-
-import (
- "fmt"
- "io"
- "os"
-
- plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
- "google.golang.org/protobuf/proto"
-)
-
-// GenerateFn is a function definition for encapsulating the ore logic of code
generation.
-type GenerateFn func(req *plugin.CodeGeneratorRequest)
(*plugin.CodeGeneratorResponse, error)
-
-// Generate is a wrapper for a main function of a protoc generator plugin.
-func Generate(fn GenerateFn) {
- data, err := io.ReadAll(os.Stdin)
- if err != nil {
- fatal("Unable to read input proto: %v\n", err)
- }
-
- var request plugin.CodeGeneratorRequest
- if err = proto.Unmarshal(data, &request); err != nil {
- fatal("Unable to parse input proto: %v\n", err)
- }
-
- response, err := fn(&request)
- if err != nil {
- fatal("%v\n", err)
- }
-
- data, err = proto.Marshal(response)
- if err != nil {
- fatal("Unable to serialize output proto: %v\n", err)
- }
-
- _, err = os.Stdout.Write(data)
- if err != nil {
- fatal("Unable to write output proto: %v\n", err)
- }
-}
-
-func fatal(format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "ERROR: "+format, args...)
- os.Exit(1)
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/baseDesc.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/baseDesc.go
deleted file mode 100644
index 3789dd42..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/baseDesc.go
+++ /dev/null
@@ -1,125 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "strings"
-
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
-)
-
-// CoreDesc is an interface abstracting the abilities shared by all descriptors
-type CoreDesc interface {
- PackageDesc() *PackageDescriptor
- FileDesc() *FileDescriptor
- QualifiedName() []string
- IsHidden() bool
- Class() string
- Location() LocationDescriptor
-}
-
-// The common data for every descriptor in the model. This implements the
coreDesc interface.
-type baseDesc struct {
- loc *descriptor.SourceCodeInfo_Location
- hidden bool
- cl string
- file *FileDescriptor
- name []string
-}
-
-func newBaseDesc(file *FileDescriptor, path pathVector, qualifiedName
[]string) baseDesc {
- loc := file.find(path)
- cl := ""
- com := ""
-
- if loc != nil {
- var newCom string
- com = loc.GetLeadingComments()
- if com != "" {
- cl, newCom = getClass(com)
- if cl != "" {
- clone := *loc // nolint: govet
- clone.LeadingComments = &newCom
- loc = &clone
- }
- } else {
- com = loc.GetTrailingComments()
- if com != "" {
- cl, newCom = getClass(com)
- if cl != "" {
- clone := *loc // nolint: govet
- clone.TrailingComments = &newCom
- loc = &clone
- }
- }
- }
- }
-
- return baseDesc{
- file: file,
- loc: loc,
- hidden: strings.Contains(com, "$hide_from_docs") ||
strings.Contains(com, "[#not-implemented-hide:]"),
- cl: cl,
- name: qualifiedName,
- }
-}
-
-const class = "$class: "
-
-func getClass(com string) (cl string, newCom string) {
- start := strings.Index(com, class)
- if start < 0 {
- return cl, newCom
- }
-
- name := start + len(class)
- end := strings.IndexAny(com[name:], " \t\n") + start + len(class)
-
- if end < 0 {
- newCom = com[:start]
- cl = com[name:]
- } else {
- newCom = com[:start] + com[end:]
- cl = com[name:end]
- }
-
- return cl, newCom
-}
-
-func (bd baseDesc) PackageDesc() *PackageDescriptor {
- return bd.file.Parent
-}
-
-func (bd baseDesc) FileDesc() *FileDescriptor {
- return bd.file
-}
-
-func (bd baseDesc) QualifiedName() []string {
- return bd.name
-}
-
-func (bd baseDesc) IsHidden() bool {
- return bd.hidden
-}
-
-func (bd baseDesc) Class() string {
- return bd.cl
-}
-
-func (bd baseDesc) Location() LocationDescriptor {
- return newLocationDescriptor(bd.loc, bd.file)
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/enumDescriptor.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/enumDescriptor.go
deleted file mode 100644
index ac33c36b..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/enumDescriptor.go
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
-)
-
-type EnumDescriptor struct {
- baseDesc
- *descriptor.EnumDescriptorProto
- Values []*EnumValueDescriptor // The values of this enum
-}
-
-type EnumValueDescriptor struct {
- baseDesc
- *descriptor.EnumValueDescriptorProto
-}
-
-func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent
*MessageDescriptor, file *FileDescriptor, path pathVector) *EnumDescriptor {
- var qualifiedName []string
- if parent == nil {
- qualifiedName = []string{desc.GetName()}
- } else {
- qualifiedName = make([]string, len(parent.QualifiedName()),
len(parent.QualifiedName())+1)
- copy(qualifiedName, parent.QualifiedName())
- qualifiedName = append(qualifiedName, desc.GetName())
- }
-
- e := &EnumDescriptor{
- EnumDescriptorProto: desc,
- baseDesc: newBaseDesc(file, path, qualifiedName),
- }
-
- e.Values = make([]*EnumValueDescriptor, 0, len(desc.Value))
- for i, ev := range desc.Value {
- nameCopy := make([]string, len(qualifiedName),
len(qualifiedName)+1)
- copy(nameCopy, qualifiedName)
- nameCopy = append(nameCopy, ev.GetName())
-
- evd := &EnumValueDescriptor{
- EnumValueDescriptorProto: ev,
- baseDesc: newBaseDesc(file,
path.append(enumValuePath, i), nameCopy),
- }
- e.Values = append(e.Values, evd)
- }
-
- return e
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/fileDescriptor.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/fileDescriptor.go
deleted file mode 100644
index 97873918..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/fileDescriptor.go
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
-)
-
-type FileDescriptor struct {
- *descriptor.FileDescriptorProto
- Parent *PackageDescriptor
- AllMessages []*MessageDescriptor // All
the messages defined in this file
- AllEnums []*EnumDescriptor // All
the enums defined in this file
- Messages []*MessageDescriptor //
Top-level messages defined in this file
- Enums []*EnumDescriptor //
Top-level enums defined in this file
- Services []*ServiceDescriptor // All
services defined in this file
- Dependencies []*FileDescriptor //
Files imported by this file
- locations map[pathVector]*descriptor.SourceCodeInfo_Location //
Provenance
- Matter FrontMatter //
Title, overview, homeLocation, front_matter
-}
-
-func newFileDescriptor(desc *descriptor.FileDescriptorProto, parent
*PackageDescriptor) *FileDescriptor {
- f := &FileDescriptor{
- FileDescriptorProto: desc,
- locations:
make(map[pathVector]*descriptor.SourceCodeInfo_Location,
len(desc.GetSourceCodeInfo().GetLocation())),
- Parent: parent,
- }
-
- // put all the locations in a map for quick lookup
- for _, loc := range desc.GetSourceCodeInfo().GetLocation() {
- if len(loc.Path) > 0 {
- pv := newPathVector(int(loc.Path[0]))
- for _, v := range loc.Path[1:] {
- pv = pv.append(int(v))
- }
- f.locations[pv] = loc
- }
- }
-
- path := newPathVector(messagePath)
- for i, md := range desc.MessageType {
- f.Messages = append(f.Messages, newMessageDescriptor(md, nil,
f, path.append(i)))
- }
-
- path = newPathVector(enumPath)
- for i, e := range desc.EnumType {
- f.Enums = append(f.Enums, newEnumDescriptor(e, nil, f,
path.append(i)))
- }
-
- path = newPathVector(servicePath)
- for i, s := range desc.Service {
- f.Services = append(f.Services, newServiceDescriptor(s, f,
path.append(i)))
- }
-
- // Find title/overview/etc content in comments and store it explicitly.
- loc := f.find(newPathVector(packagePath))
- if loc != nil && loc.LeadingDetachedComments != nil {
- f.Matter = extractFrontMatter(f.GetName(), loc, f)
- }
-
- // get the transitive close of all messages and enums
- f.aggregateMessages(f.Messages)
- f.aggregateEnums(f.Enums)
-
- return f
-}
-
-func (f *FileDescriptor) find(path pathVector)
*descriptor.SourceCodeInfo_Location {
- loc := f.locations[path]
- return loc
-}
-
-func (f *FileDescriptor) aggregateMessages(messages []*MessageDescriptor) {
- f.AllMessages = append(f.AllMessages, messages...)
- for _, msg := range messages {
- f.aggregateMessages(msg.Messages)
- f.aggregateEnums(msg.Enums)
- }
-}
-
-func (f *FileDescriptor) aggregateEnums(enums []*EnumDescriptor) {
- f.AllEnums = append(f.AllEnums, enums...)
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/frontMatter.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/frontMatter.go
deleted file mode 100644
index 0f21050b..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/frontMatter.go
+++ /dev/null
@@ -1,116 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "fmt"
- "os"
- "strings"
-
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
-)
-
-type Mode string
-
-var (
- ModeUnset Mode
- ModeFile Mode = "file"
- ModePackage Mode = "package"
- ModeNone Mode = "none"
-)
-
-type FrontMatter struct {
- Title string
- Overview string
- Description string
- HomeLocation string
- Extra []string
- Location LocationDescriptor
- Mode Mode
-}
-
-const (
- titleTag = "$title: "
- overviewTag = "$overview: "
- descriptionTag = "$description: "
- locationTag = "$location: "
- frontMatterTag = "$front_matter: "
- modeTag = "$mode: "
-)
-
-func checkSingle(name string, old string, line string, tag string) string {
- result := line[len(tag):]
- if old != "" {
- _, _ = fmt.Fprintf(os.Stderr, "%v has more than one %v: %v\n",
name, tag, result)
- }
- return result
-}
-
-func extractFrontMatter(name string, loc *descriptor.SourceCodeInfo_Location,
file *FileDescriptor) FrontMatter {
- title := ""
- overview := ""
- description := ""
- homeLocation := ""
- mode := ""
- var extra []string
-
- for _, para := range loc.LeadingDetachedComments {
- lines := strings.Split(para, "\n")
- for _, l := range lines {
- l = strings.Trim(l, " ")
-
- if strings.HasPrefix(l, "$") {
- if strings.HasPrefix(l, titleTag) {
- title = checkSingle(name, title, l,
titleTag)
- } else if strings.HasPrefix(l, overviewTag) {
- overview = checkSingle(name, overview,
l, overviewTag)
- } else if strings.HasPrefix(l, descriptionTag) {
- description = checkSingle(name,
description, l, descriptionTag)
- } else if strings.HasPrefix(l, locationTag) {
- homeLocation = checkSingle(name,
homeLocation, l, locationTag)
- } else if strings.HasPrefix(l, frontMatterTag) {
- // old way to specify custom
front-matter
- extra = append(extra,
l[len(frontMatterTag):])
- } else if strings.HasPrefix(l, modeTag) {
- mode = checkSingle(name, mode, l,
modeTag)
- } else {
- extra = append(extra, l[1:])
- }
- }
- }
- }
-
- return FrontMatter{
- Title: title,
- Overview: overview,
- Description: description,
- HomeLocation: homeLocation,
- Mode: checkMode(mode),
- Extra: extra,
- Location: newLocationDescriptor(loc, file),
- }
-}
-
-func checkMode(single string) Mode {
- switch Mode(single) {
- case ModeUnset, ModeFile, ModePackage, ModeNone:
- return Mode(single)
- default:
- fmt.Fprintf(os.Stderr, "unknown mode: %v\n", single)
- return ModeUnset
- }
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/locationDescriptor.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/locationDescriptor.go
deleted file mode 100644
index 8c93bc8e..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/locationDescriptor.go
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
-)
-
-type LocationDescriptor struct {
- *descriptor.SourceCodeInfo_Location
- File *FileDescriptor
-}
-
-func newLocationDescriptor(desc *descriptor.SourceCodeInfo_Location, file
*FileDescriptor) LocationDescriptor {
- return LocationDescriptor{
- SourceCodeInfo_Location: desc,
- File: file,
- }
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/messageDescriptor.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/messageDescriptor.go
deleted file mode 100644
index 9232b798..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/messageDescriptor.go
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
-)
-
-type MessageDescriptor struct {
- baseDesc
- *descriptor.DescriptorProto
- Parent *MessageDescriptor // The containing message, if any
- Messages []*MessageDescriptor // Inner messages, if any
- Enums []*EnumDescriptor // Inner enums, if any
- Fields []*FieldDescriptor // Fields, if any
-}
-
-type FieldDescriptor struct {
- baseDesc
- *descriptor.FieldDescriptorProto
- FieldType CoreDesc // Type of data held by this field
-}
-
-func newMessageDescriptor(desc *descriptor.DescriptorProto, parent
*MessageDescriptor, file *FileDescriptor, path pathVector) *MessageDescriptor {
- var qualifiedName []string
- if parent == nil {
- qualifiedName = []string{desc.GetName()}
- } else {
- qualifiedName = make([]string, len(parent.QualifiedName()),
len(parent.QualifiedName())+1)
- copy(qualifiedName, parent.QualifiedName())
- qualifiedName = append(qualifiedName, desc.GetName())
- }
-
- m := &MessageDescriptor{
- DescriptorProto: desc,
- Parent: parent,
- baseDesc: newBaseDesc(file, path, qualifiedName),
- }
-
- for i, f := range desc.Field {
- nameCopy := make([]string, len(qualifiedName),
len(qualifiedName)+1)
- copy(nameCopy, qualifiedName)
- nameCopy = append(nameCopy, f.GetName())
-
- fd := &FieldDescriptor{
- FieldDescriptorProto: f,
- baseDesc: newBaseDesc(file,
path.append(messageFieldPath, i), nameCopy),
- }
-
- m.Fields = append(m.Fields, fd)
- }
-
- for i, msg := range desc.NestedType {
- m.Messages = append(m.Messages, newMessageDescriptor(msg, m,
file, path.append(messageMessagePath, i)))
- }
-
- for i, e := range desc.EnumType {
- m.Enums = append(m.Enums, newEnumDescriptor(e, m, file,
path.append(messageEnumPath, i)))
- }
-
- return m
-}
-
-func (f *FieldDescriptor) IsRepeated() bool {
- return f.Label != nil && *f.Label ==
descriptor.FieldDescriptorProto_LABEL_REPEATED
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/model.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/model.go
deleted file mode 100644
index b6516a31..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/model.go
+++ /dev/null
@@ -1,180 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "strings"
-
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
- plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
-)
-
-// model represents a resolved in-memory version of all the input protos
-type Model struct {
- AllFilesByName map[string]*FileDescriptor
- AllDescByName map[string]CoreDesc
- Packages []*PackageDescriptor
-}
-
-func NewModel(request *plugin.CodeGeneratorRequest, perFile bool) *Model {
- m := &Model{
- AllFilesByName: make(map[string]*FileDescriptor,
len(request.ProtoFile)),
- }
-
- // organize files by package
- filesByPackage := map[string][]*descriptor.FileDescriptorProto{}
- for _, pf := range request.ProtoFile {
- pkg := packageName(pf)
- slice := filesByPackage[pkg]
- filesByPackage[pkg] = append(slice, pf)
- }
-
- // create all the package descriptors
- var allFiles []*FileDescriptor
- for pkg, files := range filesByPackage {
- p := newPackageDescriptor(pkg, files, perFile)
- m.Packages = append(m.Packages, p)
-
- for _, f := range p.Files {
- allFiles = append(allFiles, f)
- m.AllFilesByName[f.GetName()] = f
- }
- }
-
- // prepare a map of name to descriptor
- m.AllDescByName = createDescMap(allFiles)
-
- // resolve all type references to nice easily used pointers
- for _, f := range allFiles {
- resolveFieldTypes(f.Messages, m.AllDescByName)
- resolveMethodTypes(f.Services, m.AllDescByName)
- resolveDependencies(f, m.AllFilesByName)
- }
-
- return m
-}
-
-func packageName(f *descriptor.FileDescriptorProto) string {
- // Does the file have a package clause?
- if pkg := f.GetPackage(); pkg != "" {
- return pkg
- }
-
- // use the last path element of the name, with the last dotted suffix
removed.
-
- // First, find the last element
- name := f.GetName()
- if i := strings.LastIndex(name, "/"); i >= 0 {
- name = name[i+1:]
- }
-
- // Now drop the suffix
- if i := strings.LastIndex(name, "."); i >= 0 {
- name = name[0:i]
- }
-
- return name
-}
-
-// createDescMap builds a map from qualified names to descriptors.
-// The key names for the map come from the input data, which puts a period at
the beginning.
-func createDescMap(files []*FileDescriptor) map[string]CoreDesc {
- descMap := make(map[string]CoreDesc)
- for _, f := range files {
- // The names in this loop are defined by the proto world, not
us, so the
- // package name may be empty. If so, the dotted package name
of X will
- // be ".X"; otherwise it will be ".pkg.X".
- dottedPkg := "." + f.GetPackage()
- if dottedPkg != "." {
- dottedPkg += "."
- }
-
- for _, svc := range f.Services {
- descMap[dottedPkg+DottedName(svc)] = svc
- }
-
- recordEnums(f.Enums, descMap, dottedPkg)
- recordMessages(f.Messages, descMap, dottedPkg)
- recordServices(f.Services, descMap, dottedPkg)
- resolveFieldTypes(f.Messages, descMap)
- }
-
- return descMap
-}
-
-func recordMessages(messages []*MessageDescriptor, descMap
map[string]CoreDesc, dottedPkg string) {
- for _, msg := range messages {
- descMap[dottedPkg+DottedName(msg)] = msg
-
- recordMessages(msg.Messages, descMap, dottedPkg)
- recordEnums(msg.Enums, descMap, dottedPkg)
-
- for _, f := range msg.Fields {
- descMap[dottedPkg+DottedName(f)] = f
- }
- }
-}
-
-func recordEnums(enums []*EnumDescriptor, descMap map[string]CoreDesc,
dottedPkg string) {
- for _, e := range enums {
- descMap[dottedPkg+DottedName(e)] = e
-
- for _, v := range e.Values {
- descMap[dottedPkg+DottedName(v)] = v
- }
- }
-}
-
-func recordServices(services []*ServiceDescriptor, descMap
map[string]CoreDesc, dottedPkg string) {
- for _, s := range services {
- descMap[dottedPkg+DottedName(s)] = s
-
- for _, m := range s.Methods {
- descMap[dottedPkg+DottedName(m)] = m
- }
- }
-}
-
-func resolveFieldTypes(messages []*MessageDescriptor, descMap
map[string]CoreDesc) {
- for _, msg := range messages {
- for _, field := range msg.Fields {
- field.FieldType = descMap[field.GetTypeName()]
- }
- resolveFieldTypes(msg.Messages, descMap)
- }
-}
-
-func resolveMethodTypes(services []*ServiceDescriptor, descMap
map[string]CoreDesc) {
- for _, svc := range services {
- for _, method := range svc.Methods {
- method.Input =
descMap[method.GetInputType()].(*MessageDescriptor)
- method.Output =
descMap[method.GetOutputType()].(*MessageDescriptor)
- }
- }
-}
-
-func resolveDependencies(file *FileDescriptor, filesByName
map[string]*FileDescriptor) {
- for _, desc := range file.Dependency {
- dep := filesByName[desc]
- file.Dependencies = append(file.Dependencies, dep)
- }
-}
-
-// DottedName returns a dotted representation of the coreDesc's name
-func DottedName(o CoreDesc) string {
- return strings.Join(o.QualifiedName(), ".")
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/packageDescriptor.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/packageDescriptor.go
deleted file mode 100644
index f0d8326e..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/packageDescriptor.go
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "fmt"
- "os"
- "sort"
-
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
-)
-
-// PackageDescriptor describes a package, which is a composition of proto
files.
-type PackageDescriptor struct {
- baseDesc
- Files []*FileDescriptor
- Name string
-}
-
-func newPackageDescriptor(name string, desc []*descriptor.FileDescriptorProto,
perFile bool) *PackageDescriptor {
- p := &PackageDescriptor{
- Name: name,
- }
-
- for _, fd := range desc {
- f := newFileDescriptor(fd, p)
- p.Files = append(p.Files, f)
-
- // The package's file is one that documents the package
statement.
- // The first file to do this "wins".
- loc := f.find(newPathVector(packagePath))
- if loc != nil {
- if p.loc == nil {
- if loc.GetLeadingComments() != "" ||
loc.GetTrailingComments() != "" {
- p.loc = loc
- p.file = f
- // Inherit only f's frontMatter, don't
get title from one file
- }
- } else if !perFile {
- leading := loc.GetLeadingComments()
- trailing := loc.GetTrailingComments()
- if leading != "" || trailing != "" {
- _, _ = fmt.Fprintf(os.Stderr, "WARNING:
package %v has a conflicting package comment in file %v.\n",
- name, f.GetName())
- _, _ = fmt.Fprintf(os.Stderr,
"Previous:\n%v\n%v\nCurrent:\n%v\n%v\n", p.loc.GetLeadingComments(),
p.loc.GetTrailingComments(), leading, trailing)
- }
- }
- }
- }
-
- // Make the documenting file first. This ensures its messages show up
first on the output
- // If we need more granularity with explicitly multiple file ordering,
we can add some sort of annotation,
- // but or now this is sufficient.
- sort.SliceStable(p.Files, func(i, j int) bool {
- return p.Files[i] == p.file
- })
-
- return p
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/pathVector.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/pathVector.go
deleted file mode 100644
index ce0b290f..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/pathVector.go
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "strconv"
-)
-
-// The SourceCodeInfo messages describes the location of elements of a parsed
-// .proto currentFile by way of a "path", which is a sequence of integers that
-// describe the route from a FileDescriptorProto to the relevant submessage.
-// The path alternates between a field number of a repeated field, and an index
-// into that repeated field. The constants below define the field numbers that
-// are used.
-//
-// See descriptor.proto for more information about this.
-const (
- // tag numbers in FileDescriptorProto
- packagePath = 2 // package
- messagePath = 4 // message_type
- enumPath = 5 // enum_type
- servicePath = 6 // service
-
- // tag numbers in DescriptorProto
- messageFieldPath = 2 // field
- messageMessagePath = 3 // nested_type
- messageEnumPath = 4 // enum_type
-
- // tag numbers in EnumDescriptorProto
- enumValuePath = 2 // value
-
- // tag numbers in ServiceDescriptorProto
- serviceMethodPath = 2 // method
-)
-
-// A vector of comma-separated integers which identify a particular entry in a
-// given's file location information
-type pathVector string
-
-func newPathVector(v int) pathVector {
- return pathVector(strconv.Itoa(v))
-}
-
-func (pv pathVector) append(v ...int) pathVector {
- result := pv
- for _, val := range v {
- result += pathVector("," + strconv.Itoa(val))
- }
- return result
-}
diff --git a/tools/cmd/protoc-gen-crd/pkg/protomodel/serviceDescriptor.go
b/tools/cmd/protoc-gen-crd/pkg/protomodel/serviceDescriptor.go
deleted file mode 100644
index 242f22c3..00000000
--- a/tools/cmd/protoc-gen-crd/pkg/protomodel/serviceDescriptor.go
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package protomodel
-
-import (
- "github.com/golang/protobuf/protoc-gen-go/descriptor"
-)
-
-type ServiceDescriptor struct {
- baseDesc
- *descriptor.ServiceDescriptorProto
- Methods []*MethodDescriptor // Methods, if any
-}
-
-type MethodDescriptor struct {
- baseDesc
- *descriptor.MethodDescriptorProto
- Input *MessageDescriptor
- Output *MessageDescriptor
-}
-
-func newServiceDescriptor(desc *descriptor.ServiceDescriptorProto, file
*FileDescriptor, path pathVector) *ServiceDescriptor {
- qualifiedName := []string{desc.GetName()}
-
- s := &ServiceDescriptor{
- ServiceDescriptorProto: desc,
- baseDesc: newBaseDesc(file, path, qualifiedName),
- }
-
- for i, m := range desc.Method {
- nameCopy := make([]string, len(qualifiedName),
len(qualifiedName)+1)
- copy(nameCopy, qualifiedName)
- nameCopy = append(nameCopy, m.GetName())
-
- md := &MethodDescriptor{
- MethodDescriptorProto: m,
- baseDesc: newBaseDesc(file,
path.append(serviceMethodPath, i), nameCopy),
- }
- s.Methods = append(s.Methods, md)
- }
-
- return s
-}
diff --git a/tools/scripts/run.sh b/tools/scripts/run.sh
deleted file mode 100755
index e6c6d9ab..00000000
--- a/tools/scripts/run.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-WD=$(dirname "$0")
-WD=$(cd "$WD"; pwd)
-
-export FOR_BUILD_CONTAINER=1
-# shellcheck disable=SC1090,SC1091
-source "${WD}/setup_env.sh"
-
-
-MOUNT_SOURCE="${MOUNT_SOURCE:-${PWD}}"
-MOUNT_DEST="${MOUNT_DEST:-/work}"
-
-read -ra DOCKER_RUN_OPTIONS <<< "${DOCKER_RUN_OPTIONS:-}"
-
-[[ -t 0 ]] && DOCKER_RUN_OPTIONS+=("-it")
-[[ ${UID} -ne 0 ]] && DOCKER_RUN_OPTIONS+=(-u "${UID}:${DOCKER_GID}")
-
-# $CONTAINER_OPTIONS becomes an empty arg when quoted, so SC2086 is disabled
for the
-# following command only
-# shellcheck disable=SC2086
-"${CONTAINER_CLI}" run \
- --rm \
- "${DOCKER_RUN_OPTIONS[@]}" \
- --init \
- --sig-proxy=true \
- --cap-add=SYS_ADMIN \
- ${DOCKER_SOCKET_MOUNT:--v /var/run/docker.sock:/var/run/docker.sock} \
- -e DOCKER_HOST=${DOCKER_SOCKET_HOST:-unix:///var/run/docker.sock} \
- $CONTAINER_OPTIONS \
- --env-file <(env | grep -v "${ENV_BLOCKLIST:-^$}") \
- -e IN_BUILD_CONTAINER=1 \
- -e TZ="${TIMEZONE:-$TZ}" \
- --mount "type=bind,source=${MOUNT_SOURCE},destination=/work" \
- --mount "type=volume,source=go,destination=/go" \
- --mount "type=volume,source=gocache,destination=/gocache" \
- --mount "type=volume,source=cache,destination=/home/.cache" \
- --mount "type=volume,source=crates,destination=/home/.cargo/registry" \
- --mount "type=volume,source=git-crates,destination=/home/.cargo/git" \
- ${CONDITIONAL_HOST_MOUNTS} \
- -w "${MOUNT_DEST}" "${IMG}" "$@"
diff --git a/tools/scripts/setup_env.sh b/tools/scripts/setup_env.sh
deleted file mode 100755
index 6b571534..00000000
--- a/tools/scripts/setup_env.sh
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env bash
-# shellcheck disable=SC2034
-
-set -e
-
-SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
-REPO_ROOT="$(dirname "$(dirname "${SCRIPT_DIR}")")"
-
-LOCAL_ARCH=$(uname -m)
-
-if [[ ${TARGET_ARCH} ]]; then
- :
-elif [[ ${LOCAL_ARCH} == x86_64 ]]; then
- TARGET_ARCH=amd64
-elif [[ ${LOCAL_ARCH} == armv8* ]]; then
- TARGET_ARCH=arm64
-elif [[ ${LOCAL_ARCH} == arm64* ]]; then
- TARGET_ARCH=arm64
-elif [[ ${LOCAL_ARCH} == aarch64* ]]; then
- TARGET_ARCH=arm64
-else
- echo "This system's architecture, ${LOCAL_ARCH}, isn't supported"
- exit 1
-fi
-
-LOCAL_OS=$(uname)
-
-if [[ ${TARGET_OS} ]]; then
- :
-elif [[ $LOCAL_OS == Linux ]]; then
- TARGET_OS=linux
- readlink_flags="-f"
-elif [[ $LOCAL_OS == Darwin ]]; then
- TARGET_OS=darwin
- readlink_flags=""
-else
- echo "This system's OS, $LOCAL_OS, isn't supported"
- exit 1
-fi
-
-TIMEZONE=$(readlink "$readlink_flags" /etc/localtime | sed -e
's/^.*zoneinfo\///')
-
-ENV_BLOCKLIST="${ENV_BLOCKLIST:-^_\|^PATH=\|^GOPATH=\|^GOROOT=\|^SHELL=\|^EDITOR=\|^TMUX=\|^USER=\|^HOME=\|^PWD=\|^TERM=\|^RUBY_\|^GEM_\|^rvm_\|^SSH=\|^TMPDIR=\|^CC=\|^CXX=\|^MAKEFILE_LIST=}"
-
-# Build image to use
-TOOLS_REGISTRY_PROVIDER=${TOOLS_REGISTRY_PROVIDER:-docker.io}
-PROJECT_ID=${PROJECT_ID:-mfordjody}
-if [[ "${IMAGE_VERSION:-}" == "" ]]; then
- IMAGE_VERSION=master
-fi
-if [[ "${IMAGE_NAME:-}" == "" ]]; then
- IMAGE_NAME=build-tools
-fi
-
-CONTAINER_CLI="${CONTAINER_CLI:-docker}"
-
-# Try to use the latest cached image we have. Use at your own risk, may have
incompatibly-old versions
-if [[ "${LATEST_CACHED_IMAGE:-}" != "" ]]; then
- prefix="$(<<<"$IMAGE_VERSION" cut -d- -f1)"
- query="${TOOLS_REGISTRY_PROVIDER}/${PROJECT_ID}/${IMAGE_NAME}:${prefix}-*"
- latest="$("${CONTAINER_CLI}" images --filter=reference="${query}" --format
"{{.CreatedAt|json}}~{{.Repository}}:{{.Tag}}~{{.CreatedSince}}" | sort -n -r |
head -n1)"
- IMG="$(<<<"$latest" cut -d~ -f2)"
- if [[ "${IMG}" == "" ]]; then
- echo "Attempted to use LATEST_CACHED_IMAGE, but found no images matching
${query}" >&2
- exit 1
- fi
- echo "Using cached image $IMG, created $(<<<"$latest" cut -d~ -f3)" >&2
-fi
-
-IMG="${IMG:-${TOOLS_REGISTRY_PROVIDER}/${PROJECT_ID}/${IMAGE_NAME}:${IMAGE_VERSION}}"
-
-TARGET_OUT="${TARGET_OUT:-$(pwd)/out/${TARGET_OS}_${TARGET_ARCH}}"
-TARGET_OUT_LINUX="${TARGET_OUT_LINUX:-$(pwd)/out/linux_${TARGET_ARCH}}"
-
-CONTAINER_TARGET_OUT="${CONTAINER_TARGET_OUT:-/work/out/${TARGET_OS}_${TARGET_ARCH}}"
-CONTAINER_TARGET_OUT_LINUX="${CONTAINER_TARGET_OUT_LINUX:-/work/out/linux_${TARGET_ARCH}}"
-
-BUILD_WITH_CONTAINER=0
-
-# LOCAL_OUT should point to architecture where we are currently running versus
the desired.
-# This is used when we need to run a build artifact during tests or later as
part of another
-# target.
-if [[ "${FOR_BUILD_CONTAINER:-0}" -eq "1" ]]; then
- # Override variables with container specific
- TARGET_OUT=${CONTAINER_TARGET_OUT}
- TARGET_OUT_LINUX=${CONTAINER_TARGET_OUT_LINUX}
- REPO_ROOT=/work
- LOCAL_OUT="${TARGET_OUT_LINUX}"
-else
- LOCAL_OUT="${TARGET_OUT}"
-fi
-
-go_os_arch=${LOCAL_OUT##*/}
-# Golang OS/Arch format
-LOCAL_GO_OS=${go_os_arch%_*}
-LOCAL_GO_ARCH=${go_os_arch##*_}
-
-VARS=(
- CONTAINER_TARGET_OUT
- CONTAINER_TARGET_OUT_LINUX
- TARGET_OUT
- TARGET_OUT_LINUX
- LOCAL_GO_OS
- LOCAL_GO_ARCH
- LOCAL_OUT
- LOCAL_OS
- TARGET_OS
- LOCAL_ARCH
- TARGET_ARCH
- TIMEZONE
- CONTAINER_CLI
- IMG
- IMAGE_NAME
- IMAGE_VERSION
- REPO_ROOT
- BUILD_WITH_CONTAINER
-)
-
-# For non container build, we need to write env to file
-if [[ "${1}" == "envfile" ]]; then
- # ! does a variable-variable https://stackoverflow.com/a/10757531/374797
- for var in "${VARS[@]}"; do
- echo "${var}"="${!var}"
- done
-else
- for var in "${VARS[@]}"; do
- # shellcheck disable=SC2163
- export "${var}"
- done
-fi
diff --git a/tools/scripts/update_crds.sh b/tools/scripts/update_crds.sh
deleted file mode 100755
index 19430cb2..00000000
--- a/tools/scripts/update_crds.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-rm -f "../../manifests/charts/base/files/crd-all.gen.yaml"
-cp "../../api/kubernetes/customresourcedefinitions.gen.yaml"
"../../manifests/charts/base/files/crd-all.gen.yaml"
\ No newline at end of file