From 2943c37e1e1106175e3f86ceaea3d229b67deddf Mon Sep 17 00:00:00 2001 From: "red-hat-konflux-kflux-prd-rh02[bot]" <190377777+red-hat-konflux-kflux-prd-rh02[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 16:19:20 +0000 Subject: [PATCH] chore(deps): update module k8s.io/gengo/v2 to v2.0.0-20250922181213-ec3ebc5fd46b Signed-off-by: red-hat-konflux-kflux-prd-rh02 <190377777+red-hat-konflux-kflux-prd-rh02[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 +- vendor/k8s.io/gengo/v2/Makefile | 2 +- vendor/k8s.io/gengo/v2/README.md | 2 +- vendor/k8s.io/gengo/v2/codetags/extractor.go | 85 ++++ vendor/k8s.io/gengo/v2/codetags/parser.go | 407 ++++++++++++++++++ vendor/k8s.io/gengo/v2/codetags/scanner.go | 228 ++++++++++ vendor/k8s.io/gengo/v2/codetags/types.go | 169 ++++++++ vendor/k8s.io/gengo/v2/comments.go | 121 +++++- vendor/k8s.io/gengo/v2/generator/execute.go | 39 +- .../gengo/v2/generator/import_tracker.go | 4 +- .../gengo/v2/generator/snippet_writer.go | 18 + vendor/k8s.io/gengo/v2/namer/namer.go | 15 +- vendor/k8s.io/gengo/v2/parser/parse.go | 135 +++++- vendor/k8s.io/gengo/v2/parser/parse_122.go | 5 + .../k8s.io/gengo/v2/parser/parse_pre_122.go | 4 + vendor/k8s.io/gengo/v2/types/types.go | 28 +- vendor/modules.txt | 5 +- 18 files changed, 1248 insertions(+), 25 deletions(-) create mode 100644 vendor/k8s.io/gengo/v2/codetags/extractor.go create mode 100644 vendor/k8s.io/gengo/v2/codetags/parser.go create mode 100644 vendor/k8s.io/gengo/v2/codetags/scanner.go create mode 100644 vendor/k8s.io/gengo/v2/codetags/types.go diff --git a/go.mod b/go.mod index 2399533cb..ff04a4816 100644 --- a/go.mod +++ b/go.mod @@ -112,7 +112,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.32.1 // indirect - k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 // indirect + k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect k8s.io/klog/v2 v2.130.1 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect diff --git a/go.sum b/go.sum index f2395c3e2..15e7bb7d2 100644 --- a/go.sum +++ b/go.sum @@ -1673,8 +1673,8 @@ k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo/v2 v2.0.0-20240826214909-a7b603a56eb7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= -k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4= -k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= +k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ= +k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= diff --git a/vendor/k8s.io/gengo/v2/Makefile b/vendor/k8s.io/gengo/v2/Makefile index 8d0fbdaa8..5cb81a2fd 100644 --- a/vendor/k8s.io/gengo/v2/Makefile +++ b/vendor/k8s.io/gengo/v2/Makefile @@ -11,4 +11,4 @@ test: verify: GODEBUG=gotypesalias=0 ./hack/verify-examples.sh GODEBUG=gotypesalias=1 ./hack/verify-examples.sh - ./hack/verify-go-directive.sh 1.20 + ./hack/verify-go-directive.sh 1.23 diff --git a/vendor/k8s.io/gengo/v2/README.md b/vendor/k8s.io/gengo/v2/README.md index 79d1070d1..e1dff4b4b 100644 --- a/vendor/k8s.io/gengo/v2/README.md +++ b/vendor/k8s.io/gengo/v2/README.md @@ -50,4 +50,4 @@ The `tracer` example in this repo can be used to examine all of the hooks. ## Contributing -Please see [CONTRIBUTING.md](CONTRIBUTING.md) for instructions on how to contribute. +Please see [CONTRIBUTING.md](../CONTRIBUTING.md) for instructions on how to contribute. diff --git a/vendor/k8s.io/gengo/v2/codetags/extractor.go b/vendor/k8s.io/gengo/v2/codetags/extractor.go new file mode 100644 index 000000000..5e58b0083 --- /dev/null +++ b/vendor/k8s.io/gengo/v2/codetags/extractor.go @@ -0,0 +1,85 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed 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 codetags + +import ( + "strings" + "unicode/utf8" +) + +// Extract identifies and collects lines containing special metadata tags. +// It processes only lines that begin with the prefix. +// +// The portion of a line immediately following the prefix is treated as +// a potential tag name. To be considered valid, this tag name must +// match the regular expression `[a-zA-Z_][a-zA-Z0-9_.-:]*`. +// +// Extract returns a map where each key is a valid tag name found in +// lines that begin with the prefix. +// The value for each key is a slice of strings. Each string in this slice +// represents the contents of an original line after the prefix has been removed. +// +// Example: When called with prefix "+k8s:", lines: +// +// Comment line without marker +// +k8s:noArgs # comment +// +withValue=value1 +// +withValue=value2 +// +k8s:withArg(arg1)=value1 +// +k8s:withArg(arg2)=value2 # comment +// +k8s:withNamedArgs(arg1=value1, arg2=value2)=value +// +// Then this function will return: +// +// map[string][]string{ +// "noArgs": {"noArgs # comment"}, +// "withArg": {"withArg(arg1)=value1", "withArg(arg2)=value2 # comment"}, +// "withNamedArgs": {"withNamedArgs(arg1=value1, arg2=value2)=value"}, +// } +func Extract(prefix string, lines []string) map[string][]string { + out := map[string][]string{} + for _, line := range lines { + line = strings.TrimLeft(line, " \t") + if !strings.HasPrefix(line, prefix) { + continue + } + line = line[len(prefix):] + + // Find the end of the presumed tag name. + nameEnd := findNameEnd(line) + name := line[:nameEnd] + out[name] = append(out[name], line) + } + return out +} + +// findNameEnd matches a tag in the same way as the parser. +func findNameEnd(s string) int { + if len(s) == 0 { + return 0 + } + if r, _ := utf8.DecodeRuneInString(s); !isIdentBegin(r) { + return 0 + } + idx := strings.IndexFunc(s, func(r rune) bool { + return !(isTagNameInterior(r)) + }) + if idx == -1 { + return len(s) + } + return idx +} diff --git a/vendor/k8s.io/gengo/v2/codetags/parser.go b/vendor/k8s.io/gengo/v2/codetags/parser.go new file mode 100644 index 000000000..8ff49b039 --- /dev/null +++ b/vendor/k8s.io/gengo/v2/codetags/parser.go @@ -0,0 +1,407 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed 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 codetags + +import ( + "fmt" + "strings" + "unicode" +) + +// Parse parses a tag string into a Tag, or returns an error if the tag +// string fails to parse. +// +// ParseOption may be provided to modify the behavior of the parser. The below +// describes the default behavior. +// +// A tag consists of a name, optional arguments, and an optional scalar value or +// tag value. For example, +// +// "name" +// "name=50" +// "name("featureX")=50" +// "name(limit: 10, path: "/xyz")=text value" +// "name(limit: 10, path: "/xyz")=+anotherTag(size: 100)" +// +// Arguments are optional and may be either: +// - A single positional argument. +// - One or more named arguments (in the format `name: value`). +// - (Positional and named arguments cannot be mixed.) +// +// For example, +// +// "name()" +// "name(arg)" +// "name(namedArg1: argValue1)" +// "name(namedArg1: argValue1, namedArg2: argValue2)" +// +// Argument values may be strings, ints, booleans, or identifiers. +// +// For example, +// +// "name("double-quoted")" +// "name(`backtick-quoted`)" +// "name(100)" +// "name(true)" +// "name(arg1: identifier)" +// "name(arg1:`string value`)" +// "name(arg1: 100)" +// "name(arg1: true)" +// +// Note: When processing Go source code comments, the Extract function is +// typically used first to find and isolate tag strings matching a specific +// prefix. Those extracted strings can then be parsed using this function. +// +// The value part of the tag is optional and follows an equals sign "=". If a +// value is present, it must be a string, int, boolean, identifier, or tag. +// +// For example, +// +// "name" # no value +// "name=identifier" +// "name="double-quoted value"" +// "name=`backtick-quoted value`" +// "name(100)" +// "name(true)" +// "name=+anotherTag" +// "name=+anotherTag(size: 100)" +// +// Trailing comments are ignored unless the RawValues option is enabled, in which +// case they are treated as part of the value. +// +// For example, +// +// "key=value # This comment is ignored" +// +// Formal Grammar: +// +// ::= [ "(" [ ] ")" ] [ ( "=" | "=+" ) ] +// ::= | +// ::= [ "," ]* +// ::= ":" +// ::= | | | +// +// ::= [a-zA-Z_][a-zA-Z0-9_-.:]* +// ::= [a-zA-Z_][a-zA-Z0-9_-.]* +// ::= /* Go-style double-quoted or backtick-quoted strings, +// ... with standard Go escape sequences for double-quoted strings. */ +// ::= /* Standard Go integer literals (decimal, 0x hex, 0o octal, 0b binary), +// ... with an optional +/- prefix. */ +// ::= "true" | "false" +func Parse(tag string, options ...ParseOption) (Tag, error) { + opts := parseOpts{} + for _, o := range options { + o(&opts) + } + + tag = strings.TrimSpace(tag) + return parseTag(tag, opts) +} + +// ParseAll calls Parse on each tag in the input slice. +func ParseAll(tags []string, options ...ParseOption) ([]Tag, error) { + var out []Tag + for _, tag := range tags { + parsed, err := Parse(tag, options...) + if err != nil { + return nil, err + } + out = append(out, parsed) + } + return out, nil +} + +type parseOpts struct { + rawValues bool +} + +// ParseOption provides a parser option. +type ParseOption func(*parseOpts) + +// RawValues skips parsing of the value part of the tag. If enabled, the Value +// in the parse response will contain all text following the "=" sign, up to the last +// non-whitespace character, and ValueType will be set to ValueTypeRaw. +// Default: disabled +func RawValues(enabled bool) ParseOption { + return func(opts *parseOpts) { + opts.rawValues = enabled + } +} + +func parseTag(input string, opts parseOpts) (Tag, error) { + const ( + stTag = "stTag" + stMaybeArgs = "stMaybeArgs" + stArg = "stArg" + stArgEndOfToken = "stArgEndOfToken" + stMaybeValue = "stMaybeValue" + stValue = "stValue" + stMaybeComment = "stMaybeComment" + ) + var startTag, endTag *Tag // both ends of the chain when parsing chained tags + + // accumulators + var tagName string // current tag name + var value string // current value + var valueType ValueType // current value type + cur := Arg{} // current argument + var args []Arg // current arguments slice + + s := scanner{buf: []rune(input)} // scanner for parsing the tag string + var incomplete bool // tracks if a token is incomplete + + // These are defined outside the loop to make errors easier. + saveArg := func(v string, t ArgType) { + cur.Value = v + cur.Type = t + args = append(args, cur) + cur = Arg{} + } + saveInt := func(v string) { saveArg(v, ArgTypeInt) } + saveString := func(v string) { saveArg(v, ArgTypeString) } + saveBoolOrString := func(value string) { + if value == "true" || value == "false" { + saveArg(value, ArgTypeBool) + } else { + saveArg(value, ArgTypeString) + } + } + saveName := func(value string) { + cur.Name = value + } + saveTag := func() error { + usingNamedArgs := false + for i, arg := range args { + if (usingNamedArgs && arg.Name == "") || (!usingNamedArgs && arg.Name != "" && i > 0) { + return fmt.Errorf("can't mix named and positional arguments") + } + if arg.Name != "" { + usingNamedArgs = true + } + } + if !usingNamedArgs && len(args) > 1 { + return fmt.Errorf("multiple arguments must use 'name: value' syntax") + } + newTag := &Tag{Name: tagName, Args: args} + if startTag == nil { + startTag = newTag + endTag = newTag + } else { + endTag.ValueTag = newTag + endTag.ValueType = ValueTypeTag + endTag = newTag + } + args = nil // Reset to nil instead of empty slice + return nil + } + saveValue := func() { + endTag.Value = value + endTag.ValueType = valueType + } + var err error + st := stTag +parseLoop: + for r := s.peek(); r != EOF; r = s.peek() { + switch st { + case stTag: // Any leading whitespace is expected to be trimmed before parsing. + switch { + case isIdentBegin(r): + tagName, err = s.nextIdent(isTagNameInterior) + if err != nil { + return Tag{}, err + } + st = stMaybeArgs + default: + break parseLoop + } + case stMaybeArgs: + switch { + case r == '(': + s.next() // consume ( + incomplete = true + st = stArg + case r == '=': + s.next() // consume = + if opts.rawValues { + // only raw values support empty values following = + valueType = ValueTypeRaw + } else { + incomplete = true + } + st = stValue + default: + st = stMaybeComment + } + case stArg: + switch { + case r == ')': + s.next() // consume ) + incomplete = false + st = stMaybeValue + case r == '-' || r == '+' || unicode.IsDigit(r): + number, err := s.nextNumber() + if err != nil { + return Tag{}, err + } + saveInt(number) + st = stArgEndOfToken + case r == '"' || r == '`': + str, err := s.nextString() + if err != nil { + return Tag{}, err + } + saveString(str) + st = stArgEndOfToken + case isIdentBegin(r): + identifier, err := s.nextIdent(isIdentInterior) + if err != nil { + return Tag{}, err + } + r = s.peek() // reset r after nextIdent + + switch { + case r == ',' || r == ')': // positional arg + if r == ',' { + r = s.skipWhitespace() // allow whitespace after , + } + saveBoolOrString(identifier) + st = stArgEndOfToken + case r == ':': // named arg + s.next() // consume : + r = s.skipWhitespace() // allow whitespace after : + saveName(identifier) + st = stArg + default: + break parseLoop + } + default: + break parseLoop + } + case stArgEndOfToken: + switch { + case r == ',': + s.next() // consume , + r = s.skipWhitespace() // allow whitespace after , + st = stArg + case r == ')': + s.next() // consume ) + incomplete = false + st = stMaybeValue + default: + break parseLoop + } + case stMaybeValue: + switch { + case r == '=': + s.next() // consume = + if opts.rawValues { + // Empty values are allowed for raw. + // Since = might be the last char in the input, we need + // to record the valueType as raw immediately. + valueType = ValueTypeRaw + } + st = stValue + default: + st = stMaybeComment + } + case stValue: + switch { + case opts.rawValues: // When enabled, consume all remaining chars + incomplete = false + value = s.remainder() + break parseLoop + case r == '+' && isIdentBegin(s.peekN(1)): // tag value + incomplete = false + s.next() // consume + + if err := saveTag(); err != nil { + return Tag{}, err + } + st = stTag + case r == '-' || r == '+' || unicode.IsDigit(r): + incomplete = false + number, err := s.nextNumber() + valueType = ValueTypeInt + if err != nil { + return Tag{}, err + } + value = number + st = stMaybeComment + case r == '"' || r == '`': + incomplete = false + str, err := s.nextString() + if err != nil { + return Tag{}, err + } + value = str + valueType = ValueTypeString + st = stMaybeComment + case isIdentBegin(r): + incomplete = false + str, err := s.nextIdent(isIdentInterior) + if err != nil { + return Tag{}, err + } + value = str + if str == "true" || str == "false" { + valueType = ValueTypeBool + } else { + valueType = ValueTypeString + } + st = stMaybeComment + default: + break parseLoop + } + case stMaybeComment: + switch { + case s.nextIsTrailingComment(): + s.remainder() + default: + break parseLoop + } + default: + return Tag{}, fmt.Errorf("unexpected internal parser error: unknown state: %s at position %d", st, s.pos) + } + } + if s.peek() != EOF { + return Tag{}, fmt.Errorf("unexpected character %q at position %d", s.next(), s.pos) + } + if incomplete { + return Tag{}, fmt.Errorf("unexpected end of input") + } + if err := saveTag(); err != nil { + return Tag{}, err + } + if len(valueType) > 0 { + saveValue() + } + if startTag == nil { + return Tag{}, fmt.Errorf("unexpected internal parser error: no tags parsed") + } + return *startTag, nil +} + +func isIdentBegin(r rune) bool { + return unicode.IsLetter(r) || r == '_' +} + +func isIdentInterior(r rune) bool { + return unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '.' || r == '-' +} + +func isTagNameInterior(r rune) bool { + return isIdentInterior(r) || r == ':' +} diff --git a/vendor/k8s.io/gengo/v2/codetags/scanner.go b/vendor/k8s.io/gengo/v2/codetags/scanner.go new file mode 100644 index 000000000..5204e347f --- /dev/null +++ b/vendor/k8s.io/gengo/v2/codetags/scanner.go @@ -0,0 +1,228 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed 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 codetags + +import ( + "bytes" + "fmt" + "strconv" + "strings" + "unicode" +) + +type scanner struct { + buf []rune + pos int +} + +func (s *scanner) next() rune { + if s.pos >= len(s.buf) { + return EOF + } + r := s.buf[s.pos] + s.pos++ + return r +} + +func (s *scanner) peek() rune { + return s.peekN(0) +} + +func (s *scanner) peekN(n int) rune { + if s.pos+n >= len(s.buf) { + return EOF + } + return s.buf[s.pos+n] +} + +func (s *scanner) skipWhitespace() rune { + for r := s.peek(); unicode.IsSpace(r); r = s.peek() { + s.next() + } + return s.peek() +} + +func (s *scanner) remainder() string { + result := string(s.buf[s.pos:]) + s.pos = len(s.buf) + return result +} + +const ( + EOF = -1 +) + +func (s *scanner) nextIsTrailingComment() bool { + i := 0 + for ; unicode.IsSpace(s.peekN(i)); i++ { + } + return s.peekN(i) == '#' +} + +func (s *scanner) nextNumber() (string, error) { + const ( + stBegin = "stBegin" + stPrefix = "stPrefix" + stPosNeg = "stPosNeg" + stNumber = "stNumber" + ) + var buf bytes.Buffer + st := stBegin + +parseLoop: + for r := s.peek(); r != EOF; r = s.peek() { + switch st { + case stBegin: + switch { + case r == '0': + buf.WriteRune(s.next()) + st = stPrefix + case r == '+' || r == '-': + buf.WriteRune(s.next()) + st = stPosNeg + case unicode.IsDigit(r): + buf.WriteRune(s.next()) + st = stNumber + default: + break parseLoop + } + case stPosNeg: + switch { + case r == '0': + buf.WriteRune(s.next()) + st = stPrefix + case unicode.IsDigit(r): + buf.WriteRune(s.next()) + st = stNumber + default: + break parseLoop + } + case stPrefix: + switch { + case unicode.IsDigit(r): + buf.WriteRune(s.next()) + st = stNumber + case r == 'x' || r == 'o' || r == 'b': + buf.WriteRune(s.next()) + st = stNumber + default: + break parseLoop + } + case stNumber: + const hexits = "abcdefABCDEF" + switch { + case unicode.IsDigit(r) || strings.Contains(hexits, string(r)): + buf.WriteRune(s.next()) + default: + break parseLoop + } + default: + return "", fmt.Errorf("unexpected internal parser error: unknown state: %s at position %d", st, s.pos) + } + } + numStr := buf.String() + if _, err := strconv.ParseInt(numStr, 0, 64); err != nil { + return "", fmt.Errorf("invalid number %q at position %d", numStr, s.pos) + } + return numStr, nil +} + +func (s *scanner) nextString() (string, error) { + const ( + stBegin = "stBegin" + stQuotedString = "stQuotedString" + stEscape = "stEscape" + ) + var buf bytes.Buffer + var quote rune + var incomplete bool + st := stBegin + +parseLoop: + for r := s.peek(); r != EOF; r = s.peek() { + switch st { + case stBegin: + switch { + case r == '"' || r == '`': + incomplete = true + quote = s.next() // consume quote + st = stQuotedString + default: + return "", fmt.Errorf("expected string at position %d", s.pos) + } + case stQuotedString: + switch { + case r == '\\': + s.next() // consume escape + st = stEscape + case r == quote: + incomplete = false + s.next() + break parseLoop + default: + buf.WriteRune(s.next()) + } + case stEscape: + switch { + case r == quote || r == '\\': + buf.WriteRune(s.next()) + st = stQuotedString + default: + return "", fmt.Errorf("unhandled escaped character %q", r) + } + default: + return "", fmt.Errorf("unexpected internal parser error: unknown state: %s at position %d", st, s.pos) + } + } + if incomplete { + return "", fmt.Errorf("unterminated string at position %d", s.pos) + } + return buf.String(), nil +} + +func (s *scanner) nextIdent(isInteriorChar func(r rune) bool) (string, error) { + const ( + stBegin = "stBegin" + stInterior = "stInterior" + ) + var buf bytes.Buffer + st := stBegin + +parseLoop: + for r := s.peek(); r != EOF; r = s.peek() { + switch st { + case stBegin: + switch { + case isIdentBegin(r): + buf.WriteRune(s.next()) + st = stInterior + default: + return "", fmt.Errorf("expected identifier at position %d", s.pos) + } + case stInterior: + switch { + case isInteriorChar(r): + buf.WriteRune(s.next()) + default: + break parseLoop + } + default: + return "", fmt.Errorf("unexpected internal parser error: unknown state: %s at position %d", st, s.pos) + } + } + return buf.String(), nil +} diff --git a/vendor/k8s.io/gengo/v2/codetags/types.go b/vendor/k8s.io/gengo/v2/codetags/types.go new file mode 100644 index 000000000..d004f9bf2 --- /dev/null +++ b/vendor/k8s.io/gengo/v2/codetags/types.go @@ -0,0 +1,169 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed 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 codetags + +import ( + "strconv" + "strings" +) + +// Tag represents a single comment tag with typed args. +type Tag struct { + // Name is the name of the tag with no arguments. + Name string + + // Args is a list of optional arguments to the tag. + Args []Arg + + // Value is the string representation of the tag value. + // Provides the tag value when ValueType is ValueTypeString, ValueTypeBool, ValueTypeInt or ValueTypeRaw. + Value string + + // ValueTag is another tag parsed from the value of this tag. + // Provides the tag value when ValueType is ValueTypeTag. + ValueTag *Tag + + // ValueType is the type of the value. + ValueType ValueType +} + +// PositionalArg returns the positional argument. If there is no positional +// argument, it returns false. +func (t Tag) PositionalArg() (Arg, bool) { + if len(t.Args) == 0 || len(t.Args[0].Name) > 0 { + return Arg{}, false + } + return t.Args[0], true +} + +// NamedArg returns the named argument. If o named argument is found, it returns +// false. Always returns false for empty name; use PositionalArg instead. +func (t Tag) NamedArg(name string) (Arg, bool) { + if len(name) == 0 { + return Arg{}, false + } + for _, arg := range t.Args { + if arg.Name == name { + return arg, true + } + } + return Arg{}, false +} + +// String returns the canonical string representation of the tag. +// All strings are represented in double quotes. Spacing is normalized. +func (t Tag) String() string { + buf := strings.Builder{} + buf.WriteString(t.Name) + if len(t.Args) > 0 { + buf.WriteString("(") + for i, a := range t.Args { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(a.String()) + } + buf.WriteString(")") + } + if t.ValueType != ValueTypeNone { + if t.ValueType == ValueTypeTag { + buf.WriteString("=+") + buf.WriteString(t.ValueTag.String()) + } else { + buf.WriteString("=") + if t.ValueType == ValueTypeString { + buf.WriteString(strconv.Quote(t.Value)) + } else { + buf.WriteString(t.Value) + } + } + } + return buf.String() +} + +// Arg represents a argument. +type Arg struct { + // Name is the name of a named argument. This is zero-valued for positional arguments. + Name string + + // Value is the string value of an argument. It has been validated to match the Type. + // See the ArgType const godoc for further details on how to parse the value for the + // Type. + Value string + + // Type identifies the type of the argument. + Type ArgType +} + +func (a Arg) String() string { + buf := strings.Builder{} + if len(a.Name) > 0 { + buf.WriteString(a.Name) + buf.WriteString(": ") + } + if a.Type == ArgTypeString { + buf.WriteString(strconv.Quote(a.Value)) + } else { + buf.WriteString(a.Value) + } + return buf.String() +} + +// ArgType is an argument's type. +type ArgType string + +const ( + // ArgTypeString identifies string values. + ArgTypeString ArgType = "string" + + // ArgTypeInt identifies int values. Values of this type may be in decimal, + // octal, hex or binary string representations. Consider using strconv.ParseInt + // to parse, as it supports all these string representations. + ArgTypeInt ArgType = "int" + + // ArgTypeBool identifies bool values. Values of this type must either be the + // string "true" or "false". + ArgTypeBool ArgType = "bool" +) + +// ValueType is a tag's value type. +type ValueType string + +const ( + // ValueTypeNone indicates that the tag has no value. + ValueTypeNone ValueType = "" + + // ValueTypeString identifies string values. + ValueTypeString ValueType = "string" + + // ValueTypeInt identifies int values. Values of this type may be in decimal, + // octal, hex or binary string representations. Consider using strconv.ParseInt + // to parse, as it supports all these string representations. + ValueTypeInt ValueType = "int" + + // ValueTypeBool identifies bool values. Values of this type must either be the + // string "true" or "false". + ValueTypeBool ValueType = "bool" + + // ValueTypeTag identifies that the value is another tag. + ValueTypeTag ValueType = "tag" + + // ValueTypeRaw identifies that the value is raw, untyped content and contains + // all text from the tag declaration following the "=" sign, up to the last + // non-whitespace character. + ValueTypeRaw ValueType = "raw" +) diff --git a/vendor/k8s.io/gengo/v2/comments.go b/vendor/k8s.io/gengo/v2/comments.go index ba49c432b..fbc41bed5 100644 --- a/vendor/k8s.io/gengo/v2/comments.go +++ b/vendor/k8s.io/gengo/v2/comments.go @@ -17,8 +17,12 @@ limitations under the License. package gengo import ( + "bytes" "fmt" + "slices" "strings" + + "k8s.io/gengo/v2/codetags" ) // ExtractCommentTags parses comments for lines of the form: @@ -39,7 +43,9 @@ import ( // // Then this function will return: // -// map[string][]string{"foo":{"value1, "value2"}, "bar": {""}, "baz": {"qux"}} +// map[string][]string{"foo":{"value1, "value2"}, "bar": {""}, "baz": {`"qux"`}} +// +// Deprecated: Prefer codetags.Extract and codetags.Parse. func ExtractCommentTags(marker string, lines []string) map[string][]string { out := map[string][]string{} for _, line := range lines { @@ -50,7 +56,6 @@ func ExtractCommentTags(marker string, lines []string) map[string][]string { if !strings.HasPrefix(line, marker) { continue } - // TODO: we could support multiple values per key if we split on spaces kv := strings.SplitN(line[len(marker):], "=", 2) if len(kv) == 2 { out[kv[0]] = append(out[kv[0]], kv[1]) @@ -68,16 +73,122 @@ func ExtractCommentTags(marker string, lines []string) map[string][]string { // If the tag is not found, the default value is returned. Values are asserted // to be boolean ("true" or "false"), and any other value will cause an error // to be returned. If the key has multiple values, the first one will be used. +// +// This function is a wrapper around codetags.Extract and codetags.Parse, but only supports tags with +// a single position arg of type string, and a value of type bool. func ExtractSingleBoolCommentTag(marker string, key string, defaultVal bool, lines []string) (bool, error) { - values := ExtractCommentTags(marker, lines)[key] + tags, err := ExtractFunctionStyleCommentTags(marker, []string{key}, lines, ParseValues(true)) + if err != nil { + return false, err + } + values := tags[key] if values == nil { return defaultVal, nil } - if values[0] == "true" { + if values[0].Value == "true" { return true, nil } - if values[0] == "false" { + if values[0].Value == "false" { return false, nil } return false, fmt.Errorf("tag value for %q is not boolean: %q", key, values[0]) } + +// ExtractFunctionStyleCommentTags parses comments for special metadata tags. +// +// This function is a wrapper around codetags.Extract and codetags.Parse, but only supports tags with +// a single position arg of type string. +func ExtractFunctionStyleCommentTags(marker string, tagNames []string, lines []string, options ...TagOption) (map[string][]Tag, error) { + opts := tagOpts{} + for _, o := range options { + o(&opts) + } + + out := map[string][]Tag{} + + tags := codetags.Extract(marker, lines) + for tagName, tagLines := range tags { + if len(tagNames) > 0 && !slices.Contains(tagNames, tagName) { + continue + } + for _, line := range tagLines { + typedTag, err := codetags.Parse(line, codetags.RawValues(!opts.parseValues)) + if err != nil { + return nil, err + } + tag, err := toStringArgs(typedTag) + if err != nil { + return nil, err + } + out[tagName] = append(out[tagName], tag) + } + } + + return out, nil +} + +// TagOption provides an option for extracting tags. +type TagOption func(opts *tagOpts) + +// ParseValues enables parsing of tag values. When enabled, tag values must +// be valid quoted strings, ints, booleans, identifiers, or tags. Otherwise, a +// parse error will be returned. Also, when enabled, trailing comments are +// ignored. +// Default: disabled +func ParseValues(enabled bool) TagOption { + return func(opts *tagOpts) { + opts.parseValues = enabled + } +} + +type tagOpts struct { + parseValues bool +} + +func toStringArgs(tag codetags.Tag) (Tag, error) { + var stringArgs []string + if len(tag.Args) > 1 { + return Tag{}, fmt.Errorf("expected one argument, got: %v", tag.Args) + } + for _, arg := range tag.Args { + if len(arg.Name) > 0 { + return Tag{}, fmt.Errorf("unexpected named argument: %q", arg.Name) + } + if arg.Type != codetags.ArgTypeString { + return Tag{}, fmt.Errorf("unexpected argument type: %s", arg.Type) + } else { + stringArgs = append(stringArgs, arg.Value) + } + } + return Tag{ + Name: tag.Name, + Args: stringArgs, + Value: tag.Value, + }, nil +} + +// Tag represents a single comment tag. +type Tag struct { + // Name is the name of the tag with no arguments. + Name string + // Args is a list of optional arguments to the tag. + Args []string + // Value is the value of the tag. + Value string +} + +func (t Tag) String() string { + buf := bytes.Buffer{} + buf.WriteString(t.Name) + if len(t.Args) > 0 { + buf.WriteString("(") + for i, a := range t.Args { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(a) + } + buf.WriteString(")") + } + return buf.String() +} diff --git a/vendor/k8s.io/gengo/v2/generator/execute.go b/vendor/k8s.io/gengo/v2/generator/execute.go index a1e052f5c..964a70e91 100644 --- a/vendor/k8s.io/gengo/v2/generator/execute.go +++ b/vendor/k8s.io/gengo/v2/generator/execute.go @@ -22,6 +22,7 @@ import ( "fmt" "io" "os" + "os/exec" "path/filepath" "strings" @@ -114,19 +115,53 @@ func assembleGoFile(w io.Writer, f *File) { w.Write(f.Body.Bytes()) } +func formatCode(src []byte) ([]byte, error) { + // We call goimports because it formats imports better than gofmt, but also + // call gofmt because it has the "simplify" logic. If a gofmt binary is + // not found, we will skip it. + src, err := importsWrapper(src) + if err != nil { + return nil, err + } + return gofmtWrapper(src) +} + func importsWrapper(src []byte) ([]byte, error) { opt := imports.Options{ Comments: true, TabIndent: true, TabWidth: 8, - FormatOnly: true, // Disable the insertion and deletion of imports + FormatOnly: true, // Disable the insertion and deletion of imports (slow!) } return imports.Process("", src, &opt) } +func gofmtWrapper(src []byte) ([]byte, error) { + const gofmt = "gofmt" + + if _, err := exec.LookPath(gofmt); err != nil { + klog.Errorf("WARNING: skipping output simplification: %v", err) + return src, nil + } + + cmd := exec.Command(gofmt, "-s") + cmd.Stdin = bytes.NewReader(src) + stdout := &bytes.Buffer{} + cmd.Stdout = stdout + stderr := &bytes.Buffer{} + cmd.Stderr = stderr + if err := cmd.Run(); err != nil { + if stderr.Len() > 0 { + return nil, fmt.Errorf("%s failed: %v: %s", gofmt, err, strings.TrimSpace(stderr.String())) + } + return nil, fmt.Errorf("%s failed: %v", gofmt, err) + } + return stdout.Bytes(), nil +} + func NewGoFile() *DefaultFileType { return &DefaultFileType{ - Format: importsWrapper, + Format: formatCode, Assemble: assembleGoFile, } } diff --git a/vendor/k8s.io/gengo/v2/generator/import_tracker.go b/vendor/k8s.io/gengo/v2/generator/import_tracker.go index 22393e4d4..f4b0f7b5f 100644 --- a/vendor/k8s.io/gengo/v2/generator/import_tracker.go +++ b/vendor/k8s.io/gengo/v2/generator/import_tracker.go @@ -61,13 +61,13 @@ func goTrackerLocalName(tracker namer.ImportTracker, localPkg string, t types.Na path := t.Package // Using backslashes in package names causes gengo to produce Go code which - // will not compile with the gc compiler. See the comment on GoSeperator. + // will not compile with the gc compiler. See the comment on GoSeparator. if strings.ContainsRune(path, '\\') { klog.Warningf("Warning: backslash used in import path '%v', this is unsupported.\n", path) } localLeaf := filepath.Base(localPkg) - dirs := strings.Split(path, namer.GoSeperator) + dirs := strings.Split(path, namer.GoSeparator) for n := len(dirs) - 1; n >= 0; n-- { // follow kube convention of not having anything between directory names name := strings.Join(dirs[n:], "") diff --git a/vendor/k8s.io/gengo/v2/generator/snippet_writer.go b/vendor/k8s.io/gengo/v2/generator/snippet_writer.go index 550214e16..b0adcc28a 100644 --- a/vendor/k8s.io/gengo/v2/generator/snippet_writer.go +++ b/vendor/k8s.io/gengo/v2/generator/snippet_writer.go @@ -165,6 +165,24 @@ func (s *SnippetWriter) Dup(w io.Writer) *SnippetWriter { // Append adds the contents of the io.Reader to this SnippetWriter's buffer. func (s *SnippetWriter) Append(r io.Reader) error { + // The behavior of Do() is to ignore all future calls if there's an error, + // assuming the top-level caller will check Error(). This method is + // effectively a fancy Do(), so keep the same semantic. + if s.err != nil { + return nil + } _, err := io.Copy(s.w, r) return err } + +// Merge adds the contents of the io.Reader to this SnippetWriter's buffer and +// sets this SnippetWriter's error to the other's, if needed. +func (s *SnippetWriter) Merge(r io.Reader, other *SnippetWriter) error { + if s.err != nil { + return nil + } + if other.err != nil { + s.err = other.err + } + return s.Append(r) +} diff --git a/vendor/k8s.io/gengo/v2/namer/namer.go b/vendor/k8s.io/gengo/v2/namer/namer.go index 37877eb49..2202f8e70 100644 --- a/vendor/k8s.io/gengo/v2/namer/namer.go +++ b/vendor/k8s.io/gengo/v2/namer/namer.go @@ -26,14 +26,17 @@ import ( ) const ( - // GoSeperator is used to split go import paths. + // GoSeparator is used to split go import paths. // Forward slash is used instead of filepath.Seperator because it is the // only universally-accepted path delimiter and the only delimiter not // potentially forbidden by Go compilers. (In particular gc does not allow // the use of backslashes in import paths.) // See https://golang.org/ref/spec#Import_declarations. // See also https://github.com/kubernetes/gengo/issues/83#issuecomment-367040772. - GoSeperator = "/" + GoSeparator = "/" + // GoSeperator is a typo for GoSeparator. + // Deprecated: use GoSeparator instead. + GoSeperator = GoSeparator ) // Returns whether a name is a private Go name. @@ -200,7 +203,7 @@ var ( // filters out unwanted directory names and sanitizes remaining names. func (ns *NameStrategy) filterDirs(path string) []string { - allDirs := strings.Split(path, GoSeperator) + allDirs := strings.Split(path, GoSeparator) dirs := make([]string, 0, len(allDirs)) for _, p := range allDirs { if ns.IgnoreWords == nil || !ns.IgnoreWords[p] { @@ -370,7 +373,11 @@ func (r *rawNamer) Name(t *types.Type) string { // TODO: include function signature elems = append(elems, m.Name.Name) } - name = "interface{" + strings.Join(elems, "; ") + "}" + if len(elems) == 0 { + name = "any" + } else { + name = "interface{" + strings.Join(elems, "; ") + "}" + } case types.Func: // TODO: add to name test params := []string{} diff --git a/vendor/k8s.io/gengo/v2/parser/parse.go b/vendor/k8s.io/gengo/v2/parser/parse.go index d4de19e76..f3760983d 100644 --- a/vendor/k8s.io/gengo/v2/parser/parse.go +++ b/vendor/k8s.io/gengo/v2/parser/parse.go @@ -23,7 +23,10 @@ import ( "go/constant" "go/token" gotypes "go/types" + "maps" "path/filepath" + "reflect" + "slices" "sort" "strings" "time" @@ -382,11 +385,117 @@ func (p *Parser) NewUniverse() (types.Universe, error) { return u, nil } +// minimize returns a copy of lines with "irrelevant" lines removed. This +// includes blank lines and paragraphs starting with "Deprecated:". +func minimize(lines []string) []string { + out := make([]string, 0, len(lines)) + inDeprecated := false // paragraph tracking + prevWasBlank := false + for _, line := range lines { + if len(strings.TrimSpace(line)) == 0 { + prevWasBlank = true + inDeprecated = false + continue + } + if inDeprecated { + continue + } + if prevWasBlank && strings.HasPrefix(strings.TrimSpace(line), "Deprecated:") { + prevWasBlank = false + inDeprecated = true + continue + } + prevWasBlank = false + out = append(out, line) + } + return out +} + // addCommentsToType takes any accumulated comment lines prior to obj and // attaches them to the type t. func (p *Parser) addCommentsToType(obj gotypes.Object, t *types.Type) { - t.CommentLines = p.docComment(obj.Pos()) - t.SecondClosestCommentLines = p.priorDetachedComment(obj.Pos()) + if newLines, oldLines := p.docComment(obj.Pos()), t.CommentLines; len(newLines) > 0 { + switch { + case reflect.DeepEqual(oldLines, newLines): + // nothing needed + + case len(oldLines) == 0: + // no comments associated, or comments match exactly + t.CommentLines = newLines + + case isTypeAlias(obj.Type()): + // Ignore mismatched comments from obj because it's an alias. + // This can only be hit if gotypesalias is enabled. + if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) { + klog.Warningf( + "Mismatched comments on type %v.\n Using comments:\n%s\n Ignoring comments from type alias:\n%s\n", + t.GoType, + formatCommentBlock(oldLines), + formatCommentBlock(newLines), + ) + } + + case !isTypeAlias(obj.Type()): + // Overwrite existing comments with ones from obj because obj is not an alias. + // If gotypesalias is enabled, this should mean we found the "real" + // type, not an alias. If gotypesalias is disabled, we can end up + // overwriting the "real" comments with an alias's comments, but + // it is not clear if we can assume which one is the "real" one. + t.CommentLines = newLines + if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) { + klog.Warningf( + "Mismatched comments on type %v.\n Using comments:\n%s\n Ignoring comments from possible type alias:\n%s\n", + t.GoType, + formatCommentBlock(newLines), + formatCommentBlock(oldLines), + ) + } + } + } + + if newLines, oldLines := p.priorDetachedComment(obj.Pos()), t.SecondClosestCommentLines; len(newLines) > 0 { + switch { + case reflect.DeepEqual(oldLines, newLines): + // nothing needed + + case len(oldLines) == 0: + // no comments associated, or comments match exactly + t.SecondClosestCommentLines = newLines + + case isTypeAlias(obj.Type()): + // Ignore mismatched comments from obj because it's an alias. + // This can only be hit if gotypesalias is enabled. + if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) { + // ignore mismatched comments from obj because it's an alias + klog.Warningf( + "Mismatched secondClosestCommentLines on type %v.\n Using comments:\n%s\n Ignoring comments from type alias:\n%s\n", + t.GoType, + formatCommentBlock(oldLines), + formatCommentBlock(newLines), + ) + } + + case !isTypeAlias(obj.Type()): + // Overwrite existing comments with ones from obj because obj is not an alias. + // If gotypesalias is enabled, this should mean we found the "real" + // type, not an alias. If gotypesalias is disabled, we can end up + // overwriting the "real" comments with an alias's comments, but + // it is not clear if we can assume which one is the "real" one. + t.SecondClosestCommentLines = newLines + if !reflect.DeepEqual(minimize(oldLines), minimize(newLines)) { + klog.Warningf( + "Mismatched secondClosestCommentLines on type %v.\n Using comments:\n%s\n Ignoring comments from possible type alias:\n%s\n", + t.GoType, + formatCommentBlock(newLines), + formatCommentBlock(oldLines), + ) + } + } + } +} + +func formatCommentBlock(lines []string) string { + return " ```\n " + strings.Join(lines, "\n ") + "\n ```" } // packageDir tries to figure out the directory of the specified package. @@ -510,7 +619,9 @@ func (p *Parser) addPkgToUniverse(pkg *packages.Package, u *types.Universe) erro // Add all of this package's imports. importedPkgs := []string{} - for _, imp := range pkg.Imports { + // Iterate imports in a predictable order + for _, key := range slices.Sorted(maps.Keys(pkg.Imports)) { + imp := pkg.Imports[key] if err := p.addPkgToUniverse(imp, u); err != nil { return err } @@ -557,7 +668,11 @@ func (p *Parser) priorCommentLines(pos token.Pos, lines int) *ast.CommentGroup { } func splitLines(str string) []string { - return strings.Split(strings.TrimRight(str, "\n"), "\n") + lines := strings.Split(strings.TrimRight(str, "\n"), "\n") + if len(lines) == 1 && lines[0] == "" { + return nil + } + return lines } func goFuncNameToName(in string) types.Name { @@ -652,6 +767,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type switch t := in.(type) { case *gotypes.Struct: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -670,6 +786,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type return out case *gotypes.Map: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -679,6 +796,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type return out case *gotypes.Pointer: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -687,6 +805,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type return out case *gotypes.Slice: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -695,6 +814,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type return out case *gotypes.Array: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -704,6 +824,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type return out case *gotypes.Chan: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -717,6 +838,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type Package: "", // This is a magic package name in the Universe. Name: t.Name(), }) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -724,6 +846,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type return out case *gotypes.Signature: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -732,6 +855,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type return out case *gotypes.Interface: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -754,6 +878,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type case *gotypes.Named, *gotypes.Basic, *gotypes.Map, *gotypes.Slice: name := goNameToName(t.String()) out = u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } @@ -776,6 +901,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type } if out := u.Type(name); out.Kind != types.Unknown { + out.GoType = in return out // short circuit if we've already made this. } out = p.walkType(u, &name, t.Underlying()) @@ -817,6 +943,7 @@ func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type } default: out := u.Type(name) + out.GoType = in if out.Kind != types.Unknown { return out } diff --git a/vendor/k8s.io/gengo/v2/parser/parse_122.go b/vendor/k8s.io/gengo/v2/parser/parse_122.go index ec2064958..de378eedd 100644 --- a/vendor/k8s.io/gengo/v2/parser/parse_122.go +++ b/vendor/k8s.io/gengo/v2/parser/parse_122.go @@ -31,3 +31,8 @@ func (p *Parser) walkAliasType(u types.Universe, in gotypes.Type) *types.Type { } return nil } + +func isTypeAlias(in gotypes.Type) bool { + _, isAlias := in.(*gotypes.Alias) + return isAlias +} diff --git a/vendor/k8s.io/gengo/v2/parser/parse_pre_122.go b/vendor/k8s.io/gengo/v2/parser/parse_pre_122.go index 6f62100c0..535d6c9db 100644 --- a/vendor/k8s.io/gengo/v2/parser/parse_pre_122.go +++ b/vendor/k8s.io/gengo/v2/parser/parse_pre_122.go @@ -28,3 +28,7 @@ import ( func (p *Parser) walkAliasType(u types.Universe, in gotypes.Type) *types.Type { return nil } + +func isTypeAlias(in gotypes.Type) bool { + return false +} diff --git a/vendor/k8s.io/gengo/v2/types/types.go b/vendor/k8s.io/gengo/v2/types/types.go index 7bbca0173..dab11d96e 100644 --- a/vendor/k8s.io/gengo/v2/types/types.go +++ b/vendor/k8s.io/gengo/v2/types/types.go @@ -16,7 +16,10 @@ limitations under the License. package types -import "strings" +import ( + gotypes "go/types" + "strings" +) // Ref makes a reference to the given type. It can only be used for e.g. // passing to namers. @@ -358,6 +361,9 @@ type Type struct { // If Kind == Array Len int64 + + // The underlying Go type. + GoType gotypes.Type } // String returns the name of the type. @@ -402,6 +408,11 @@ func (t *Type) IsAnonymousStruct() bool { return (t.Kind == Struct && t.Name.Name == "struct{}") || (t.Kind == Alias && t.Underlying.IsAnonymousStruct()) } +// IsComparable returns whether the type is comparable. +func (t *Type) IsComparable() bool { + return gotypes.Comparable(t.GoType) +} + // A single struct member type Member struct { // The name of the member. @@ -452,6 +463,10 @@ type Signature struct { // Built in types. var ( + Any = &Type{ + Name: Name{Name: "any"}, + Kind: Interface, + } String = &Type{ Name: Name{Name: "string"}, Kind: Builtin, @@ -515,6 +530,7 @@ var ( builtins = &Package{ Types: map[string]*Type{ + "any": Any, "bool": Bool, "string": String, "int": Int, @@ -539,6 +555,16 @@ var ( } ) +func PointerTo(t *Type) *Type { + return &Type{ + Name: Name{ + Name: "*" + t.Name.String(), + }, + Kind: Pointer, + Elem: t, + } +} + func IsInteger(t *Type) bool { switch t { case Int, Int64, Int32, Int16, Uint, Uint64, Uint32, Uint16, Byte: diff --git a/vendor/modules.txt b/vendor/modules.txt index adfff717d..0785d1143 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1094,9 +1094,10 @@ k8s.io/code-generator/cmd/lister-gen/args k8s.io/code-generator/cmd/lister-gen/generators k8s.io/code-generator/pkg/namer k8s.io/code-generator/pkg/util -# k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 -## explicit; go 1.20 +# k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b +## explicit; go 1.23 k8s.io/gengo/v2 +k8s.io/gengo/v2/codetags k8s.io/gengo/v2/generator k8s.io/gengo/v2/namer k8s.io/gengo/v2/parser