update dependencies (#6267)
Signed-off-by: hongming <coder.scala@gmail.com>
This commit is contained in:
199
vendor/k8s.io/gengo/args/args.go
generated
vendored
199
vendor/k8s.io/gengo/args/args.go
generated
vendored
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 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 args has common command-line flags for generation programs.
|
||||
package args
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
goflag "flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/parser"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// Default returns a defaulted GeneratorArgs. You may change the defaults
|
||||
// before calling AddFlags.
|
||||
func Default() *GeneratorArgs {
|
||||
return &GeneratorArgs{
|
||||
OutputBase: DefaultSourceTree(),
|
||||
GoHeaderFilePath: filepath.Join(DefaultSourceTree(), "k8s.io/gengo/boilerplate/boilerplate.go.txt"),
|
||||
GeneratedBuildTag: "ignore_autogenerated",
|
||||
GeneratedByCommentTemplate: "// Code generated by GENERATOR_NAME. DO NOT EDIT.",
|
||||
defaultCommandLineFlags: true,
|
||||
}
|
||||
}
|
||||
|
||||
// GeneratorArgs has arguments that are passed to generators.
|
||||
type GeneratorArgs struct {
|
||||
// Which directories to parse.
|
||||
InputDirs []string
|
||||
|
||||
// Source tree to write results to.
|
||||
OutputBase string
|
||||
|
||||
// Package path within the source tree.
|
||||
OutputPackagePath string
|
||||
|
||||
// Output file name.
|
||||
OutputFileBaseName string
|
||||
|
||||
// Where to get copyright header text.
|
||||
GoHeaderFilePath string
|
||||
|
||||
// If GeneratedByCommentTemplate is set, generate a "Code generated by" comment
|
||||
// below the bloilerplate, of the format defined by this string.
|
||||
// Any instances of "GENERATOR_NAME" will be replaced with the name of the code generator.
|
||||
GeneratedByCommentTemplate string
|
||||
|
||||
// If true, only verify, don't write anything.
|
||||
VerifyOnly bool
|
||||
|
||||
// If true, include *_test.go files
|
||||
IncludeTestFiles bool
|
||||
|
||||
// GeneratedBuildTag is the tag used to identify code generated by execution
|
||||
// of this type. Each generator should use a different tag, and different
|
||||
// groups of generators (external API that depends on Kube generations) should
|
||||
// keep tags distinct as well.
|
||||
GeneratedBuildTag string
|
||||
|
||||
// Any custom arguments go here
|
||||
CustomArgs interface{}
|
||||
|
||||
// If specified, trim the prefix from OutputPackagePath before writing files.
|
||||
TrimPathPrefix string
|
||||
|
||||
// Whether to use default command line flags
|
||||
defaultCommandLineFlags bool
|
||||
}
|
||||
|
||||
// WithoutDefaultFlagParsing disables implicit addition of command line flags and parsing.
|
||||
func (g *GeneratorArgs) WithoutDefaultFlagParsing() *GeneratorArgs {
|
||||
g.defaultCommandLineFlags = false
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *GeneratorArgs) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringSliceVarP(&g.InputDirs, "input-dirs", "i", g.InputDirs, "Comma-separated list of import paths to get input types from.")
|
||||
fs.StringVarP(&g.OutputBase, "output-base", "o", g.OutputBase, "Output base; defaults to $GOPATH/src/ or ./ if $GOPATH is not set.")
|
||||
fs.StringVarP(&g.OutputPackagePath, "output-package", "p", g.OutputPackagePath, "Base package path.")
|
||||
fs.StringVarP(&g.OutputFileBaseName, "output-file-base", "O", g.OutputFileBaseName, "Base name (without .go suffix) for output files.")
|
||||
fs.StringVarP(&g.GoHeaderFilePath, "go-header-file", "h", g.GoHeaderFilePath, "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.")
|
||||
fs.BoolVar(&g.VerifyOnly, "verify-only", g.VerifyOnly, "If true, only verify existing output, do not write anything.")
|
||||
fs.StringVar(&g.GeneratedBuildTag, "build-tag", g.GeneratedBuildTag, "A Go build tag to use to identify files generated by this command. Should be unique.")
|
||||
fs.StringVar(&g.TrimPathPrefix, "trim-path-prefix", g.TrimPathPrefix, "If set, trim the specified prefix from --output-package when generating files.")
|
||||
}
|
||||
|
||||
// LoadGoBoilerplate loads the boilerplate file passed to --go-header-file.
|
||||
func (g *GeneratorArgs) LoadGoBoilerplate() ([]byte, error) {
|
||||
b, err := ioutil.ReadFile(g.GoHeaderFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = bytes.Replace(b, []byte("YEAR"), []byte(strconv.Itoa(time.Now().UTC().Year())), -1)
|
||||
|
||||
if g.GeneratedByCommentTemplate != "" {
|
||||
if len(b) != 0 {
|
||||
b = append(b, byte('\n'))
|
||||
}
|
||||
generatorName := path.Base(os.Args[0])
|
||||
generatedByComment := strings.Replace(g.GeneratedByCommentTemplate, "GENERATOR_NAME", generatorName, -1)
|
||||
s := fmt.Sprintf("%s\n\n", generatedByComment)
|
||||
b = append(b, []byte(s)...)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// NewBuilder makes a new parser.Builder and populates it with the input
|
||||
// directories.
|
||||
func (g *GeneratorArgs) NewBuilder() (*parser.Builder, error) {
|
||||
b := parser.New()
|
||||
|
||||
// flag for including *_test.go
|
||||
b.IncludeTestFiles = g.IncludeTestFiles
|
||||
|
||||
// Ignore all auto-generated files.
|
||||
b.AddBuildTags(g.GeneratedBuildTag)
|
||||
|
||||
for _, d := range g.InputDirs {
|
||||
var err error
|
||||
if strings.HasSuffix(d, "/...") {
|
||||
err = b.AddDirRecursive(strings.TrimSuffix(d, "/..."))
|
||||
} else {
|
||||
err = b.AddDir(d)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to add directory %q: %v", d, err)
|
||||
}
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// DefaultSourceTree returns the /src directory of the first entry in $GOPATH.
|
||||
// If $GOPATH is empty, it returns "./". Useful as a default output location.
|
||||
func DefaultSourceTree() string {
|
||||
paths := strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator))
|
||||
if len(paths) > 0 && len(paths[0]) > 0 {
|
||||
return filepath.Join(paths[0], "src")
|
||||
}
|
||||
return "./"
|
||||
}
|
||||
|
||||
// Execute implements main().
|
||||
// If you don't need any non-default behavior, use as:
|
||||
// args.Default().Execute(...)
|
||||
func (g *GeneratorArgs) Execute(nameSystems namer.NameSystems, defaultSystem string, pkgs func(*generator.Context, *GeneratorArgs) generator.Packages) error {
|
||||
if g.defaultCommandLineFlags {
|
||||
g.AddFlags(pflag.CommandLine)
|
||||
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
|
||||
pflag.Parse()
|
||||
}
|
||||
|
||||
b, err := g.NewBuilder()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed making a parser: %v", err)
|
||||
}
|
||||
|
||||
// pass through the flag on whether to include *_test.go files
|
||||
b.IncludeTestFiles = g.IncludeTestFiles
|
||||
|
||||
c, err := generator.NewContext(b, nameSystems, defaultSystem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed making a context: %v", err)
|
||||
}
|
||||
|
||||
c.TrimPathPrefix = g.TrimPathPrefix
|
||||
|
||||
c.Verify = g.VerifyOnly
|
||||
packages := pkgs(c, g)
|
||||
if err := c.ExecutePackages(g.OutputBase, packages); err != nil {
|
||||
return fmt.Errorf("Failed executing generator: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
935
vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go
generated
vendored
935
vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go
generated
vendored
@@ -1,935 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 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 generators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/examples/set-gen/sets"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// CustomArgs is used tby the go2idl framework to pass args specific to this
|
||||
// generator.
|
||||
type CustomArgs struct {
|
||||
BoundingDirs []string // Only deal with types rooted under these dirs.
|
||||
}
|
||||
|
||||
// This is the comment tag that carries parameters for deep-copy generation.
|
||||
const (
|
||||
tagEnabledName = "k8s:deepcopy-gen"
|
||||
interfacesTagName = tagEnabledName + ":interfaces"
|
||||
interfacesNonPointerTagName = tagEnabledName + ":nonpointer-interfaces" // attach the DeepCopy<Interface> methods to the
|
||||
)
|
||||
|
||||
// Known values for the comment tag.
|
||||
const tagValuePackage = "package"
|
||||
|
||||
// enabledTagValue holds parameters from a tagName tag.
|
||||
type enabledTagValue struct {
|
||||
value string
|
||||
register bool
|
||||
}
|
||||
|
||||
func extractEnabledTypeTag(t *types.Type) *enabledTagValue {
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
return extractEnabledTag(comments)
|
||||
}
|
||||
|
||||
func extractEnabledTag(comments []string) *enabledTagValue {
|
||||
tagVals := types.ExtractCommentTags("+", comments)[tagEnabledName]
|
||||
if tagVals == nil {
|
||||
// No match for the tag.
|
||||
return nil
|
||||
}
|
||||
// If there are multiple values, abort.
|
||||
if len(tagVals) > 1 {
|
||||
klog.Fatalf("Found %d %s tags: %q", len(tagVals), tagEnabledName, tagVals)
|
||||
}
|
||||
|
||||
// If we got here we are returning something.
|
||||
tag := &enabledTagValue{}
|
||||
|
||||
// Get the primary value.
|
||||
parts := strings.Split(tagVals[0], ",")
|
||||
if len(parts) >= 1 {
|
||||
tag.value = parts[0]
|
||||
}
|
||||
|
||||
// Parse extra arguments.
|
||||
parts = parts[1:]
|
||||
for i := range parts {
|
||||
kv := strings.SplitN(parts[i], "=", 2)
|
||||
k := kv[0]
|
||||
v := ""
|
||||
if len(kv) == 2 {
|
||||
v = kv[1]
|
||||
}
|
||||
switch k {
|
||||
case "register":
|
||||
if v != "false" {
|
||||
tag.register = true
|
||||
}
|
||||
default:
|
||||
klog.Fatalf("Unsupported %s param: %q", tagEnabledName, parts[i])
|
||||
}
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
// TODO: This is created only to reduce number of changes in a single PR.
|
||||
// Remove it and use PublicNamer instead.
|
||||
func deepCopyNamer() *namer.NameStrategy {
|
||||
return &namer.NameStrategy{
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return strings.Join(in, "_")
|
||||
},
|
||||
PrependPackageNames: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"public": deepCopyNamer(),
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "public"
|
||||
}
|
||||
|
||||
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
boilerplate, err := arguments.LoadGoBoilerplate()
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed loading boilerplate: %v", err)
|
||||
}
|
||||
|
||||
inputs := sets.NewString(context.Inputs...)
|
||||
packages := generator.Packages{}
|
||||
header := append([]byte(fmt.Sprintf("//go:build !%s\n// +build !%s\n\n", arguments.GeneratedBuildTag, arguments.GeneratedBuildTag)), boilerplate...)
|
||||
|
||||
boundingDirs := []string{}
|
||||
if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
|
||||
if customArgs.BoundingDirs == nil {
|
||||
customArgs.BoundingDirs = context.Inputs
|
||||
}
|
||||
for i := range customArgs.BoundingDirs {
|
||||
// Strip any trailing slashes - they are not exactly "correct" but
|
||||
// this is friendlier.
|
||||
boundingDirs = append(boundingDirs, strings.TrimRight(customArgs.BoundingDirs[i], "/"))
|
||||
}
|
||||
}
|
||||
|
||||
for i := range inputs {
|
||||
klog.V(5).Infof("Considering pkg %q", i)
|
||||
pkg := context.Universe[i]
|
||||
if pkg == nil {
|
||||
// If the input had no Go files, for example.
|
||||
continue
|
||||
}
|
||||
|
||||
ptag := extractEnabledTag(pkg.Comments)
|
||||
ptagValue := ""
|
||||
ptagRegister := false
|
||||
if ptag != nil {
|
||||
ptagValue = ptag.value
|
||||
if ptagValue != tagValuePackage {
|
||||
klog.Fatalf("Package %v: unsupported %s value: %q", i, tagEnabledName, ptagValue)
|
||||
}
|
||||
ptagRegister = ptag.register
|
||||
klog.V(5).Infof(" tag.value: %q, tag.register: %t", ptagValue, ptagRegister)
|
||||
} else {
|
||||
klog.V(5).Infof(" no tag")
|
||||
}
|
||||
|
||||
// If the pkg-scoped tag says to generate, we can skip scanning types.
|
||||
pkgNeedsGeneration := (ptagValue == tagValuePackage)
|
||||
if !pkgNeedsGeneration {
|
||||
// If the pkg-scoped tag did not exist, scan all types for one that
|
||||
// explicitly wants generation. Ensure all types that want generation
|
||||
// can be copied.
|
||||
var uncopyable []string
|
||||
for _, t := range pkg.Types {
|
||||
klog.V(5).Infof(" considering type %q", t.Name.String())
|
||||
ttag := extractEnabledTypeTag(t)
|
||||
if ttag != nil && ttag.value == "true" {
|
||||
klog.V(5).Infof(" tag=true")
|
||||
if !copyableType(t) {
|
||||
uncopyable = append(uncopyable, fmt.Sprintf("%v", t))
|
||||
} else {
|
||||
pkgNeedsGeneration = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(uncopyable) > 0 {
|
||||
klog.Fatalf("Types requested deepcopy generation but are not copyable: %s",
|
||||
strings.Join(uncopyable, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
if pkgNeedsGeneration {
|
||||
klog.V(3).Infof("Package %q needs generation", i)
|
||||
path := pkg.Path
|
||||
// if the source path is within a /vendor/ directory (for example,
|
||||
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow
|
||||
// generation to output to the proper relative path (under vendor).
|
||||
// Otherwise, the generator will create the file in the wrong location
|
||||
// in the output directory.
|
||||
// TODO: build a more fundamental concept in gengo for dealing with modifications
|
||||
// to vendored packages.
|
||||
if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) {
|
||||
expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase)
|
||||
if strings.Contains(expandedPath, "/vendor/") {
|
||||
path = expandedPath
|
||||
}
|
||||
}
|
||||
packages = append(packages,
|
||||
&generator.DefaultPackage{
|
||||
PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0],
|
||||
PackagePath: path,
|
||||
HeaderText: header,
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
return []generator.Generator{
|
||||
NewGenDeepCopy(arguments.OutputFileBaseName, pkg.Path, boundingDirs, (ptagValue == tagValuePackage), ptagRegister),
|
||||
}
|
||||
},
|
||||
FilterFunc: func(c *generator.Context, t *types.Type) bool {
|
||||
return t.Name.Package == pkg.Path
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
// genDeepCopy produces a file with autogenerated deep-copy functions.
|
||||
type genDeepCopy struct {
|
||||
generator.DefaultGen
|
||||
targetPackage string
|
||||
boundingDirs []string
|
||||
allTypes bool
|
||||
registerTypes bool
|
||||
imports namer.ImportTracker
|
||||
typesForInit []*types.Type
|
||||
}
|
||||
|
||||
func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator {
|
||||
return &genDeepCopy{
|
||||
DefaultGen: generator.DefaultGen{
|
||||
OptionalName: sanitizedName,
|
||||
},
|
||||
targetPackage: targetPackage,
|
||||
boundingDirs: boundingDirs,
|
||||
allTypes: allTypes,
|
||||
registerTypes: registerTypes,
|
||||
imports: generator.NewImportTracker(),
|
||||
typesForInit: make([]*types.Type, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems {
|
||||
// Have the raw namer for this file track what it imports.
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer(g.targetPackage, g.imports),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool {
|
||||
// Filter out types not being processed or not copyable within the package.
|
||||
enabled := g.allTypes
|
||||
if !enabled {
|
||||
ttag := extractEnabledTypeTag(t)
|
||||
if ttag != nil && ttag.value == "true" {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
if !enabled {
|
||||
return false
|
||||
}
|
||||
if !copyableType(t) {
|
||||
klog.V(2).Infof("Type %v is not copyable", t)
|
||||
return false
|
||||
}
|
||||
klog.V(4).Infof("Type %v is copyable", t)
|
||||
g.typesForInit = append(g.typesForInit, t)
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) copyableAndInBounds(t *types.Type) bool {
|
||||
if !copyableType(t) {
|
||||
return false
|
||||
}
|
||||
// Only packages within the restricted range can be processed.
|
||||
if !isRootedUnder(t.Name.Package, g.boundingDirs) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// deepCopyMethod returns the signature of a DeepCopy() method, nil or an error
|
||||
// if the type does not match. This allows more efficient deep copy
|
||||
// implementations to be defined by the type's author. The correct signature
|
||||
// for a type T is:
|
||||
// func (t T) DeepCopy() T
|
||||
// or:
|
||||
// func (t *T) DeepCopy() *T
|
||||
func deepCopyMethod(t *types.Type) (*types.Signature, error) {
|
||||
f, found := t.Methods["DeepCopy"]
|
||||
if !found {
|
||||
return nil, nil
|
||||
}
|
||||
if len(f.Signature.Parameters) != 0 {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no parameters", t)
|
||||
}
|
||||
if len(f.Signature.Results) != 1 {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one result", t)
|
||||
}
|
||||
|
||||
ptrResult := f.Signature.Results[0].Kind == types.Pointer && f.Signature.Results[0].Elem.Name == t.Name
|
||||
nonPtrResult := f.Signature.Results[0].Name == t.Name
|
||||
|
||||
if !ptrResult && !nonPtrResult {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected to return %s or *%s", t, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
|
||||
ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
|
||||
nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
|
||||
|
||||
if ptrRcvr && !ptrResult {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a *%s result for a *%s receiver", t, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
if nonPtrRcvr && !nonPtrResult {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a %s result for a %s receiver", t, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
|
||||
return f.Signature, nil
|
||||
}
|
||||
|
||||
// deepCopyMethodOrDie returns the signatrue of a DeepCopy method, nil or calls klog.Fatalf
|
||||
// if the type does not match.
|
||||
func deepCopyMethodOrDie(t *types.Type) *types.Signature {
|
||||
ret, err := deepCopyMethod(t)
|
||||
if err != nil {
|
||||
klog.Fatal(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// deepCopyIntoMethod returns the signature of a DeepCopyInto() method, nil or an error
|
||||
// if the type is wrong. DeepCopyInto allows more efficient deep copy
|
||||
// implementations to be defined by the type's author. The correct signature
|
||||
// for a type T is:
|
||||
// func (t T) DeepCopyInto(t *T)
|
||||
// or:
|
||||
// func (t *T) DeepCopyInto(t *T)
|
||||
func deepCopyIntoMethod(t *types.Type) (*types.Signature, error) {
|
||||
f, found := t.Methods["DeepCopyInto"]
|
||||
if !found {
|
||||
return nil, nil
|
||||
}
|
||||
if len(f.Signature.Parameters) != 1 {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one parameter", t)
|
||||
}
|
||||
if len(f.Signature.Results) != 0 {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no result type", t)
|
||||
}
|
||||
|
||||
ptrParam := f.Signature.Parameters[0].Kind == types.Pointer && f.Signature.Parameters[0].Elem.Name == t.Name
|
||||
|
||||
if !ptrParam {
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected parameter of type *%s", t, t.Name.Name)
|
||||
}
|
||||
|
||||
ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
|
||||
nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
|
||||
|
||||
if !ptrRcvr && !nonPtrRcvr {
|
||||
// this should never happen
|
||||
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a receiver of type %s or *%s", t, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
|
||||
return f.Signature, nil
|
||||
}
|
||||
|
||||
// deepCopyIntoMethodOrDie returns the signature of a DeepCopyInto() method, nil or calls klog.Fatalf
|
||||
// if the type is wrong.
|
||||
func deepCopyIntoMethodOrDie(t *types.Type) *types.Signature {
|
||||
ret, err := deepCopyIntoMethod(t)
|
||||
if err != nil {
|
||||
klog.Fatal(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func isRootedUnder(pkg string, roots []string) bool {
|
||||
// Add trailing / to avoid false matches, e.g. foo/bar vs foo/barn. This
|
||||
// assumes that bounding dirs do not have trailing slashes.
|
||||
pkg = pkg + "/"
|
||||
for _, root := range roots {
|
||||
if strings.HasPrefix(pkg, root+"/") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func copyableType(t *types.Type) bool {
|
||||
// If the type opts out of copy-generation, stop.
|
||||
ttag := extractEnabledTypeTag(t)
|
||||
if ttag != nil && ttag.value == "false" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter out private types.
|
||||
if namer.IsPrivateGoName(t.Name.Name) {
|
||||
return false
|
||||
}
|
||||
|
||||
if t.Kind == types.Alias {
|
||||
// if the underlying built-in is not deepcopy-able, deepcopy is opt-in through definition of custom methods.
|
||||
// Note that aliases of builtins, maps, slices can have deepcopy methods.
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
return true
|
||||
} else {
|
||||
return t.Underlying.Kind != types.Builtin || copyableType(t.Underlying)
|
||||
}
|
||||
}
|
||||
|
||||
if t.Kind != types.Struct {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func underlyingType(t *types.Type) *types.Type {
|
||||
for t.Kind == types.Alias {
|
||||
t = t.Underlying
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) isOtherPackage(pkg string) bool {
|
||||
if pkg == g.targetPackage {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) {
|
||||
importLines := []string{}
|
||||
for _, singleImport := range g.imports.ImportLines() {
|
||||
if g.isOtherPackage(singleImport) {
|
||||
importLines = append(importLines, singleImport)
|
||||
}
|
||||
}
|
||||
return importLines
|
||||
}
|
||||
|
||||
func argsFromType(ts ...*types.Type) generator.Args {
|
||||
a := generator.Args{
|
||||
"type": ts[0],
|
||||
}
|
||||
for i, t := range ts {
|
||||
a[fmt.Sprintf("type%d", i+1)] = t
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) needsGeneration(t *types.Type) bool {
|
||||
tag := extractEnabledTypeTag(t)
|
||||
tv := ""
|
||||
if tag != nil {
|
||||
tv = tag.value
|
||||
if tv != "true" && tv != "false" {
|
||||
klog.Fatalf("Type %v: unsupported %s value: %q", t, tagEnabledName, tag.value)
|
||||
}
|
||||
}
|
||||
if g.allTypes && tv == "false" {
|
||||
// The whole package is being generated, but this type has opted out.
|
||||
klog.V(5).Infof("Not generating for type %v because type opted out", t)
|
||||
return false
|
||||
}
|
||||
if !g.allTypes && tv != "true" {
|
||||
// The whole package is NOT being generated, and this type has NOT opted in.
|
||||
klog.V(5).Infof("Not generating for type %v because type did not opt in", t)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func extractInterfacesTag(t *types.Type) []string {
|
||||
var result []string
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
values := types.ExtractCommentTags("+", comments)[interfacesTagName]
|
||||
for _, v := range values {
|
||||
if len(v) == 0 {
|
||||
continue
|
||||
}
|
||||
intfs := strings.Split(v, ",")
|
||||
for _, intf := range intfs {
|
||||
if intf == "" {
|
||||
continue
|
||||
}
|
||||
result = append(result, intf)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func extractNonPointerInterfaces(t *types.Type) (bool, error) {
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
values := types.ExtractCommentTags("+", comments)[interfacesNonPointerTagName]
|
||||
if len(values) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
result := values[0] == "true"
|
||||
for _, v := range values {
|
||||
if v == "true" != result {
|
||||
return false, fmt.Errorf("contradicting %v value %q found to previous value %v", interfacesNonPointerTagName, v, result)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (g *genDeepCopy) deepCopyableInterfacesInner(c *generator.Context, t *types.Type) ([]*types.Type, error) {
|
||||
if t.Kind != types.Struct {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
intfs := extractInterfacesTag(t)
|
||||
|
||||
var ts []*types.Type
|
||||
for _, intf := range intfs {
|
||||
t := types.ParseFullyQualifiedName(intf)
|
||||
err := c.AddDir(t.Package)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
intfT := c.Universe.Type(t)
|
||||
if intfT == nil {
|
||||
return nil, fmt.Errorf("unknown type %q in %s tag of type %s", intf, interfacesTagName, intfT)
|
||||
}
|
||||
if intfT.Kind != types.Interface {
|
||||
return nil, fmt.Errorf("type %q in %s tag of type %s is not an interface, but: %q", intf, interfacesTagName, t, intfT.Kind)
|
||||
}
|
||||
g.imports.AddType(intfT)
|
||||
ts = append(ts, intfT)
|
||||
}
|
||||
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// deepCopyableInterfaces returns the interface types to implement and whether they apply to a non-pointer receiver.
|
||||
func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, bool, error) {
|
||||
ts, err := g.deepCopyableInterfacesInner(c, t)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
set := map[string]*types.Type{}
|
||||
for _, t := range ts {
|
||||
set[t.String()] = t
|
||||
}
|
||||
|
||||
result := []*types.Type{}
|
||||
for _, t := range set {
|
||||
result = append(result, t)
|
||||
}
|
||||
|
||||
TypeSlice(result).Sort() // we need a stable sorting because it determines the order in generation
|
||||
|
||||
nonPointerReceiver, err := extractNonPointerInterfaces(t)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return result, nonPointerReceiver, nil
|
||||
}
|
||||
|
||||
type TypeSlice []*types.Type
|
||||
|
||||
func (s TypeSlice) Len() int { return len(s) }
|
||||
func (s TypeSlice) Less(i, j int) bool { return s[i].String() < s[j].String() }
|
||||
func (s TypeSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s TypeSlice) Sort() { sort.Sort(s) }
|
||||
|
||||
func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
if !g.needsGeneration(t) {
|
||||
return nil
|
||||
}
|
||||
klog.V(5).Infof("Generating deepcopy function for type %v", t)
|
||||
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
args := argsFromType(t)
|
||||
|
||||
if deepCopyIntoMethodOrDie(t) == nil {
|
||||
sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\n", args)
|
||||
if isReference(t) {
|
||||
sw.Do("func (in $.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
|
||||
sw.Do("{in:=&in\n", nil)
|
||||
} else {
|
||||
sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
|
||||
}
|
||||
if deepCopyMethodOrDie(t) != nil {
|
||||
if t.Methods["DeepCopy"].Signature.Receiver.Kind == types.Pointer {
|
||||
sw.Do("clone := in.DeepCopy()\n", nil)
|
||||
sw.Do("*out = *clone\n", nil)
|
||||
} else {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
}
|
||||
sw.Do("return\n", nil)
|
||||
} else {
|
||||
g.generateFor(t, sw)
|
||||
sw.Do("return\n", nil)
|
||||
}
|
||||
if isReference(t) {
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
|
||||
if deepCopyMethodOrDie(t) == nil {
|
||||
sw.Do("// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new $.type|raw$.\n", args)
|
||||
if isReference(t) {
|
||||
sw.Do("func (in $.type|raw$) DeepCopy() $.type|raw$ {\n", args)
|
||||
} else {
|
||||
sw.Do("func (in *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args)
|
||||
}
|
||||
sw.Do("if in == nil { return nil }\n", nil)
|
||||
sw.Do("out := new($.type|raw$)\n", args)
|
||||
sw.Do("in.DeepCopyInto(out)\n", nil)
|
||||
if isReference(t) {
|
||||
sw.Do("return *out\n", nil)
|
||||
} else {
|
||||
sw.Do("return out\n", nil)
|
||||
}
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
|
||||
intfs, nonPointerReceiver, err := g.deepCopyableInterfaces(c, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, intf := range intfs {
|
||||
sw.Do(fmt.Sprintf("// DeepCopy%s is an autogenerated deepcopy function, copying the receiver, creating a new $.type2|raw$.\n", intf.Name.Name), argsFromType(t, intf))
|
||||
if nonPointerReceiver {
|
||||
sw.Do(fmt.Sprintf("func (in $.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
|
||||
sw.Do("return *in.DeepCopy()", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
} else {
|
||||
sw.Do(fmt.Sprintf("func (in *$.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
|
||||
sw.Do("if c := in.DeepCopy(); c != nil {\n", nil)
|
||||
sw.Do("return c\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
sw.Do("return nil\n", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
// isReference return true for pointer, maps, slices and aliases of those.
|
||||
func isReference(t *types.Type) bool {
|
||||
if t.Kind == types.Pointer || t.Kind == types.Map || t.Kind == types.Slice {
|
||||
return true
|
||||
}
|
||||
return t.Kind == types.Alias && isReference(underlyingType(t))
|
||||
}
|
||||
|
||||
// we use the system of shadowing 'in' and 'out' so that the same code is valid
|
||||
// at any nesting level. This makes the autogenerator easy to understand, and
|
||||
// the compiler shouldn't care.
|
||||
func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
|
||||
// derive inner types if t is an alias. We call the do* methods below with the alias type.
|
||||
// basic rule: generate according to inner type, but construct objects with the alias type.
|
||||
ut := underlyingType(t)
|
||||
|
||||
var f func(*types.Type, *generator.SnippetWriter)
|
||||
switch ut.Kind {
|
||||
case types.Builtin:
|
||||
f = g.doBuiltin
|
||||
case types.Map:
|
||||
f = g.doMap
|
||||
case types.Slice:
|
||||
f = g.doSlice
|
||||
case types.Struct:
|
||||
f = g.doStruct
|
||||
case types.Pointer:
|
||||
f = g.doPointer
|
||||
case types.Interface:
|
||||
// interfaces are handled in-line in the other cases
|
||||
klog.Fatalf("Hit an interface type %v. This should never happen.", t)
|
||||
case types.Alias:
|
||||
// can never happen because we branch on the underlying type which is never an alias
|
||||
klog.Fatalf("Hit an alias type %v. This should never happen.", t)
|
||||
default:
|
||||
klog.Fatalf("Hit an unsupported type %v.", t)
|
||||
}
|
||||
f(t, sw)
|
||||
}
|
||||
|
||||
// doBuiltin generates code for a builtin or an alias to a builtin. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
return
|
||||
}
|
||||
|
||||
sw.Do("*out = *in\n", nil)
|
||||
}
|
||||
|
||||
// doMap generates code for a map or an alias to a map. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
|
||||
ut := underlyingType(t)
|
||||
uet := underlyingType(ut.Elem)
|
||||
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if !ut.Key.IsAssignable() {
|
||||
klog.Fatalf("Hit an unsupported type %v for: %v", uet, t)
|
||||
}
|
||||
|
||||
sw.Do("*out = make($.|raw$, len(*in))\n", t)
|
||||
sw.Do("for key, val := range *in {\n", nil)
|
||||
dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
|
||||
switch {
|
||||
case dc != nil || dci != nil:
|
||||
// Note: a DeepCopy exists because it is added if DeepCopyInto is manually defined
|
||||
leftPointer := ut.Elem.Kind == types.Pointer
|
||||
rightPointer := !isReference(ut.Elem)
|
||||
if dc != nil {
|
||||
rightPointer = dc.Results[0].Kind == types.Pointer
|
||||
}
|
||||
if leftPointer == rightPointer {
|
||||
sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
|
||||
} else if leftPointer {
|
||||
sw.Do("x := val.DeepCopy()\n", nil)
|
||||
sw.Do("(*out)[key] = &x\n", nil)
|
||||
} else {
|
||||
sw.Do("(*out)[key] = *val.DeepCopy()\n", nil)
|
||||
}
|
||||
case ut.Elem.IsAnonymousStruct(): // not uet here because it needs type cast
|
||||
sw.Do("(*out)[key] = val\n", nil)
|
||||
case uet.IsAssignable():
|
||||
sw.Do("(*out)[key] = val\n", nil)
|
||||
case uet.Kind == types.Interface:
|
||||
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
|
||||
if uet.Name.Name == "interface{}" {
|
||||
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uet.Name.Name)
|
||||
}
|
||||
sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil)
|
||||
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
||||
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
||||
// parser does not give us the underlying interface name. So we cannot do any better.
|
||||
sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", uet.Name.Name), nil)
|
||||
sw.Do("}\n", nil)
|
||||
case uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer:
|
||||
sw.Do("var outVal $.|raw$\n", uet)
|
||||
sw.Do("if val == nil { (*out)[key] = nil } else {\n", nil)
|
||||
sw.Do("in, out := &val, &outVal\n", uet)
|
||||
g.generateFor(ut.Elem, sw)
|
||||
sw.Do("}\n", nil)
|
||||
sw.Do("(*out)[key] = outVal\n", nil)
|
||||
case uet.Kind == types.Struct:
|
||||
sw.Do("(*out)[key] = *val.DeepCopy()\n", uet)
|
||||
default:
|
||||
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
|
||||
}
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
|
||||
// doSlice generates code for a slice or an alias to a slice. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
|
||||
ut := underlyingType(t)
|
||||
uet := underlyingType(ut.Elem)
|
||||
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
return
|
||||
}
|
||||
|
||||
sw.Do("*out = make($.|raw$, len(*in))\n", t)
|
||||
if deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
|
||||
sw.Do("for i := range *in {\n", nil)
|
||||
// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
|
||||
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
|
||||
sw.Do("}\n", nil)
|
||||
} else if uet.Kind == types.Builtin || uet.IsAssignable() {
|
||||
sw.Do("copy(*out, *in)\n", nil)
|
||||
} else {
|
||||
sw.Do("for i := range *in {\n", nil)
|
||||
if uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer || deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
|
||||
sw.Do("if (*in)[i] != nil {\n", nil)
|
||||
sw.Do("in, out := &(*in)[i], &(*out)[i]\n", nil)
|
||||
g.generateFor(ut.Elem, sw)
|
||||
sw.Do("}\n", nil)
|
||||
} else if uet.Kind == types.Interface {
|
||||
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
|
||||
if uet.Name.Name == "interface{}" {
|
||||
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uet.Name.Name)
|
||||
}
|
||||
sw.Do("if (*in)[i] != nil {\n", nil)
|
||||
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
||||
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
||||
// parser does not give us the underlying interface name. So we cannot do any better.
|
||||
sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", uet.Name.Name), nil)
|
||||
sw.Do("}\n", nil)
|
||||
} else if uet.Kind == types.Struct {
|
||||
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
|
||||
} else {
|
||||
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
|
||||
}
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
}
|
||||
|
||||
// doStruct generates code for a struct or an alias to a struct. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
|
||||
ut := underlyingType(t)
|
||||
|
||||
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
||||
sw.Do("*out = in.DeepCopy()\n", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Simple copy covers a lot of cases.
|
||||
sw.Do("*out = *in\n", nil)
|
||||
|
||||
// Now fix-up fields as needed.
|
||||
for _, m := range ut.Members {
|
||||
ft := m.Type
|
||||
uft := underlyingType(ft)
|
||||
|
||||
args := generator.Args{
|
||||
"type": ft,
|
||||
"kind": ft.Kind,
|
||||
"name": m.Name,
|
||||
}
|
||||
dc, dci := deepCopyMethodOrDie(ft), deepCopyIntoMethodOrDie(ft)
|
||||
switch {
|
||||
case dc != nil || dci != nil:
|
||||
// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
|
||||
leftPointer := ft.Kind == types.Pointer
|
||||
rightPointer := !isReference(ft)
|
||||
if dc != nil {
|
||||
rightPointer = dc.Results[0].Kind == types.Pointer
|
||||
}
|
||||
if leftPointer == rightPointer {
|
||||
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
|
||||
} else if leftPointer {
|
||||
sw.Do("x := in.$.name$.DeepCopy()\n", args)
|
||||
sw.Do("out.$.name$ = = &x\n", args)
|
||||
} else {
|
||||
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
|
||||
}
|
||||
case uft.Kind == types.Builtin:
|
||||
// the initial *out = *in was enough
|
||||
case uft.Kind == types.Map, uft.Kind == types.Slice, uft.Kind == types.Pointer:
|
||||
// Fixup non-nil reference-semantic types.
|
||||
sw.Do("if in.$.name$ != nil {\n", args)
|
||||
sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
|
||||
g.generateFor(ft, sw)
|
||||
sw.Do("}\n", nil)
|
||||
case uft.Kind == types.Array:
|
||||
sw.Do("out.$.name$ = in.$.name$\n", args)
|
||||
case uft.Kind == types.Struct:
|
||||
if ft.IsAssignable() {
|
||||
sw.Do("out.$.name$ = in.$.name$\n", args)
|
||||
} else {
|
||||
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
|
||||
}
|
||||
case uft.Kind == types.Interface:
|
||||
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
|
||||
if uft.Name.Name == "interface{}" {
|
||||
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uft.Name.Name)
|
||||
}
|
||||
sw.Do("if in.$.name$ != nil {\n", args)
|
||||
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
||||
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
||||
// parser does not give us the underlying interface name. So we cannot do any better.
|
||||
sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", uft.Name.Name), args)
|
||||
sw.Do("}\n", nil)
|
||||
default:
|
||||
klog.Fatalf("Hit an unsupported type %v for %v, from %v", uft, ft, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// doPointer generates code for a pointer or an alias to a pointer. The generated code is
|
||||
// is the same for both cases, i.e. it's the code for the underlying type.
|
||||
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
|
||||
ut := underlyingType(t)
|
||||
uet := underlyingType(ut.Elem)
|
||||
|
||||
dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
|
||||
switch {
|
||||
case dc != nil || dci != nil:
|
||||
rightPointer := !isReference(ut.Elem)
|
||||
if dc != nil {
|
||||
rightPointer = dc.Results[0].Kind == types.Pointer
|
||||
}
|
||||
if rightPointer {
|
||||
sw.Do("*out = (*in).DeepCopy()\n", nil)
|
||||
} else {
|
||||
sw.Do("x := (*in).DeepCopy()\n", nil)
|
||||
sw.Do("*out = &x\n", nil)
|
||||
}
|
||||
case uet.IsAssignable():
|
||||
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
||||
sw.Do("**out = **in", nil)
|
||||
case uet.Kind == types.Map, uet.Kind == types.Slice, uet.Kind == types.Pointer:
|
||||
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
||||
sw.Do("if **in != nil {\n", nil)
|
||||
sw.Do("in, out := *in, *out\n", nil)
|
||||
g.generateFor(uet, sw)
|
||||
sw.Do("}\n", nil)
|
||||
case uet.Kind == types.Struct:
|
||||
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
||||
sw.Do("(*in).DeepCopyInto(*out)\n", nil)
|
||||
default:
|
||||
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
|
||||
}
|
||||
}
|
||||
1260
vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go
generated
vendored
1260
vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go
generated
vendored
File diff suppressed because it is too large
Load Diff
221
vendor/k8s.io/gengo/examples/set-gen/sets/byte.go
generated
vendored
221
vendor/k8s.io/gengo/examples/set-gen/sets/byte.go
generated
vendored
@@ -1,221 +0,0 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.Byte is a set of bytes, implemented via map[byte]struct{} for minimal memory consumption.
|
||||
type Byte map[byte]Empty
|
||||
|
||||
// NewByte creates a Byte from a list of values.
|
||||
func NewByte(items ...byte) Byte {
|
||||
ss := make(Byte, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// ByteKeySet creates a Byte from a keys of a map[byte](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func ByteKeySet(theMap interface{}) Byte {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := Byte{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(byte))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s Byte) Insert(items ...byte) Byte {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Byte) Delete(items ...byte) Byte {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s Byte) Has(item byte) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s Byte) HasAll(items ...byte) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s Byte) HasAny(items ...byte) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s Byte) Clone() Byte {
|
||||
result := make(Byte, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s1 Byte) Difference(s2 Byte) Byte {
|
||||
result := NewByte()
|
||||
for key := range s1 {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SymmetricDifference returns a set of elements which are in either of the sets, but not in their intersection.
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.SymmetricDifference(s2) = {a3, a4, a5}
|
||||
// s2.SymmetricDifference(s1) = {a3, a4, a5}
|
||||
func (s1 Byte) SymmetricDifference(s2 Byte) Byte {
|
||||
return s1.Difference(s2).Union(s2.Difference(s1))
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Byte) Union(s2 Byte) Byte {
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 Byte) Intersection(s2 Byte) Byte {
|
||||
var walk, other Byte
|
||||
result := NewByte()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 Byte) IsSuperset(s2 Byte) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 Byte) Equal(s2 Byte) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfByte []byte
|
||||
|
||||
func (s sortableSliceOfByte) Len() int { return len(s) }
|
||||
func (s sortableSliceOfByte) Less(i, j int) bool { return lessByte(s[i], s[j]) }
|
||||
func (s sortableSliceOfByte) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted byte slice.
|
||||
func (s Byte) List() []byte {
|
||||
res := make(sortableSliceOfByte, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []byte(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s Byte) UnsortedList() []byte {
|
||||
res := make([]byte, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s Byte) PopAny() (byte, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue byte
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s Byte) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessByte(lhs, rhs byte) bool {
|
||||
return lhs < rhs
|
||||
}
|
||||
20
vendor/k8s.io/gengo/examples/set-gen/sets/doc.go
generated
vendored
20
vendor/k8s.io/gengo/examples/set-gen/sets/doc.go
generated
vendored
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
// Package sets has auto-generated set types.
|
||||
package sets
|
||||
23
vendor/k8s.io/gengo/examples/set-gen/sets/empty.go
generated
vendored
23
vendor/k8s.io/gengo/examples/set-gen/sets/empty.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
// Empty is public since it is used by some internal API objects for conversions between external
|
||||
// string arrays and internal sets, and conversion logic requires public types today.
|
||||
type Empty struct{}
|
||||
221
vendor/k8s.io/gengo/examples/set-gen/sets/int.go
generated
vendored
221
vendor/k8s.io/gengo/examples/set-gen/sets/int.go
generated
vendored
@@ -1,221 +0,0 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.Int is a set of ints, implemented via map[int]struct{} for minimal memory consumption.
|
||||
type Int map[int]Empty
|
||||
|
||||
// NewInt creates a Int from a list of values.
|
||||
func NewInt(items ...int) Int {
|
||||
ss := make(Int, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// IntKeySet creates a Int from a keys of a map[int](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func IntKeySet(theMap interface{}) Int {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := Int{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(int))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s Int) Insert(items ...int) Int {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Int) Delete(items ...int) Int {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s Int) Has(item int) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s Int) HasAll(items ...int) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s Int) HasAny(items ...int) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s Int) Clone() Int {
|
||||
result := make(Int, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s1 Int) Difference(s2 Int) Int {
|
||||
result := NewInt()
|
||||
for key := range s1 {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SymmetricDifference returns a set of elements which are in either of the sets, but not in their intersection.
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.SymmetricDifference(s2) = {a3, a4, a5}
|
||||
// s2.SymmetricDifference(s1) = {a3, a4, a5}
|
||||
func (s1 Int) SymmetricDifference(s2 Int) Int {
|
||||
return s1.Difference(s2).Union(s2.Difference(s1))
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Int) Union(s2 Int) Int {
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 Int) Intersection(s2 Int) Int {
|
||||
var walk, other Int
|
||||
result := NewInt()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 Int) IsSuperset(s2 Int) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 Int) Equal(s2 Int) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfInt []int
|
||||
|
||||
func (s sortableSliceOfInt) Len() int { return len(s) }
|
||||
func (s sortableSliceOfInt) Less(i, j int) bool { return lessInt(s[i], s[j]) }
|
||||
func (s sortableSliceOfInt) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted int slice.
|
||||
func (s Int) List() []int {
|
||||
res := make(sortableSliceOfInt, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []int(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s Int) UnsortedList() []int {
|
||||
res := make([]int, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s Int) PopAny() (int, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue int
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s Int) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessInt(lhs, rhs int) bool {
|
||||
return lhs < rhs
|
||||
}
|
||||
221
vendor/k8s.io/gengo/examples/set-gen/sets/int64.go
generated
vendored
221
vendor/k8s.io/gengo/examples/set-gen/sets/int64.go
generated
vendored
@@ -1,221 +0,0 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.Int64 is a set of int64s, implemented via map[int64]struct{} for minimal memory consumption.
|
||||
type Int64 map[int64]Empty
|
||||
|
||||
// NewInt64 creates a Int64 from a list of values.
|
||||
func NewInt64(items ...int64) Int64 {
|
||||
ss := make(Int64, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// Int64KeySet creates a Int64 from a keys of a map[int64](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func Int64KeySet(theMap interface{}) Int64 {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := Int64{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(int64))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s Int64) Insert(items ...int64) Int64 {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Int64) Delete(items ...int64) Int64 {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s Int64) Has(item int64) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s Int64) HasAll(items ...int64) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s Int64) HasAny(items ...int64) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s Int64) Clone() Int64 {
|
||||
result := make(Int64, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s1 Int64) Difference(s2 Int64) Int64 {
|
||||
result := NewInt64()
|
||||
for key := range s1 {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SymmetricDifference returns a set of elements which are in either of the sets, but not in their intersection.
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.SymmetricDifference(s2) = {a3, a4, a5}
|
||||
// s2.SymmetricDifference(s1) = {a3, a4, a5}
|
||||
func (s1 Int64) SymmetricDifference(s2 Int64) Int64 {
|
||||
return s1.Difference(s2).Union(s2.Difference(s1))
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Int64) Union(s2 Int64) Int64 {
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 Int64) Intersection(s2 Int64) Int64 {
|
||||
var walk, other Int64
|
||||
result := NewInt64()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 Int64) IsSuperset(s2 Int64) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 Int64) Equal(s2 Int64) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfInt64 []int64
|
||||
|
||||
func (s sortableSliceOfInt64) Len() int { return len(s) }
|
||||
func (s sortableSliceOfInt64) Less(i, j int) bool { return lessInt64(s[i], s[j]) }
|
||||
func (s sortableSliceOfInt64) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted int64 slice.
|
||||
func (s Int64) List() []int64 {
|
||||
res := make(sortableSliceOfInt64, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []int64(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s Int64) UnsortedList() []int64 {
|
||||
res := make([]int64, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s Int64) PopAny() (int64, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue int64
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s Int64) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessInt64(lhs, rhs int64) bool {
|
||||
return lhs < rhs
|
||||
}
|
||||
221
vendor/k8s.io/gengo/examples/set-gen/sets/string.go
generated
vendored
221
vendor/k8s.io/gengo/examples/set-gen/sets/string.go
generated
vendored
@@ -1,221 +0,0 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
|
||||
type String map[string]Empty
|
||||
|
||||
// NewString creates a String from a list of values.
|
||||
func NewString(items ...string) String {
|
||||
ss := make(String, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func StringKeySet(theMap interface{}) String {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := String{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(string))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s String) Insert(items ...string) String {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s String) Delete(items ...string) String {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s String) Has(item string) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s String) HasAll(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s String) HasAny(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s String) Clone() String {
|
||||
result := make(String, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s1 String) Difference(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s1 {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SymmetricDifference returns a set of elements which are in either of the sets, but not in their intersection.
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.SymmetricDifference(s2) = {a3, a4, a5}
|
||||
// s2.SymmetricDifference(s1) = {a3, a4, a5}
|
||||
func (s1 String) SymmetricDifference(s2 String) String {
|
||||
return s1.Difference(s2).Union(s2.Difference(s1))
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 String) Union(s2 String) String {
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 String) Intersection(s2 String) String {
|
||||
var walk, other String
|
||||
result := NewString()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 String) IsSuperset(s2 String) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 String) Equal(s2 String) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfString []string
|
||||
|
||||
func (s sortableSliceOfString) Len() int { return len(s) }
|
||||
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
|
||||
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted string slice.
|
||||
func (s String) List() []string {
|
||||
res := make(sortableSliceOfString, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []string(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s String) UnsortedList() []string {
|
||||
res := make([]string, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s String) PopAny() (string, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue string
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s String) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessString(lhs, rhs string) bool {
|
||||
return lhs < rhs
|
||||
}
|
||||
62
vendor/k8s.io/gengo/generator/default_generator.go
generated
vendored
62
vendor/k8s.io/gengo/generator/default_generator.go
generated
vendored
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 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 generator
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
const (
|
||||
GolangFileType = "golang"
|
||||
)
|
||||
|
||||
// DefaultGen implements a do-nothing Generator.
|
||||
//
|
||||
// It can be used to implement static content files.
|
||||
type DefaultGen struct {
|
||||
// OptionalName, if present, will be used for the generator's name, and
|
||||
// the filename (with ".go" appended).
|
||||
OptionalName string
|
||||
|
||||
// OptionalBody, if present, will be used as the return from the "Init"
|
||||
// method. This causes it to be static content for the entire file if
|
||||
// no other generator touches the file.
|
||||
OptionalBody []byte
|
||||
}
|
||||
|
||||
func (d DefaultGen) Name() string { return d.OptionalName }
|
||||
func (d DefaultGen) Filter(*Context, *types.Type) bool { return true }
|
||||
func (d DefaultGen) Namers(*Context) namer.NameSystems { return nil }
|
||||
func (d DefaultGen) Imports(*Context) []string { return []string{} }
|
||||
func (d DefaultGen) PackageVars(*Context) []string { return []string{} }
|
||||
func (d DefaultGen) PackageConsts(*Context) []string { return []string{} }
|
||||
func (d DefaultGen) GenerateType(*Context, *types.Type, io.Writer) error { return nil }
|
||||
func (d DefaultGen) Filename() string { return d.OptionalName + ".go" }
|
||||
func (d DefaultGen) FileType() string { return GolangFileType }
|
||||
func (d DefaultGen) Finalize(*Context, io.Writer) error { return nil }
|
||||
|
||||
func (d DefaultGen) Init(c *Context, w io.Writer) error {
|
||||
_, err := w.Write(d.OptionalBody)
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
_ = Generator(DefaultGen{})
|
||||
)
|
||||
75
vendor/k8s.io/gengo/generator/default_package.go
generated
vendored
75
vendor/k8s.io/gengo/generator/default_package.go
generated
vendored
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 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 generator
|
||||
|
||||
import (
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
// DefaultPackage contains a default implementation of Package.
|
||||
type DefaultPackage struct {
|
||||
// Short name of package, used in the "package xxxx" line.
|
||||
PackageName string
|
||||
// Import path of the package, and the location on disk of the package.
|
||||
PackagePath string
|
||||
// The location of the package on disk.
|
||||
Source string
|
||||
|
||||
// Emitted at the top of every file.
|
||||
HeaderText []byte
|
||||
|
||||
// Emitted only for a "doc.go" file; appended to the HeaderText for
|
||||
// that file.
|
||||
PackageDocumentation []byte
|
||||
|
||||
// If non-nil, will be called on "Generators"; otherwise, the static
|
||||
// list will be used. So you should set only one of these two fields.
|
||||
GeneratorFunc func(*Context) []Generator
|
||||
GeneratorList []Generator
|
||||
|
||||
// Optional; filters the types exposed to the generators.
|
||||
FilterFunc func(*Context, *types.Type) bool
|
||||
}
|
||||
|
||||
func (d *DefaultPackage) Name() string { return d.PackageName }
|
||||
func (d *DefaultPackage) Path() string { return d.PackagePath }
|
||||
func (d *DefaultPackage) SourcePath() string { return d.Source }
|
||||
|
||||
func (d *DefaultPackage) Filter(c *Context, t *types.Type) bool {
|
||||
if d.FilterFunc != nil {
|
||||
return d.FilterFunc(c, t)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *DefaultPackage) Generators(c *Context) []Generator {
|
||||
if d.GeneratorFunc != nil {
|
||||
return d.GeneratorFunc(c)
|
||||
}
|
||||
return d.GeneratorList
|
||||
}
|
||||
|
||||
func (d *DefaultPackage) Header(filename string) []byte {
|
||||
if filename == "doc.go" {
|
||||
return append(d.HeaderText, d.PackageDocumentation...)
|
||||
}
|
||||
return d.HeaderText
|
||||
}
|
||||
|
||||
var (
|
||||
_ = Package(&DefaultPackage{})
|
||||
)
|
||||
65
vendor/k8s.io/gengo/generator/transitive_closure.go
generated
vendored
65
vendor/k8s.io/gengo/generator/transitive_closure.go
generated
vendored
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 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 generator
|
||||
|
||||
import "sort"
|
||||
|
||||
type edge struct {
|
||||
from string
|
||||
to string
|
||||
}
|
||||
|
||||
func transitiveClosure(in map[string][]string) map[string][]string {
|
||||
adj := make(map[edge]bool)
|
||||
imports := make(map[string]struct{})
|
||||
for from, tos := range in {
|
||||
for _, to := range tos {
|
||||
adj[edge{from, to}] = true
|
||||
imports[to] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Warshal's algorithm
|
||||
for k := range in {
|
||||
for i := range in {
|
||||
if !adj[edge{i, k}] {
|
||||
continue
|
||||
}
|
||||
for j := range imports {
|
||||
if adj[edge{i, j}] {
|
||||
continue
|
||||
}
|
||||
if adj[edge{k, j}] {
|
||||
adj[edge{i, j}] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out := make(map[string][]string, len(in))
|
||||
for i := range in {
|
||||
for j := range imports {
|
||||
if adj[edge{i, j}] {
|
||||
out[i] = append(out[i], j)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(out[i])
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
925
vendor/k8s.io/gengo/parser/parse.go
generated
vendored
925
vendor/k8s.io/gengo/parser/parse.go
generated
vendored
@@ -1,925 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 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 parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/constant"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
tc "go/types"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// This clarifies when a pkg path has been canonicalized.
|
||||
type importPathString string
|
||||
|
||||
// Builder lets you add all the go files in all the packages that you care
|
||||
// about, then constructs the type source data.
|
||||
type Builder struct {
|
||||
context *build.Context
|
||||
|
||||
// If true, include *_test.go
|
||||
IncludeTestFiles bool
|
||||
|
||||
// Map of package names to more canonical information about the package.
|
||||
// This might hold the same value for multiple names, e.g. if someone
|
||||
// referenced ./pkg/name or in the case of vendoring, which canonicalizes
|
||||
// differently that what humans would type.
|
||||
//
|
||||
// This must only be accessed via getLoadedBuildPackage and setLoadedBuildPackage
|
||||
buildPackages map[importPathString]*build.Package
|
||||
|
||||
fset *token.FileSet
|
||||
// map of package path to list of parsed files
|
||||
parsed map[importPathString][]parsedFile
|
||||
// map of package path to absolute path (to prevent overlap)
|
||||
absPaths map[importPathString]string
|
||||
|
||||
// Set by typeCheckPackage(), used by importPackage() and friends.
|
||||
typeCheckedPackages map[importPathString]*tc.Package
|
||||
|
||||
// Map of package path to whether the user requested it or it was from
|
||||
// an import.
|
||||
userRequested map[importPathString]bool
|
||||
|
||||
// All comments from everywhere in every parsed file.
|
||||
endLineToCommentGroup map[fileLine]*ast.CommentGroup
|
||||
|
||||
// map of package to list of packages it imports.
|
||||
importGraph map[importPathString]map[string]struct{}
|
||||
}
|
||||
|
||||
// parsedFile is for tracking files with name
|
||||
type parsedFile struct {
|
||||
name string
|
||||
file *ast.File
|
||||
}
|
||||
|
||||
// key type for finding comments.
|
||||
type fileLine struct {
|
||||
file string
|
||||
line int
|
||||
}
|
||||
|
||||
// New constructs a new builder.
|
||||
func New() *Builder {
|
||||
c := build.Default
|
||||
if c.GOROOT == "" {
|
||||
if p, err := exec.Command("which", "go").CombinedOutput(); err == nil {
|
||||
// The returned string will have some/path/bin/go, so remove the last two elements.
|
||||
c.GOROOT = filepath.Dir(filepath.Dir(strings.Trim(string(p), "\n")))
|
||||
} else {
|
||||
klog.Warningf("Warning: $GOROOT not set, and unable to run `which go` to find it: %v\n", err)
|
||||
}
|
||||
}
|
||||
// Force this to off, since we don't properly parse CGo. All symbols must
|
||||
// have non-CGo equivalents.
|
||||
c.CgoEnabled = false
|
||||
return &Builder{
|
||||
context: &c,
|
||||
buildPackages: map[importPathString]*build.Package{},
|
||||
typeCheckedPackages: map[importPathString]*tc.Package{},
|
||||
fset: token.NewFileSet(),
|
||||
parsed: map[importPathString][]parsedFile{},
|
||||
absPaths: map[importPathString]string{},
|
||||
userRequested: map[importPathString]bool{},
|
||||
endLineToCommentGroup: map[fileLine]*ast.CommentGroup{},
|
||||
importGraph: map[importPathString]map[string]struct{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// AddBuildTags adds the specified build tags to the parse context.
|
||||
func (b *Builder) AddBuildTags(tags ...string) {
|
||||
b.context.BuildTags = append(b.context.BuildTags, tags...)
|
||||
}
|
||||
|
||||
func (b *Builder) getLoadedBuildPackage(importPath string) (*build.Package, bool) {
|
||||
canonicalized := canonicalizeImportPath(importPath)
|
||||
if string(canonicalized) != importPath {
|
||||
klog.V(5).Infof("getLoadedBuildPackage: %s normalized to %s", importPath, canonicalized)
|
||||
}
|
||||
buildPkg, ok := b.buildPackages[canonicalized]
|
||||
return buildPkg, ok
|
||||
}
|
||||
func (b *Builder) setLoadedBuildPackage(importPath string, buildPkg *build.Package) {
|
||||
canonicalizedImportPath := canonicalizeImportPath(importPath)
|
||||
if string(canonicalizedImportPath) != importPath {
|
||||
klog.V(5).Infof("setLoadedBuildPackage: importPath %s normalized to %s", importPath, canonicalizedImportPath)
|
||||
}
|
||||
|
||||
canonicalizedBuildPkgImportPath := canonicalizeImportPath(buildPkg.ImportPath)
|
||||
if string(canonicalizedBuildPkgImportPath) != buildPkg.ImportPath {
|
||||
klog.V(5).Infof("setLoadedBuildPackage: buildPkg.ImportPath %s normalized to %s", buildPkg.ImportPath, canonicalizedBuildPkgImportPath)
|
||||
}
|
||||
|
||||
if canonicalizedImportPath != canonicalizedBuildPkgImportPath {
|
||||
klog.V(5).Infof("setLoadedBuildPackage: normalized importPath (%s) differs from buildPkg.ImportPath (%s)", canonicalizedImportPath, canonicalizedBuildPkgImportPath)
|
||||
}
|
||||
b.buildPackages[canonicalizedImportPath] = buildPkg
|
||||
b.buildPackages[canonicalizedBuildPkgImportPath] = buildPkg
|
||||
}
|
||||
|
||||
// Get package information from the go/build package. Automatically excludes
|
||||
// e.g. test files and files for other platforms-- there is quite a bit of
|
||||
// logic of that nature in the build package.
|
||||
func (b *Builder) importBuildPackage(dir string) (*build.Package, error) {
|
||||
if buildPkg, ok := b.getLoadedBuildPackage(dir); ok {
|
||||
return buildPkg, nil
|
||||
}
|
||||
// This validates the `package foo // github.com/bar/foo` comments.
|
||||
buildPkg, err := b.importWithMode(dir, build.ImportComment)
|
||||
if err != nil {
|
||||
if _, ok := err.(*build.NoGoError); !ok {
|
||||
return nil, fmt.Errorf("unable to import %q: %v", dir, err)
|
||||
}
|
||||
}
|
||||
if buildPkg == nil {
|
||||
// Might be an empty directory. Try to just find the dir.
|
||||
buildPkg, err = b.importWithMode(dir, build.FindOnly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Remember it under the user-provided name.
|
||||
klog.V(5).Infof("saving buildPackage %s", dir)
|
||||
b.setLoadedBuildPackage(dir, buildPkg)
|
||||
|
||||
return buildPkg, nil
|
||||
}
|
||||
|
||||
// AddFileForTest adds a file to the set, without verifying that the provided
|
||||
// pkg actually exists on disk. The pkg must be of the form "canonical/pkg/path"
|
||||
// and the path must be the absolute path to the file. Because this bypasses
|
||||
// the normal recursive finding of package dependencies (on disk), test should
|
||||
// sort their test files topologically first, so all deps are resolved by the
|
||||
// time we need them.
|
||||
func (b *Builder) AddFileForTest(pkg string, path string, src []byte) error {
|
||||
if err := b.addFile(importPathString(pkg), path, src, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.typeCheckPackage(importPathString(pkg), true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// addFile adds a file to the set. The pkgPath must be of the form
|
||||
// "canonical/pkg/path" and the path must be the absolute path to the file. A
|
||||
// flag indicates whether this file was user-requested or just from following
|
||||
// the import graph.
|
||||
func (b *Builder) addFile(pkgPath importPathString, path string, src []byte, userRequested bool) error {
|
||||
for _, p := range b.parsed[pkgPath] {
|
||||
if path == p.name {
|
||||
klog.V(5).Infof("addFile %s %s already parsed, skipping", pkgPath, path)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
klog.V(6).Infof("addFile %s %s", pkgPath, path)
|
||||
p, err := parser.ParseFile(b.fset, path, src, parser.DeclarationErrors|parser.ParseComments)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This is redundant with addDir, but some tests call AddFileForTest, which
|
||||
// call into here without calling addDir.
|
||||
b.userRequested[pkgPath] = userRequested || b.userRequested[pkgPath]
|
||||
|
||||
b.parsed[pkgPath] = append(b.parsed[pkgPath], parsedFile{path, p})
|
||||
for _, c := range p.Comments {
|
||||
position := b.fset.Position(c.End())
|
||||
b.endLineToCommentGroup[fileLine{position.Filename, position.Line}] = c
|
||||
}
|
||||
|
||||
// We have to get the packages from this specific file, in case the
|
||||
// user added individual files instead of entire directories.
|
||||
if b.importGraph[pkgPath] == nil {
|
||||
b.importGraph[pkgPath] = map[string]struct{}{}
|
||||
}
|
||||
for _, im := range p.Imports {
|
||||
importedPath := strings.Trim(im.Path.Value, `"`)
|
||||
b.importGraph[pkgPath][importedPath] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDir adds an entire directory, scanning it for go files. 'dir' should have
|
||||
// a single go package in it. GOPATH, GOROOT, and the location of your go
|
||||
// binary (`which go`) will all be searched if dir doesn't literally resolve.
|
||||
func (b *Builder) AddDir(dir string) error {
|
||||
_, err := b.importPackage(dir, true)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddDirRecursive is just like AddDir, but it also recursively adds
|
||||
// subdirectories; it returns an error only if the path couldn't be resolved;
|
||||
// any directories recursed into without go source are ignored.
|
||||
func (b *Builder) AddDirRecursive(dir string) error {
|
||||
// Add the root.
|
||||
if _, err := b.importPackage(dir, true); err != nil {
|
||||
klog.Warningf("Ignoring directory %v: %v", dir, err)
|
||||
}
|
||||
|
||||
// filepath.Walk does not follow symlinks. We therefore evaluate symlinks and use that with
|
||||
// filepath.Walk.
|
||||
buildPkg, ok := b.getLoadedBuildPackage(dir)
|
||||
if !ok {
|
||||
return fmt.Errorf("no loaded build package for %s", dir)
|
||||
}
|
||||
realPath, err := filepath.EvalSymlinks(buildPkg.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fn := func(filePath string, info os.FileInfo, err error) error {
|
||||
if info != nil && info.IsDir() {
|
||||
rel := filepath.ToSlash(strings.TrimPrefix(filePath, realPath))
|
||||
if rel != "" {
|
||||
// Make a pkg path.
|
||||
buildPkg, ok := b.getLoadedBuildPackage(dir)
|
||||
if !ok {
|
||||
return fmt.Errorf("no loaded build package for %s", dir)
|
||||
}
|
||||
pkg := path.Join(string(canonicalizeImportPath(buildPkg.ImportPath)), rel)
|
||||
|
||||
// Add it.
|
||||
if _, err := b.importPackage(pkg, true); err != nil {
|
||||
klog.Warningf("Ignoring child directory %v: %v", pkg, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := filepath.Walk(realPath, fn); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDirTo adds an entire directory to a given Universe. Unlike AddDir, this
|
||||
// processes the package immediately, which makes it safe to use from within a
|
||||
// generator (rather than just at init time. 'dir' must be a single go package.
|
||||
// GOPATH, GOROOT, and the location of your go binary (`which go`) will all be
|
||||
// searched if dir doesn't literally resolve.
|
||||
// Deprecated. Please use AddDirectoryTo.
|
||||
func (b *Builder) AddDirTo(dir string, u *types.Universe) error {
|
||||
// We want all types from this package, as if they were directly added
|
||||
// by the user. They WERE added by the user, in effect.
|
||||
if _, err := b.importPackage(dir, true); err != nil {
|
||||
return err
|
||||
}
|
||||
pkg, ok := b.getLoadedBuildPackage(dir)
|
||||
if !ok {
|
||||
return fmt.Errorf("no such package: %q", dir)
|
||||
}
|
||||
return b.findTypesIn(canonicalizeImportPath(pkg.ImportPath), u)
|
||||
}
|
||||
|
||||
// AddDirectoryTo adds an entire directory to a given Universe. Unlike AddDir,
|
||||
// this processes the package immediately, which makes it safe to use from
|
||||
// within a generator (rather than just at init time. 'dir' must be a single go
|
||||
// package. GOPATH, GOROOT, and the location of your go binary (`which go`)
|
||||
// will all be searched if dir doesn't literally resolve.
|
||||
func (b *Builder) AddDirectoryTo(dir string, u *types.Universe) (*types.Package, error) {
|
||||
// We want all types from this package, as if they were directly added
|
||||
// by the user. They WERE added by the user, in effect.
|
||||
if _, err := b.importPackage(dir, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkg, ok := b.getLoadedBuildPackage(dir)
|
||||
if !ok || pkg == nil {
|
||||
return nil, fmt.Errorf("no such package: %q", dir)
|
||||
}
|
||||
path := canonicalizeImportPath(pkg.ImportPath)
|
||||
if err := b.findTypesIn(path, u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return u.Package(string(path)), nil
|
||||
}
|
||||
|
||||
// The implementation of AddDir. A flag indicates whether this directory was
|
||||
// user-requested or just from following the import graph.
|
||||
func (b *Builder) addDir(dir string, userRequested bool) error {
|
||||
klog.V(5).Infof("addDir %s", dir)
|
||||
buildPkg, err := b.importBuildPackage(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
canonicalPackage := canonicalizeImportPath(buildPkg.ImportPath)
|
||||
pkgPath := canonicalPackage
|
||||
if dir != string(canonicalPackage) {
|
||||
klog.V(5).Infof("addDir %s, canonical path is %s", dir, pkgPath)
|
||||
}
|
||||
|
||||
// Sanity check the pkg dir has not changed.
|
||||
if prev, found := b.absPaths[pkgPath]; found {
|
||||
if buildPkg.Dir != prev {
|
||||
return fmt.Errorf("package %q (%s) previously resolved to %s", pkgPath, buildPkg.Dir, prev)
|
||||
}
|
||||
} else {
|
||||
b.absPaths[pkgPath] = buildPkg.Dir
|
||||
}
|
||||
|
||||
files := []string{}
|
||||
files = append(files, buildPkg.GoFiles...)
|
||||
if b.IncludeTestFiles {
|
||||
files = append(files, buildPkg.TestGoFiles...)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if !strings.HasSuffix(file, ".go") {
|
||||
continue
|
||||
}
|
||||
absPath := filepath.Join(buildPkg.Dir, file)
|
||||
data, err := ioutil.ReadFile(absPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("while loading %q: %v", absPath, err)
|
||||
}
|
||||
err = b.addFile(pkgPath, absPath, data, userRequested)
|
||||
if err != nil {
|
||||
return fmt.Errorf("while parsing %q: %v", absPath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// regexErrPackageNotFound helps test the expected error for not finding a package.
|
||||
var regexErrPackageNotFound = regexp.MustCompile(`^unable to import ".*?":.*`)
|
||||
|
||||
func isErrPackageNotFound(err error) bool {
|
||||
return regexErrPackageNotFound.MatchString(err.Error())
|
||||
}
|
||||
|
||||
// importPackage is a function that will be called by the type check package when it
|
||||
// needs to import a go package. 'path' is the import path.
|
||||
func (b *Builder) importPackage(dir string, userRequested bool) (*tc.Package, error) {
|
||||
klog.V(5).Infof("importPackage %s", dir)
|
||||
|
||||
var pkgPath = importPathString(dir)
|
||||
|
||||
// Get the canonical path if we can.
|
||||
if buildPkg, _ := b.getLoadedBuildPackage(dir); buildPkg != nil {
|
||||
canonicalPackage := canonicalizeImportPath(buildPkg.ImportPath)
|
||||
klog.V(5).Infof("importPackage %s, canonical path is %s", dir, canonicalPackage)
|
||||
pkgPath = canonicalPackage
|
||||
}
|
||||
|
||||
// If we have not seen this before, process it now.
|
||||
ignoreError := false
|
||||
if _, found := b.parsed[pkgPath]; !found {
|
||||
// Ignore errors in paths that we're importing solely because
|
||||
// they're referenced by other packages.
|
||||
ignoreError = true
|
||||
|
||||
// Add it.
|
||||
if err := b.addDir(dir, userRequested); err != nil {
|
||||
if isErrPackageNotFound(err) {
|
||||
klog.V(6).Info(err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the canonical path now that it has been added.
|
||||
if buildPkg, _ := b.getLoadedBuildPackage(dir); buildPkg != nil {
|
||||
canonicalPackage := canonicalizeImportPath(buildPkg.ImportPath)
|
||||
klog.V(5).Infof("importPackage %s, canonical path is %s", dir, canonicalPackage)
|
||||
pkgPath = canonicalPackage
|
||||
}
|
||||
}
|
||||
|
||||
// If it was previously known, just check that the user-requestedness hasn't
|
||||
// changed.
|
||||
b.userRequested[pkgPath] = userRequested || b.userRequested[pkgPath]
|
||||
|
||||
// Run the type checker. We may end up doing this to pkgs that are already
|
||||
// done, or are in the queue to be done later, but it will short-circuit,
|
||||
// and we can't miss pkgs that are only depended on.
|
||||
pkg, err := b.typeCheckPackage(pkgPath, !ignoreError)
|
||||
if err != nil {
|
||||
switch {
|
||||
case ignoreError && pkg != nil:
|
||||
klog.V(4).Infof("type checking encountered some issues in %q, but ignoring.\n", pkgPath)
|
||||
case !ignoreError && pkg != nil:
|
||||
klog.V(3).Infof("type checking encountered some errors in %q\n", pkgPath)
|
||||
return nil, err
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
type importAdapter struct {
|
||||
b *Builder
|
||||
}
|
||||
|
||||
func (a importAdapter) Import(path string) (*tc.Package, error) {
|
||||
return a.b.importPackage(path, false)
|
||||
}
|
||||
|
||||
// typeCheckPackage will attempt to return the package even if there are some
|
||||
// errors, so you may check whether the package is nil or not even if you get
|
||||
// an error.
|
||||
func (b *Builder) typeCheckPackage(pkgPath importPathString, logErr bool) (*tc.Package, error) {
|
||||
klog.V(5).Infof("typeCheckPackage %s", pkgPath)
|
||||
if pkg, ok := b.typeCheckedPackages[pkgPath]; ok {
|
||||
if pkg != nil {
|
||||
klog.V(6).Infof("typeCheckPackage %s already done", pkgPath)
|
||||
return pkg, nil
|
||||
}
|
||||
// We store a nil right before starting work on a package. So
|
||||
// if we get here and it's present and nil, that means there's
|
||||
// another invocation of this function on the call stack
|
||||
// already processing this package.
|
||||
return nil, fmt.Errorf("circular dependency for %q", pkgPath)
|
||||
}
|
||||
parsedFiles, ok := b.parsed[pkgPath]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("No files for pkg %q", pkgPath)
|
||||
}
|
||||
files := make([]*ast.File, len(parsedFiles))
|
||||
for i := range parsedFiles {
|
||||
files[i] = parsedFiles[i].file
|
||||
}
|
||||
b.typeCheckedPackages[pkgPath] = nil
|
||||
c := tc.Config{
|
||||
IgnoreFuncBodies: true,
|
||||
// Note that importAdapter can call b.importPackage which calls this
|
||||
// method. So there can't be cycles in the import graph.
|
||||
Importer: importAdapter{b},
|
||||
Error: func(err error) {
|
||||
if logErr {
|
||||
klog.V(2).Infof("type checker: %v\n", err)
|
||||
} else {
|
||||
klog.V(3).Infof("type checker: %v\n", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
pkg, err := c.Check(string(pkgPath), b.fset, files, nil)
|
||||
b.typeCheckedPackages[pkgPath] = pkg // record the result whether or not there was an error
|
||||
return pkg, err
|
||||
}
|
||||
|
||||
// FindPackages fetches a list of the user-imported packages.
|
||||
// Note that you need to call b.FindTypes() first.
|
||||
func (b *Builder) FindPackages() []string {
|
||||
// Iterate packages in a predictable order.
|
||||
pkgPaths := []string{}
|
||||
for k := range b.typeCheckedPackages {
|
||||
pkgPaths = append(pkgPaths, string(k))
|
||||
}
|
||||
sort.Strings(pkgPaths)
|
||||
|
||||
result := []string{}
|
||||
for _, pkgPath := range pkgPaths {
|
||||
if b.userRequested[importPathString(pkgPath)] {
|
||||
// Since walkType is recursive, all types that are in packages that
|
||||
// were directly mentioned will be included. We don't need to
|
||||
// include all types in all transitive packages, though.
|
||||
result = append(result, pkgPath)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// FindTypes finalizes the package imports, and searches through all the
|
||||
// packages for types.
|
||||
func (b *Builder) FindTypes() (types.Universe, error) {
|
||||
// Take a snapshot of pkgs to iterate, since this will recursively mutate
|
||||
// b.parsed. Iterate in a predictable order.
|
||||
pkgPaths := []string{}
|
||||
for pkgPath := range b.parsed {
|
||||
pkgPaths = append(pkgPaths, string(pkgPath))
|
||||
}
|
||||
sort.Strings(pkgPaths)
|
||||
|
||||
u := types.Universe{}
|
||||
for _, pkgPath := range pkgPaths {
|
||||
if err := b.findTypesIn(importPathString(pkgPath), &u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// addCommentsToType takes any accumulated comment lines prior to obj and
|
||||
// attaches them to the type t.
|
||||
func (b *Builder) addCommentsToType(obj tc.Object, t *types.Type) {
|
||||
c1 := b.priorCommentLines(obj.Pos(), 1)
|
||||
// c1.Text() is safe if c1 is nil
|
||||
t.CommentLines = splitLines(c1.Text())
|
||||
if c1 == nil {
|
||||
t.SecondClosestCommentLines = splitLines(b.priorCommentLines(obj.Pos(), 2).Text())
|
||||
} else {
|
||||
t.SecondClosestCommentLines = splitLines(b.priorCommentLines(c1.List[0].Slash, 2).Text())
|
||||
}
|
||||
}
|
||||
|
||||
// findTypesIn finalizes the package import and searches through the package
|
||||
// for types.
|
||||
func (b *Builder) findTypesIn(pkgPath importPathString, u *types.Universe) error {
|
||||
klog.V(5).Infof("findTypesIn %s", pkgPath)
|
||||
pkg := b.typeCheckedPackages[pkgPath]
|
||||
if pkg == nil {
|
||||
return fmt.Errorf("findTypesIn(%s): package is not known", pkgPath)
|
||||
}
|
||||
if !b.userRequested[pkgPath] {
|
||||
// Since walkType is recursive, all types that the
|
||||
// packages they asked for depend on will be included.
|
||||
// But we don't need to include all types in all
|
||||
// *packages* they depend on.
|
||||
klog.V(5).Infof("findTypesIn %s: package is not user requested", pkgPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// We're keeping this package. This call will create the record.
|
||||
u.Package(string(pkgPath)).Name = pkg.Name()
|
||||
u.Package(string(pkgPath)).Path = pkg.Path()
|
||||
u.Package(string(pkgPath)).SourcePath = b.absPaths[pkgPath]
|
||||
|
||||
for _, f := range b.parsed[pkgPath] {
|
||||
if _, fileName := filepath.Split(f.name); fileName == "doc.go" {
|
||||
tp := u.Package(string(pkgPath))
|
||||
// findTypesIn might be called multiple times. Clean up tp.Comments
|
||||
// to avoid repeatedly fill same comments to it.
|
||||
tp.Comments = []string{}
|
||||
for i := range f.file.Comments {
|
||||
tp.Comments = append(tp.Comments, splitLines(f.file.Comments[i].Text())...)
|
||||
}
|
||||
if f.file.Doc != nil {
|
||||
tp.DocComments = splitLines(f.file.Doc.Text())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s := pkg.Scope()
|
||||
for _, n := range s.Names() {
|
||||
obj := s.Lookup(n)
|
||||
tn, ok := obj.(*tc.TypeName)
|
||||
if ok {
|
||||
t := b.walkType(*u, nil, tn.Type())
|
||||
b.addCommentsToType(obj, t)
|
||||
}
|
||||
tf, ok := obj.(*tc.Func)
|
||||
// We only care about functions, not concrete/abstract methods.
|
||||
if ok && tf.Type() != nil && tf.Type().(*tc.Signature).Recv() == nil {
|
||||
t := b.addFunction(*u, nil, tf)
|
||||
b.addCommentsToType(obj, t)
|
||||
}
|
||||
tv, ok := obj.(*tc.Var)
|
||||
if ok && !tv.IsField() {
|
||||
t := b.addVariable(*u, nil, tv)
|
||||
b.addCommentsToType(obj, t)
|
||||
}
|
||||
tconst, ok := obj.(*tc.Const)
|
||||
if ok {
|
||||
t := b.addConstant(*u, nil, tconst)
|
||||
b.addCommentsToType(obj, t)
|
||||
}
|
||||
}
|
||||
|
||||
importedPkgs := []string{}
|
||||
for k := range b.importGraph[pkgPath] {
|
||||
importedPkgs = append(importedPkgs, string(k))
|
||||
}
|
||||
sort.Strings(importedPkgs)
|
||||
for _, p := range importedPkgs {
|
||||
u.AddImports(string(pkgPath), p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) importWithMode(dir string, mode build.ImportMode) (*build.Package, error) {
|
||||
// This is a bit of a hack. The srcDir argument to Import() should
|
||||
// properly be the dir of the file which depends on the package to be
|
||||
// imported, so that vendoring can work properly and local paths can
|
||||
// resolve. We assume that there is only one level of vendoring, and that
|
||||
// the CWD is inside the GOPATH, so this should be safe. Nobody should be
|
||||
// using local (relative) paths except on the CLI, so CWD is also
|
||||
// sufficient.
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get current directory: %v", err)
|
||||
}
|
||||
|
||||
// normalize to drop /vendor/ if present
|
||||
dir = string(canonicalizeImportPath(dir))
|
||||
|
||||
buildPkg, err := b.context.Import(filepath.ToSlash(dir), cwd, mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buildPkg, nil
|
||||
}
|
||||
|
||||
// if there's a comment on the line `lines` before pos, return its text, otherwise "".
|
||||
func (b *Builder) priorCommentLines(pos token.Pos, lines int) *ast.CommentGroup {
|
||||
position := b.fset.Position(pos)
|
||||
key := fileLine{position.Filename, position.Line - lines}
|
||||
return b.endLineToCommentGroup[key]
|
||||
}
|
||||
|
||||
func splitLines(str string) []string {
|
||||
return strings.Split(strings.TrimRight(str, "\n"), "\n")
|
||||
}
|
||||
|
||||
func tcFuncNameToName(in string) types.Name {
|
||||
name := strings.TrimPrefix(in, "func ")
|
||||
nameParts := strings.Split(name, "(")
|
||||
return tcNameToName(nameParts[0])
|
||||
}
|
||||
|
||||
func tcVarNameToName(in string) types.Name {
|
||||
nameParts := strings.Split(in, " ")
|
||||
// nameParts[0] is "var".
|
||||
// nameParts[2:] is the type of the variable, we ignore it for now.
|
||||
return tcNameToName(nameParts[1])
|
||||
}
|
||||
|
||||
func tcNameToName(in string) types.Name {
|
||||
// Detect anonymous type names. (These may have '.' characters because
|
||||
// embedded types may have packages, so we detect them specially.)
|
||||
if strings.HasPrefix(in, "struct{") ||
|
||||
strings.HasPrefix(in, "<-chan") ||
|
||||
strings.HasPrefix(in, "chan<-") ||
|
||||
strings.HasPrefix(in, "chan ") ||
|
||||
strings.HasPrefix(in, "func(") ||
|
||||
strings.HasPrefix(in, "func (") ||
|
||||
strings.HasPrefix(in, "*") ||
|
||||
strings.HasPrefix(in, "map[") ||
|
||||
strings.HasPrefix(in, "[") {
|
||||
return types.Name{Name: in}
|
||||
}
|
||||
|
||||
// Otherwise, if there are '.' characters present, the name has a
|
||||
// package path in front.
|
||||
nameParts := strings.Split(in, ".")
|
||||
name := types.Name{Name: in}
|
||||
if n := len(nameParts); n >= 2 {
|
||||
// The final "." is the name of the type--previous ones must
|
||||
// have been in the package path.
|
||||
name.Package, name.Name = strings.Join(nameParts[:n-1], "."), nameParts[n-1]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (b *Builder) convertSignature(u types.Universe, t *tc.Signature) *types.Signature {
|
||||
signature := &types.Signature{}
|
||||
for i := 0; i < t.Params().Len(); i++ {
|
||||
signature.Parameters = append(signature.Parameters, b.walkType(u, nil, t.Params().At(i).Type()))
|
||||
signature.ParameterNames = append(signature.ParameterNames, t.Params().At(i).Name())
|
||||
}
|
||||
for i := 0; i < t.Results().Len(); i++ {
|
||||
signature.Results = append(signature.Results, b.walkType(u, nil, t.Results().At(i).Type()))
|
||||
signature.ResultNames = append(signature.ResultNames, t.Results().At(i).Name())
|
||||
}
|
||||
if r := t.Recv(); r != nil {
|
||||
signature.Receiver = b.walkType(u, nil, r.Type())
|
||||
}
|
||||
signature.Variadic = t.Variadic()
|
||||
return signature
|
||||
}
|
||||
|
||||
// walkType adds the type, and any necessary child types.
|
||||
func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *types.Type {
|
||||
// Most of the cases are underlying types of the named type.
|
||||
name := tcNameToName(in.String())
|
||||
if useName != nil {
|
||||
name = *useName
|
||||
}
|
||||
|
||||
switch t := in.(type) {
|
||||
case *tc.Struct:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Struct
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
f := t.Field(i)
|
||||
m := types.Member{
|
||||
Name: f.Name(),
|
||||
Embedded: f.Anonymous(),
|
||||
Tags: t.Tag(i),
|
||||
Type: b.walkType(u, nil, f.Type()),
|
||||
CommentLines: splitLines(b.priorCommentLines(f.Pos(), 1).Text()),
|
||||
}
|
||||
out.Members = append(out.Members, m)
|
||||
}
|
||||
return out
|
||||
case *tc.Map:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Map
|
||||
out.Elem = b.walkType(u, nil, t.Elem())
|
||||
out.Key = b.walkType(u, nil, t.Key())
|
||||
return out
|
||||
case *tc.Pointer:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Pointer
|
||||
out.Elem = b.walkType(u, nil, t.Elem())
|
||||
return out
|
||||
case *tc.Slice:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Slice
|
||||
out.Elem = b.walkType(u, nil, t.Elem())
|
||||
return out
|
||||
case *tc.Array:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Array
|
||||
out.Elem = b.walkType(u, nil, t.Elem())
|
||||
out.Len = in.(*tc.Array).Len()
|
||||
return out
|
||||
case *tc.Chan:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Chan
|
||||
out.Elem = b.walkType(u, nil, t.Elem())
|
||||
// TODO: need to store direction, otherwise raw type name
|
||||
// cannot be properly written.
|
||||
return out
|
||||
case *tc.Basic:
|
||||
out := u.Type(types.Name{
|
||||
Package: "",
|
||||
Name: t.Name(),
|
||||
})
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Unsupported
|
||||
return out
|
||||
case *tc.Signature:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Func
|
||||
out.Signature = b.convertSignature(u, t)
|
||||
return out
|
||||
case *tc.Interface:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Interface
|
||||
t.Complete()
|
||||
for i := 0; i < t.NumMethods(); i++ {
|
||||
if out.Methods == nil {
|
||||
out.Methods = map[string]*types.Type{}
|
||||
}
|
||||
method := t.Method(i)
|
||||
name := tcNameToName(method.String())
|
||||
mt := b.walkType(u, &name, method.Type())
|
||||
mt.CommentLines = splitLines(b.priorCommentLines(method.Pos(), 1).Text())
|
||||
out.Methods[method.Name()] = mt
|
||||
}
|
||||
return out
|
||||
case *tc.Named:
|
||||
var out *types.Type
|
||||
switch t.Underlying().(type) {
|
||||
case *tc.Named, *tc.Basic, *tc.Map, *tc.Slice:
|
||||
name := tcNameToName(t.String())
|
||||
out = u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Alias
|
||||
out.Underlying = b.walkType(u, nil, t.Underlying())
|
||||
default:
|
||||
// tc package makes everything "named" with an
|
||||
// underlying anonymous type--we remove that annoying
|
||||
// "feature" for users. This flattens those types
|
||||
// together.
|
||||
name := tcNameToName(t.String())
|
||||
if out := u.Type(name); out.Kind != types.Unknown {
|
||||
return out // short circuit if we've already made this.
|
||||
}
|
||||
out = b.walkType(u, &name, t.Underlying())
|
||||
}
|
||||
// If the underlying type didn't already add methods, add them.
|
||||
// (Interface types will have already added methods.)
|
||||
if len(out.Methods) == 0 {
|
||||
for i := 0; i < t.NumMethods(); i++ {
|
||||
if out.Methods == nil {
|
||||
out.Methods = map[string]*types.Type{}
|
||||
}
|
||||
method := t.Method(i)
|
||||
name := tcNameToName(method.String())
|
||||
mt := b.walkType(u, &name, method.Type())
|
||||
mt.CommentLines = splitLines(b.priorCommentLines(method.Pos(), 1).Text())
|
||||
out.Methods[method.Name()] = mt
|
||||
}
|
||||
}
|
||||
return out
|
||||
default:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Unsupported
|
||||
klog.Warningf("Making unsupported type entry %q for: %#v\n", out, t)
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) addFunction(u types.Universe, useName *types.Name, in *tc.Func) *types.Type {
|
||||
name := tcFuncNameToName(in.String())
|
||||
if useName != nil {
|
||||
name = *useName
|
||||
}
|
||||
out := u.Function(name)
|
||||
out.Kind = types.DeclarationOf
|
||||
out.Underlying = b.walkType(u, nil, in.Type())
|
||||
return out
|
||||
}
|
||||
|
||||
func (b *Builder) addVariable(u types.Universe, useName *types.Name, in *tc.Var) *types.Type {
|
||||
name := tcVarNameToName(in.String())
|
||||
if useName != nil {
|
||||
name = *useName
|
||||
}
|
||||
out := u.Variable(name)
|
||||
out.Kind = types.DeclarationOf
|
||||
out.Underlying = b.walkType(u, nil, in.Type())
|
||||
return out
|
||||
}
|
||||
|
||||
func (b *Builder) addConstant(u types.Universe, useName *types.Name, in *tc.Const) *types.Type {
|
||||
name := tcVarNameToName(in.String())
|
||||
if useName != nil {
|
||||
name = *useName
|
||||
}
|
||||
out := u.Constant(name)
|
||||
out.Kind = types.DeclarationOf
|
||||
out.Underlying = b.walkType(u, nil, in.Type())
|
||||
|
||||
var constval string
|
||||
|
||||
// For strings, we use `StringVal()` to get the un-truncated,
|
||||
// un-quoted string. For other values, `.String()` is preferable to
|
||||
// get something relatively human readable (especially since for
|
||||
// floating point types, `ExactString()` will generate numeric
|
||||
// expressions using `big.(*Float).Text()`.
|
||||
switch in.Val().Kind() {
|
||||
case constant.String:
|
||||
constval = constant.StringVal(in.Val())
|
||||
default:
|
||||
constval = in.Val().String()
|
||||
}
|
||||
|
||||
out.ConstValue = &constval
|
||||
return out
|
||||
}
|
||||
|
||||
// canonicalizeImportPath takes an import path and returns the actual package.
|
||||
// It doesn't support nested vendoring.
|
||||
func canonicalizeImportPath(importPath string) importPathString {
|
||||
if !strings.Contains(importPath, "/vendor/") {
|
||||
return importPathString(importPath)
|
||||
}
|
||||
|
||||
return importPathString(importPath[strings.Index(importPath, "/vendor/")+len("/vendor/"):])
|
||||
}
|
||||
57
vendor/k8s.io/gengo/types/flatten.go
generated
vendored
57
vendor/k8s.io/gengo/types/flatten.go
generated
vendored
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 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 types
|
||||
|
||||
// FlattenMembers recursively takes any embedded members and puts them in the
|
||||
// top level, correctly hiding them if the top level hides them. There must not
|
||||
// be a cycle-- that implies infinite members.
|
||||
//
|
||||
// This is useful for e.g. computing all the valid keys in a json struct,
|
||||
// properly considering any configuration of embedded structs.
|
||||
func FlattenMembers(m []Member) []Member {
|
||||
embedded := []Member{}
|
||||
normal := []Member{}
|
||||
type nameInfo struct {
|
||||
top bool
|
||||
i int
|
||||
}
|
||||
names := map[string]nameInfo{}
|
||||
for i := range m {
|
||||
if m[i].Embedded && m[i].Type.Kind == Struct {
|
||||
embedded = append(embedded, m[i])
|
||||
} else {
|
||||
normal = append(normal, m[i])
|
||||
names[m[i].Name] = nameInfo{true, len(normal) - 1}
|
||||
}
|
||||
}
|
||||
for i := range embedded {
|
||||
for _, e := range FlattenMembers(embedded[i].Type.Members) {
|
||||
if info, found := names[e.Name]; found {
|
||||
if info.top {
|
||||
continue
|
||||
}
|
||||
if n := normal[info.i]; n.Name == e.Name && n.Type == e.Type {
|
||||
continue
|
||||
}
|
||||
panic("conflicting members")
|
||||
}
|
||||
normal = append(normal, e)
|
||||
names[e.Name] = nameInfo{false, len(normal) - 1}
|
||||
}
|
||||
}
|
||||
return normal
|
||||
}
|
||||
0
vendor/k8s.io/gengo/LICENSE → vendor/k8s.io/gengo/v2/LICENSE
generated
vendored
0
vendor/k8s.io/gengo/LICENSE → vendor/k8s.io/gengo/v2/LICENSE
generated
vendored
53
vendor/k8s.io/gengo/v2/README.md
generated
vendored
Normal file
53
vendor/k8s.io/gengo/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
[![GoDoc Widget]][GoDoc] [![GoReport]][GoReportStatus]
|
||||
|
||||
[GoDoc]: https://godoc.org/k8s.io/gengo
|
||||
[GoDoc Widget]: https://godoc.org/k8s.io/gengo?status.svg
|
||||
[GoReport]: https://goreportcard.com/badge/github.com/kubernetes/gengo
|
||||
[GoReportStatus]: https://goreportcard.com/report/github.com/kubernetes/gengo
|
||||
|
||||
# Gengo: a framework for building simple code generators
|
||||
|
||||
This repo is used by Kubernetes to build some codegen tooling. It is not
|
||||
intended to be general-purpose and makes some assumptions that may not hold
|
||||
outside of Kubernetes.
|
||||
|
||||
In the past this repo was partially supported for external use (outside of the
|
||||
Kubernetes project overall), but that is no longer true. We may change the API
|
||||
in incompatible ways, without warning.
|
||||
|
||||
If you are not building something that is part of Kubernetes, DO NOT DEPEND ON
|
||||
THIS REPO.
|
||||
|
||||
## New usage within Kubernetes
|
||||
|
||||
Gengo is a very opinionated framework. It is primarily aimed at generating Go
|
||||
code derived from types defined in other Go code, but it is possible to use it
|
||||
for other things (e.g. proto files). Net new tools should consider using
|
||||
`golang.org/x/tools/go/packages` directly. Gengo can serve as an example of
|
||||
how to do that.
|
||||
|
||||
If you still decide you want to use gengo, see the
|
||||
[simple examples](./examples) in this repo or the more extensive tools in the
|
||||
Kubernetes [code-generator](https://github.com/kubernetes/code-generator/)
|
||||
repo.
|
||||
|
||||
## Overview
|
||||
|
||||
Gengo is used to build tools (generally a tool is a binary). Each tool
|
||||
describes some number of `Targets`. A target is a single output package, which
|
||||
may be the same as the inputs (if the tool generates code alongside the inputs)
|
||||
or different. Each `Target` describes some number of `Generators`. A
|
||||
generator is responsible for emitting a single file into the target directory.
|
||||
|
||||
Gengo helps the tool to load and process input packages, e.g. extracting type
|
||||
information and associating comments. Each target will be offered every known
|
||||
type, and can filter that down to the set of types it cares about. Each
|
||||
generator will be offered the result of the target's filtering, and can filter
|
||||
the set of types further. Finally, the generator will be called to emit code
|
||||
for all of the remaining types.
|
||||
|
||||
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.
|
||||
21
vendor/k8s.io/gengo/types/comments.go → vendor/k8s.io/gengo/v2/comments.go
generated
vendored
21
vendor/k8s.io/gengo/types/comments.go → vendor/k8s.io/gengo/v2/comments.go
generated
vendored
@@ -14,9 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package types contains go type information, packaged in a way that makes
|
||||
// auto-generation convenient, whether by template or straight go functions.
|
||||
package types
|
||||
package gengo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -25,7 +23,7 @@ import (
|
||||
|
||||
// ExtractCommentTags parses comments for lines of the form:
|
||||
//
|
||||
// 'marker' + "key=value".
|
||||
// 'marker' + "key=value".
|
||||
//
|
||||
// Values are optional; "" is the default. A tag can be specified more than
|
||||
// one time and all values are returned. If the resulting map has an entry for
|
||||
@@ -33,12 +31,15 @@ import (
|
||||
//
|
||||
// Example: if you pass "+" for 'marker', and the following lines are in
|
||||
// the comments:
|
||||
// +foo=value1
|
||||
// +bar
|
||||
// +foo=value2
|
||||
// +baz="qux"
|
||||
//
|
||||
// +foo=value1
|
||||
// +bar
|
||||
// +foo=value2
|
||||
// +baz="qux"
|
||||
//
|
||||
// Then this function will return:
|
||||
// map[string][]string{"foo":{"value1, "value2"}, "bar": {""}, "baz": {"qux"}}
|
||||
//
|
||||
// map[string][]string{"foo":{"value1, "value2"}, "bar": {""}, "baz": {"qux"}}
|
||||
func ExtractCommentTags(marker string, lines []string) map[string][]string {
|
||||
out := map[string][]string{}
|
||||
for _, line := range lines {
|
||||
@@ -62,7 +63,7 @@ func ExtractCommentTags(marker string, lines []string) map[string][]string {
|
||||
|
||||
// ExtractSingleBoolCommentTag parses comments for lines of the form:
|
||||
//
|
||||
// 'marker' + "key=value1"
|
||||
// 'marker' + "key=value1"
|
||||
//
|
||||
// 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
|
||||
98
vendor/k8s.io/gengo/v2/execute.go
generated
vendored
Normal file
98
vendor/k8s.io/gengo/v2/execute.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright 2015 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 gengo is a code-generation framework.
|
||||
package gengo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/gengo/v2/generator"
|
||||
"k8s.io/gengo/v2/namer"
|
||||
"k8s.io/gengo/v2/parser"
|
||||
)
|
||||
|
||||
// StdBuildTag is a suggested build-tag which tools can use both as an argument
|
||||
// to GoBoilerplate and to Execute.
|
||||
const StdBuildTag = "ignore_autogenerated"
|
||||
|
||||
// StdGeneratedBy is a suggested "generated by" line which tools can use as an
|
||||
// argument to GoBoilerplate.
|
||||
const StdGeneratedBy = "// Code generated by GENERATOR_NAME. DO NOT EDIT."
|
||||
|
||||
// GoBoilerplate returns the Go file header:
|
||||
// - an optional build tag (negative, set it to ignore generated code)
|
||||
// - an optional boilerplate file
|
||||
// - an optional "generated by" comment
|
||||
func GoBoilerplate(headerFile, buildTag, generatedBy string) ([]byte, error) {
|
||||
buf := bytes.Buffer{}
|
||||
|
||||
if buildTag != "" {
|
||||
buf.WriteString(
|
||||
fmt.Sprintf("//go:build !%s\n// +build !%s\n\n", buildTag, buildTag))
|
||||
}
|
||||
|
||||
if headerFile != "" {
|
||||
b, err := os.ReadFile(headerFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = bytes.ReplaceAll(b, []byte("YEAR"), []byte(strconv.Itoa(time.Now().UTC().Year())))
|
||||
buf.Write(b)
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
|
||||
if generatedBy != "" {
|
||||
generatorName := filepath.Base(os.Args[0])
|
||||
// Strip the extension from the name to normalize output between *nix and Windows.
|
||||
generatorName = generatorName[:len(generatorName)-len(filepath.Ext(generatorName))]
|
||||
generatedByComment := strings.ReplaceAll(generatedBy, "GENERATOR_NAME", generatorName)
|
||||
buf.WriteString(fmt.Sprintf("%s\n\n", generatedByComment))
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Execute implements most of a tool's main loop.
|
||||
func Execute(nameSystems namer.NameSystems, defaultSystem string, getTargets func(*generator.Context) []generator.Target, buildTag string, patterns []string) error {
|
||||
var buildTags []string
|
||||
if buildTag != "" {
|
||||
buildTags = append(buildTags, buildTag)
|
||||
}
|
||||
|
||||
p := parser.NewWithOptions(parser.Options{BuildTags: buildTags})
|
||||
if err := p.LoadPackages(patterns...); err != nil {
|
||||
return fmt.Errorf("failed making a parser: %v", err)
|
||||
}
|
||||
|
||||
c, err := generator.NewContext(p, nameSystems, defaultSystem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed making a context: %v", err)
|
||||
}
|
||||
|
||||
targets := getTargets(c)
|
||||
if err := c.ExecuteTargets(targets); err != nil {
|
||||
return fmt.Errorf("failed executing generator: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
2
vendor/k8s.io/gengo/generator/doc.go → vendor/k8s.io/gengo/v2/generator/doc.go
generated
vendored
2
vendor/k8s.io/gengo/generator/doc.go → vendor/k8s.io/gengo/v2/generator/doc.go
generated
vendored
@@ -28,4 +28,4 @@ limitations under the License.
|
||||
// package. Additionally, all naming systems in the Context will be added as
|
||||
// functions to the parsed template, so that they can be called directly from
|
||||
// your templates!
|
||||
package generator // import "k8s.io/gengo/generator"
|
||||
package generator // import "k8s.io/gengo/v2/generator"
|
||||
155
vendor/k8s.io/gengo/generator/execute.go → vendor/k8s.io/gengo/v2/generator/execute.go
generated
vendored
155
vendor/k8s.io/gengo/generator/execute.go → vendor/k8s.io/gengo/v2/generator/execute.go
generated
vendored
@@ -18,42 +18,31 @@ package generator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/imports"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/gengo/v2/namer"
|
||||
"k8s.io/gengo/v2/types"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
func errs2strings(errors []error) []string {
|
||||
strs := make([]string, len(errors))
|
||||
for i := range errors {
|
||||
strs[i] = errors[i].Error()
|
||||
}
|
||||
return strs
|
||||
}
|
||||
// ExecuteTargets runs the generators for the provided targets.
|
||||
func (c *Context) ExecuteTargets(targets []Target) error {
|
||||
klog.V(5).Infof("ExecuteTargets: %d targets", len(targets))
|
||||
|
||||
// ExecutePackages runs the generators for every package in 'packages'. 'outDir'
|
||||
// is the base directory in which to place all the generated packages; it
|
||||
// should be a physical path on disk, not an import path. e.g.:
|
||||
// /path/to/home/path/to/gopath/src/
|
||||
// Each package has its import path already, this will be appended to 'outDir'.
|
||||
func (c *Context) ExecutePackages(outDir string, packages Packages) error {
|
||||
var errors []error
|
||||
for _, p := range packages {
|
||||
if err := c.ExecutePackage(outDir, p); err != nil {
|
||||
errors = append(errors, err)
|
||||
var errs []error
|
||||
for _, tgt := range targets {
|
||||
if err := c.ExecuteTarget(tgt); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return fmt.Errorf("some packages had errors:\n%v\n", strings.Join(errs2strings(errors), "\n"))
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("some targets had errors: %w", errors.Join(errs...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -65,6 +54,7 @@ type DefaultFileType struct {
|
||||
|
||||
func (ft DefaultFileType) AssembleFile(f *File, pathname string) error {
|
||||
klog.V(5).Infof("Assembling file %q", pathname)
|
||||
|
||||
destFile, err := os.Create(pathname)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -78,7 +68,7 @@ func (ft DefaultFileType) AssembleFile(f *File, pathname string) error {
|
||||
return et.Error()
|
||||
}
|
||||
if formatted, err := ft.Format(b.Bytes()); err != nil {
|
||||
err = fmt.Errorf("unable to format file %q (%v).", pathname, err)
|
||||
err = fmt.Errorf("unable to format file %q (%v)", pathname, err)
|
||||
// Write the file anyway, so they can see what's going wrong and fix the generator.
|
||||
if _, err2 := destFile.Write(b.Bytes()); err2 != nil {
|
||||
return err2
|
||||
@@ -90,42 +80,7 @@ func (ft DefaultFileType) AssembleFile(f *File, pathname string) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (ft DefaultFileType) VerifyFile(f *File, pathname string) error {
|
||||
klog.V(5).Infof("Verifying file %q", pathname)
|
||||
friendlyName := filepath.Join(f.PackageName, f.Name)
|
||||
b := &bytes.Buffer{}
|
||||
et := NewErrorTracker(b)
|
||||
ft.Assemble(et, f)
|
||||
if et.Error() != nil {
|
||||
return et.Error()
|
||||
}
|
||||
formatted, err := ft.Format(b.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to format the output for %q: %v", friendlyName, err)
|
||||
}
|
||||
existing, err := ioutil.ReadFile(pathname)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read file %q for comparison: %v", friendlyName, err)
|
||||
}
|
||||
if bytes.Compare(formatted, existing) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Be nice and find the first place where they differ
|
||||
i := 0
|
||||
for i < len(formatted) && i < len(existing) && formatted[i] == existing[i] {
|
||||
i++
|
||||
}
|
||||
eDiff, fDiff := existing[i:], formatted[i:]
|
||||
if len(eDiff) > 100 {
|
||||
eDiff = eDiff[:100]
|
||||
}
|
||||
if len(fDiff) > 100 {
|
||||
fDiff = fDiff[:100]
|
||||
}
|
||||
return fmt.Errorf("output for %q differs; first existing/expected diff: \n %q\n %q", friendlyName, string(eDiff), string(fDiff))
|
||||
}
|
||||
|
||||
func assembleGolangFile(w io.Writer, f *File) {
|
||||
func assembleGoFile(w io.Writer, f *File) {
|
||||
w.Write(f.Header)
|
||||
fmt.Fprintf(w, "package %v\n\n", f.PackageName)
|
||||
|
||||
@@ -162,10 +117,10 @@ func importsWrapper(src []byte) ([]byte, error) {
|
||||
return imports.Process("", src, nil)
|
||||
}
|
||||
|
||||
func NewGolangFile() *DefaultFileType {
|
||||
func NewGoFile() *DefaultFileType {
|
||||
return &DefaultFileType{
|
||||
Format: importsWrapper,
|
||||
Assemble: assembleGolangFile,
|
||||
Assemble: assembleGoFile,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,33 +163,23 @@ func (c *Context) addNameSystems(namers namer.NameSystems) *Context {
|
||||
return &c2
|
||||
}
|
||||
|
||||
// ExecutePackage executes a single package. 'outDir' is the base directory in
|
||||
// which to place the package; it should be a physical path on disk, not an
|
||||
// import path. e.g.: '/path/to/home/path/to/gopath/src/' The package knows its
|
||||
// import path already, this will be appended to 'outDir'.
|
||||
func (c *Context) ExecutePackage(outDir string, p Package) error {
|
||||
path := filepath.Join(outDir, p.Path())
|
||||
|
||||
// When working outside of GOPATH, we typically won't want to generate the
|
||||
// full path for a package. For example, if our current project's root/base
|
||||
// package is github.com/foo/bar, outDir=., p.Path()=github.com/foo/bar/generated,
|
||||
// then we really want to be writing files to ./generated, not ./github.com/foo/bar/generated.
|
||||
// The following will trim a path prefix (github.com/foo/bar) from p.Path() to arrive at
|
||||
// a relative path that works with projects not in GOPATH.
|
||||
if c.TrimPathPrefix != "" {
|
||||
separator := string(filepath.Separator)
|
||||
if !strings.HasSuffix(c.TrimPathPrefix, separator) {
|
||||
c.TrimPathPrefix += separator
|
||||
}
|
||||
|
||||
path = strings.TrimPrefix(path, c.TrimPathPrefix)
|
||||
// ExecuteTarget runs the generators for a single target.
|
||||
func (c *Context) ExecuteTarget(tgt Target) error {
|
||||
tgtDir := tgt.Dir()
|
||||
if tgtDir == "" {
|
||||
return fmt.Errorf("no directory for target %s", tgt.Path())
|
||||
}
|
||||
klog.V(5).Infof("Processing package %q, disk location %q", p.Name(), path)
|
||||
klog.V(5).Infof("Executing target %q (%q)", tgt.Name(), tgtDir)
|
||||
|
||||
// Filter out any types the *package* doesn't care about.
|
||||
packageContext := c.filteredBy(p.Filter)
|
||||
os.MkdirAll(path, 0755)
|
||||
packageContext := c.filteredBy(tgt.Filter)
|
||||
|
||||
if err := os.MkdirAll(tgtDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
files := map[string]*File{}
|
||||
for _, g := range p.Generators(packageContext) {
|
||||
for _, g := range tgt.Generators(packageContext) {
|
||||
// Filter out types the *generator* doesn't care about.
|
||||
genContext := packageContext.filteredBy(g.Filter)
|
||||
// Now add any extra name systems defined by this generator
|
||||
@@ -248,19 +193,17 @@ func (c *Context) ExecutePackage(outDir string, p Package) error {
|
||||
if f == nil {
|
||||
// This is the first generator to reference this file, so start it.
|
||||
f = &File{
|
||||
Name: g.Filename(),
|
||||
FileType: fileType,
|
||||
PackageName: p.Name(),
|
||||
PackagePath: p.Path(),
|
||||
PackageSourcePath: p.SourcePath(),
|
||||
Header: p.Header(g.Filename()),
|
||||
Imports: map[string]struct{}{},
|
||||
Name: g.Filename(),
|
||||
FileType: fileType,
|
||||
PackageName: tgt.Name(),
|
||||
PackagePath: tgt.Path(),
|
||||
PackageDir: tgt.Dir(),
|
||||
Header: tgt.Header(g.Filename()),
|
||||
Imports: map[string]struct{}{},
|
||||
}
|
||||
files[f.Name] = f
|
||||
} else {
|
||||
if f.FileType != g.FileType() {
|
||||
return fmt.Errorf("file %q already has type %q, but generator %q wants to use type %q", f.Name, f.FileType, g.Name(), g.FileType())
|
||||
}
|
||||
} else if f.FileType != g.FileType() {
|
||||
return fmt.Errorf("file %q already has type %q, but generator %q wants to use type %q", f.Name, f.FileType, g.Name(), g.FileType())
|
||||
}
|
||||
|
||||
if vars := g.PackageVars(genContext); len(vars) > 0 {
|
||||
@@ -289,25 +232,19 @@ func (c *Context) ExecutePackage(outDir string, p Package) error {
|
||||
}
|
||||
}
|
||||
|
||||
var errors []error
|
||||
var errs []error
|
||||
for _, f := range files {
|
||||
finalPath := filepath.Join(path, f.Name)
|
||||
finalPath := filepath.Join(tgtDir, f.Name)
|
||||
assembler, ok := c.FileTypes[f.FileType]
|
||||
if !ok {
|
||||
return fmt.Errorf("the file type %q registered for file %q does not exist in the context", f.FileType, f.Name)
|
||||
}
|
||||
var err error
|
||||
if c.Verify {
|
||||
err = assembler.VerifyFile(f, finalPath)
|
||||
} else {
|
||||
err = assembler.AssembleFile(f, finalPath)
|
||||
}
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
if err := assembler.AssembleFile(f, finalPath); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return fmt.Errorf("errors in package %q:\n%v\n", p.Path(), strings.Join(errs2strings(errors), "\n"))
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("errors in target %q: %w", tgt.Path(), errors.Join(errs...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
123
vendor/k8s.io/gengo/generator/generator.go → vendor/k8s.io/gengo/v2/generator/generator.go
generated
vendored
123
vendor/k8s.io/gengo/generator/generator.go → vendor/k8s.io/gengo/v2/generator/generator.go
generated
vendored
@@ -20,19 +20,22 @@ import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/parser"
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/gengo/v2/namer"
|
||||
"k8s.io/gengo/v2/parser"
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
// Package contains the contract for generating a package.
|
||||
type Package interface {
|
||||
// Name returns the package short name.
|
||||
// Target describes a Go package into which code will be generated. A single
|
||||
// Target may have many Generators, each of which emits one file.
|
||||
type Target interface {
|
||||
// Name returns the package short name (as in `package foo`).
|
||||
Name() string
|
||||
// Path returns the package import path.
|
||||
// Path returns the package import path (as in `import "example.com/foo"`).
|
||||
Path() string
|
||||
// SourcePath returns the location of the package on disk.
|
||||
SourcePath() string
|
||||
// Dir returns the location of the resulting package on disk. This may be
|
||||
// the same directory as an input package (when generating code in-place)
|
||||
// or a different directory entirely.
|
||||
Dir() string
|
||||
|
||||
// Filter should return true if this package cares about this type.
|
||||
// Otherwise, this type will be omitted from the type ordering for
|
||||
@@ -52,26 +55,22 @@ type Package interface {
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Name string
|
||||
FileType string
|
||||
PackageName string
|
||||
Header []byte
|
||||
PackagePath string
|
||||
PackageSourcePath string
|
||||
Imports map[string]struct{}
|
||||
Vars bytes.Buffer
|
||||
Consts bytes.Buffer
|
||||
Body bytes.Buffer
|
||||
Name string
|
||||
FileType string
|
||||
PackageName string
|
||||
Header []byte
|
||||
PackagePath string
|
||||
PackageDir string
|
||||
Imports map[string]struct{}
|
||||
Vars bytes.Buffer
|
||||
Consts bytes.Buffer
|
||||
Body bytes.Buffer
|
||||
}
|
||||
|
||||
type FileType interface {
|
||||
AssembleFile(f *File, path string) error
|
||||
VerifyFile(f *File, path string) error
|
||||
}
|
||||
|
||||
// Packages is a list of packages to generate.
|
||||
type Packages []Package
|
||||
|
||||
// Generator is the contract for anything that wants to do auto-generation.
|
||||
// It's expected that the io.Writers passed to the below functions will be
|
||||
// ErrorTrackers; this allows implementations to not check for io errors,
|
||||
@@ -110,7 +109,7 @@ type Generator interface {
|
||||
|
||||
// Init should write an init function, and any other content that's not
|
||||
// generated per-type. (It's not intended for generator specific
|
||||
// initialization! Do that when your Package constructs the
|
||||
// initialization! Do that when your Target constructs the
|
||||
// Generators.)
|
||||
Init(*Context, io.Writer) error
|
||||
|
||||
@@ -160,38 +159,25 @@ type Context struct {
|
||||
// All the types, in case you want to look up something.
|
||||
Universe types.Universe
|
||||
|
||||
// Incoming imports, i.e. packages importing the given package.
|
||||
incomingImports map[string][]string
|
||||
|
||||
// Incoming transitive imports, i.e. the transitive closure of IncomingImports
|
||||
incomingTransitiveImports map[string][]string
|
||||
|
||||
// All the user-specified packages. This is after recursive expansion.
|
||||
Inputs []string
|
||||
|
||||
// The canonical ordering of the types (will be filtered by both the
|
||||
// Package's and Generator's Filter methods).
|
||||
// Target's and Generator's Filter methods).
|
||||
Order []*types.Type
|
||||
|
||||
// A set of types this context can process. If this is empty or nil,
|
||||
// the default "golang" filetype will be provided.
|
||||
// the default "go" filetype will be provided.
|
||||
FileTypes map[string]FileType
|
||||
|
||||
// If true, Execute* calls will just verify that the existing output is
|
||||
// correct. (You may set this after calling NewContext.)
|
||||
Verify bool
|
||||
|
||||
// Allows generators to add packages at runtime.
|
||||
builder *parser.Builder
|
||||
|
||||
// If specified, trim the prefix from a package's path before writing files.
|
||||
TrimPathPrefix string
|
||||
parser *parser.Parser
|
||||
}
|
||||
|
||||
// NewContext generates a context from the given builder, naming systems, and
|
||||
// NewContext generates a context from the given parser, naming systems, and
|
||||
// the naming system you wish to construct the canonical ordering from.
|
||||
func NewContext(b *parser.Builder, nameSystems namer.NameSystems, canonicalOrderName string) (*Context, error) {
|
||||
universe, err := b.FindTypes()
|
||||
func NewContext(p *parser.Parser, nameSystems namer.NameSystems, canonicalOrderName string) (*Context, error) {
|
||||
universe, err := p.NewUniverse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -199,11 +185,11 @@ func NewContext(b *parser.Builder, nameSystems namer.NameSystems, canonicalOrder
|
||||
c := &Context{
|
||||
Namers: namer.NameSystems{},
|
||||
Universe: universe,
|
||||
Inputs: b.FindPackages(),
|
||||
Inputs: p.UserRequestedPackages(),
|
||||
FileTypes: map[string]FileType{
|
||||
GolangFileType: NewGolangFile(),
|
||||
GoFileType: NewGoFile(),
|
||||
},
|
||||
builder: b,
|
||||
parser: p,
|
||||
}
|
||||
|
||||
for name, systemNamer := range nameSystems {
|
||||
@@ -216,44 +202,13 @@ func NewContext(b *parser.Builder, nameSystems namer.NameSystems, canonicalOrder
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// IncomingImports returns the incoming imports for each package. The map is lazily computed.
|
||||
func (ctxt *Context) IncomingImports() map[string][]string {
|
||||
if ctxt.incomingImports == nil {
|
||||
incoming := map[string][]string{}
|
||||
for _, pkg := range ctxt.Universe {
|
||||
for imp := range pkg.Imports {
|
||||
incoming[imp] = append(incoming[imp], pkg.Path)
|
||||
}
|
||||
}
|
||||
ctxt.incomingImports = incoming
|
||||
}
|
||||
return ctxt.incomingImports
|
||||
// LoadPackages adds Go packages to the context.
|
||||
func (c *Context) LoadPackages(patterns ...string) ([]*types.Package, error) {
|
||||
return c.parser.LoadPackagesTo(&c.Universe, patterns...)
|
||||
}
|
||||
|
||||
// TransitiveIncomingImports returns the transitive closure of the incoming imports for each package.
|
||||
// The map is lazily computed.
|
||||
func (ctxt *Context) TransitiveIncomingImports() map[string][]string {
|
||||
if ctxt.incomingTransitiveImports == nil {
|
||||
ctxt.incomingTransitiveImports = transitiveClosure(ctxt.IncomingImports())
|
||||
}
|
||||
return ctxt.incomingTransitiveImports
|
||||
}
|
||||
|
||||
// AddDir adds a Go package to the context. The specified path must be a single
|
||||
// go package import path. GOPATH, GOROOT, and the location of your go binary
|
||||
// (`which go`) will all be searched, in the normal Go fashion.
|
||||
// Deprecated. Please use AddDirectory.
|
||||
func (ctxt *Context) AddDir(path string) error {
|
||||
ctxt.incomingImports = nil
|
||||
ctxt.incomingTransitiveImports = nil
|
||||
return ctxt.builder.AddDirTo(path, &ctxt.Universe)
|
||||
}
|
||||
|
||||
// AddDirectory adds a Go package to the context. The specified path must be a
|
||||
// single go package import path. GOPATH, GOROOT, and the location of your go
|
||||
// binary (`which go`) will all be searched, in the normal Go fashion.
|
||||
func (ctxt *Context) AddDirectory(path string) (*types.Package, error) {
|
||||
ctxt.incomingImports = nil
|
||||
ctxt.incomingTransitiveImports = nil
|
||||
return ctxt.builder.AddDirectoryTo(path, &ctxt.Universe)
|
||||
// FindPackages expands Go package patterns into a list of package import
|
||||
// paths, akin to `go list -find`.
|
||||
func (c *Context) FindPackages(patterns ...string) ([]string, error) {
|
||||
return c.parser.FindPackages(patterns...)
|
||||
}
|
||||
61
vendor/k8s.io/gengo/v2/generator/go_generator.go
generated
vendored
Normal file
61
vendor/k8s.io/gengo/v2/generator/go_generator.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2015 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 generator
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"k8s.io/gengo/v2/namer"
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
const (
|
||||
GoFileType = "go"
|
||||
)
|
||||
|
||||
// GoGenerator implements a do-nothing Generator for Go files. It can be
|
||||
// used as a base for custom Generators, which embed it and then define the
|
||||
// methods they need to specialize.
|
||||
type GoGenerator struct {
|
||||
// OutputFilename is used as the Generator's name, and filename.
|
||||
OutputFilename string
|
||||
|
||||
// Body, if present, will be used as the return from the "Init" method.
|
||||
// This causes it to be static content for the entire file if no other
|
||||
// generator touches the file.
|
||||
OptionalBody []byte
|
||||
}
|
||||
|
||||
func (gg GoGenerator) Name() string { return gg.OutputFilename }
|
||||
func (gg GoGenerator) Filter(*Context, *types.Type) bool { return true }
|
||||
func (gg GoGenerator) Namers(*Context) namer.NameSystems { return nil }
|
||||
func (gg GoGenerator) Imports(*Context) []string { return []string{} }
|
||||
func (gg GoGenerator) PackageVars(*Context) []string { return []string{} }
|
||||
func (gg GoGenerator) PackageConsts(*Context) []string { return []string{} }
|
||||
func (gg GoGenerator) GenerateType(*Context, *types.Type, io.Writer) error { return nil }
|
||||
func (gg GoGenerator) Filename() string { return gg.OutputFilename }
|
||||
func (gg GoGenerator) FileType() string { return GoFileType }
|
||||
func (gg GoGenerator) Finalize(*Context, io.Writer) error { return nil }
|
||||
|
||||
func (gg GoGenerator) Init(c *Context, w io.Writer) error {
|
||||
_, err := w.Write(gg.OptionalBody)
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
_ = Generator(GoGenerator{})
|
||||
)
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/gengo/v2/namer"
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
// NewImportTrackerForPackage creates a new import tracker which is aware
|
||||
@@ -45,7 +45,7 @@ import (
|
||||
func NewImportTrackerForPackage(local string, typesToAdd ...*types.Type) *namer.DefaultImportTracker {
|
||||
tracker := namer.NewDefaultImportTracker(types.Name{Package: local})
|
||||
tracker.IsInvalidType = func(*types.Type) bool { return false }
|
||||
tracker.LocalName = func(name types.Name) string { return golangTrackerLocalName(&tracker, name) }
|
||||
tracker.LocalName = func(name types.Name) string { return goTrackerLocalName(&tracker, name) }
|
||||
tracker.PrintImport = func(path, name string) string { return name + " \"" + path + "\"" }
|
||||
|
||||
tracker.AddTypes(typesToAdd...)
|
||||
@@ -56,7 +56,7 @@ func NewImportTracker(typesToAdd ...*types.Type) *namer.DefaultImportTracker {
|
||||
return NewImportTrackerForPackage("", typesToAdd...)
|
||||
}
|
||||
|
||||
func golangTrackerLocalName(tracker namer.ImportTracker, t types.Name) string {
|
||||
func goTrackerLocalName(tracker namer.ImportTracker, t types.Name) string {
|
||||
path := t.Package
|
||||
|
||||
// Using backslashes in package names causes gengo to produce Go code which
|
||||
@@ -69,11 +69,11 @@ func golangTrackerLocalName(tracker namer.ImportTracker, t types.Name) string {
|
||||
for n := len(dirs) - 1; n >= 0; n-- {
|
||||
// follow kube convention of not having anything between directory names
|
||||
name := strings.Join(dirs[n:], "")
|
||||
name = strings.Replace(name, "_", "", -1)
|
||||
name = strings.ReplaceAll(name, "_", "")
|
||||
// These characters commonly appear in import paths for go
|
||||
// packages, but aren't legal go names. So we'll sanitize.
|
||||
name = strings.Replace(name, ".", "", -1)
|
||||
name = strings.Replace(name, "-", "", -1)
|
||||
name = strings.ReplaceAll(name, ".", "")
|
||||
name = strings.ReplaceAll(name, "-", "")
|
||||
if _, found := tracker.PathOf(name); found {
|
||||
// This name collides with some other package
|
||||
continue
|
||||
77
vendor/k8s.io/gengo/v2/generator/simple_target.go
generated
vendored
Normal file
77
vendor/k8s.io/gengo/v2/generator/simple_target.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright 2015 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 generator
|
||||
|
||||
import (
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
// SimpleTarget is implements Target in terms of static configuration.
|
||||
// The package name, path, and dir are required to be non-empty.
|
||||
type SimpleTarget struct {
|
||||
// PkgName is the name of the resulting package (as in "package xxxx").
|
||||
// Required.
|
||||
PkgName string
|
||||
// PkgPath is the canonical Go import-path of the resulting package (as in
|
||||
// "import example.com/xxxx/yyyy"). Required.
|
||||
PkgPath string
|
||||
// PkgDir is the location of the resulting package on disk (which may not
|
||||
// exist yet). It may be absolute or relative to CWD. Required.
|
||||
PkgDir string
|
||||
|
||||
// HeaderComment is emitted at the top of every output file. Optional.
|
||||
HeaderComment []byte
|
||||
|
||||
// PkgDocComment is emitted after the header comment for a "doc.go" file.
|
||||
// Optional.
|
||||
PkgDocComment []byte
|
||||
|
||||
// FilterFunc will be called to implement Target.Filter. Optional.
|
||||
FilterFunc func(*Context, *types.Type) bool
|
||||
|
||||
// GeneratorsFunc will be called to implement Target.Generators. Optional.
|
||||
GeneratorsFunc func(*Context) []Generator
|
||||
}
|
||||
|
||||
func (st SimpleTarget) Name() string { return st.PkgName }
|
||||
func (st SimpleTarget) Path() string { return st.PkgPath }
|
||||
func (st SimpleTarget) Dir() string { return st.PkgDir }
|
||||
|
||||
func (st SimpleTarget) Filter(c *Context, t *types.Type) bool {
|
||||
if st.FilterFunc != nil {
|
||||
return st.FilterFunc(c, t)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (st SimpleTarget) Generators(c *Context) []Generator {
|
||||
if st.GeneratorsFunc != nil {
|
||||
return st.GeneratorsFunc(c)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st SimpleTarget) Header(filename string) []byte {
|
||||
if filename == "doc.go" {
|
||||
return append(st.HeaderComment, st.PkgDocComment...)
|
||||
}
|
||||
return st.HeaderComment
|
||||
}
|
||||
|
||||
var (
|
||||
_ = Target(SimpleTarget{})
|
||||
)
|
||||
@@ -74,15 +74,15 @@ func NewSnippetWriter(w io.Writer, c *Context, left, right string) *SnippetWrite
|
||||
// return sw.Error()
|
||||
//
|
||||
// Where:
|
||||
// * "$" starts a template directive
|
||||
// * "." references the entire thing passed as args
|
||||
// * "type" therefore sees a map and looks up the key "type"
|
||||
// * "|" means "pass the thing on the left to the thing on the right"
|
||||
// * "public" is the name of a naming system, so the SnippetWriter has given
|
||||
// the template a function called "public" that takes a *types.Type and
|
||||
// returns the naming system's name. E.g., if the type is "string" this might
|
||||
// return "String".
|
||||
// * the second "$" ends the template directive.
|
||||
// - "$" starts a template directive
|
||||
// - "." references the entire thing passed as args
|
||||
// - "type" therefore sees a map and looks up the key "type"
|
||||
// - "|" means "pass the thing on the left to the thing on the right"
|
||||
// - "public" is the name of a naming system, so the SnippetWriter has given
|
||||
// the template a function called "public" that takes a *types.Type and
|
||||
// returns the naming system's name. E.g., if the type is "string" this might
|
||||
// return "String".
|
||||
// - the second "$" ends the template directive.
|
||||
//
|
||||
// The map is actually not necessary. The below does the same thing:
|
||||
//
|
||||
2
vendor/k8s.io/gengo/namer/doc.go → vendor/k8s.io/gengo/v2/namer/doc.go
generated
vendored
2
vendor/k8s.io/gengo/namer/doc.go → vendor/k8s.io/gengo/v2/namer/doc.go
generated
vendored
@@ -28,4 +28,4 @@ limitations under the License.
|
||||
//
|
||||
// Additionally, a "RawNamer" can optionally keep track of what needs to be
|
||||
// imported.
|
||||
package namer // import "k8s.io/gengo/namer"
|
||||
package namer // import "k8s.io/gengo/v2/namer"
|
||||
@@ -19,7 +19,7 @@ package namer
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
// ImportTracker may be passed to a namer.RawNamer, to track the imports needed
|
||||
@@ -99,7 +99,7 @@ func (tracker *DefaultImportTracker) ImportLines() []string {
|
||||
for path := range tracker.pathToName {
|
||||
importPaths = append(importPaths, path)
|
||||
}
|
||||
sort.Sort(sort.StringSlice(importPaths))
|
||||
sort.Strings(importPaths)
|
||||
out := []string{}
|
||||
for _, path := range importPaths {
|
||||
out = append(out, tracker.PrintImport(path, tracker.pathToName[path]))
|
||||
2
vendor/k8s.io/gengo/namer/namer.go → vendor/k8s.io/gengo/v2/namer/namer.go
generated
vendored
2
vendor/k8s.io/gengo/namer/namer.go → vendor/k8s.io/gengo/v2/namer/namer.go
generated
vendored
@@ -22,7 +22,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
const (
|
||||
2
vendor/k8s.io/gengo/namer/order.go → vendor/k8s.io/gengo/v2/namer/order.go
generated
vendored
2
vendor/k8s.io/gengo/namer/order.go → vendor/k8s.io/gengo/v2/namer/order.go
generated
vendored
@@ -19,7 +19,7 @@ package namer
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
// Orderer produces an ordering of types given a Namer.
|
||||
@@ -19,7 +19,7 @@ package namer
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
var consonants = "bcdfghjklmnpqrstvwxyz"
|
||||
2
vendor/k8s.io/gengo/parser/doc.go → vendor/k8s.io/gengo/v2/parser/doc.go
generated
vendored
2
vendor/k8s.io/gengo/parser/doc.go → vendor/k8s.io/gengo/v2/parser/doc.go
generated
vendored
@@ -16,4 +16,4 @@ limitations under the License.
|
||||
|
||||
// Package parser provides code to parse go files, type-check them, extract the
|
||||
// types.
|
||||
package parser // import "k8s.io/gengo/parser"
|
||||
package parser // import "k8s.io/gengo/v2/parser"
|
||||
821
vendor/k8s.io/gengo/v2/parser/parse.go
generated
vendored
Normal file
821
vendor/k8s.io/gengo/v2/parser/parse.go
generated
vendored
Normal file
@@ -0,0 +1,821 @@
|
||||
/*
|
||||
Copyright 2015 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 parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
gotypes "go/types"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
"k8s.io/gengo/v2/types"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// Parser lets you add all the go files in all the packages that you care
|
||||
// about, then constructs the type source data.
|
||||
type Parser struct {
|
||||
// Map of package paths to definitions. These keys should be canonical
|
||||
// Go import paths (example.com/foo/bar) and not local paths (./foo/bar).
|
||||
goPkgs map[string]*packages.Package
|
||||
|
||||
// Keep track of which packages were directly requested (as opposed to
|
||||
// those which are transitively loaded).
|
||||
userRequested map[string]bool
|
||||
|
||||
// Keep track of which packages have already been scanned for types.
|
||||
fullyProcessed map[string]bool
|
||||
|
||||
// Build tags to set when loading packages.
|
||||
buildTags []string
|
||||
|
||||
// Tracks accumulated parsed files, so we can do position lookups later.
|
||||
fset *token.FileSet
|
||||
|
||||
// All comments from everywhere in every parsed file. This map is keyed by
|
||||
// the file-line on which the comment block ends, which makes it easy to
|
||||
// look up comments which immediately precede a given obect (e.g. a type or
|
||||
// function definition), which is what we almost always want. We need this
|
||||
// because Go's own ast package does a very poor job of handling comments.
|
||||
endLineToCommentGroup map[fileLine]*ast.CommentGroup
|
||||
}
|
||||
|
||||
// key type for finding comments.
|
||||
type fileLine struct {
|
||||
file string
|
||||
line int
|
||||
}
|
||||
|
||||
// New constructs a new Parser.
|
||||
func New() *Parser {
|
||||
return NewWithOptions(Options{})
|
||||
}
|
||||
|
||||
func NewWithOptions(opts Options) *Parser {
|
||||
return &Parser{
|
||||
goPkgs: map[string]*packages.Package{},
|
||||
userRequested: map[string]bool{},
|
||||
fullyProcessed: map[string]bool{},
|
||||
fset: token.NewFileSet(),
|
||||
endLineToCommentGroup: map[fileLine]*ast.CommentGroup{},
|
||||
buildTags: opts.BuildTags,
|
||||
}
|
||||
}
|
||||
|
||||
// Options holds optional settings for the Parser.
|
||||
type Options struct {
|
||||
// BuildTags is a list of optional tags to be specified when loading
|
||||
// packages.
|
||||
BuildTags []string
|
||||
}
|
||||
|
||||
// FindPackages expands the provided patterns into a list of Go import-paths,
|
||||
// much like `go list -find`.
|
||||
func (p *Parser) FindPackages(patterns ...string) ([]string, error) {
|
||||
return p.findPackages(nil, patterns...)
|
||||
}
|
||||
|
||||
// baseCfg is an optional (may be nil) config which might be injected by tests.
|
||||
func (p *Parser) findPackages(baseCfg *packages.Config, patterns ...string) ([]string, error) {
|
||||
toFind := make([]string, 0, len(patterns))
|
||||
results := make([]string, 0, len(patterns))
|
||||
for _, pat := range patterns {
|
||||
if pkg := p.goPkgs[pat]; pkg != nil {
|
||||
results = append(results, pkg.PkgPath)
|
||||
} else {
|
||||
toFind = append(toFind, pat)
|
||||
}
|
||||
}
|
||||
if len(toFind) == 0 {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
cfg := packages.Config{
|
||||
Mode: packages.NeedName | packages.NeedFiles,
|
||||
BuildFlags: []string{"-tags", strings.Join(p.buildTags, ",")},
|
||||
Tests: false,
|
||||
}
|
||||
if baseCfg != nil {
|
||||
// This is to support tests, e.g. to inject a fake GOPATH or CWD.
|
||||
cfg.Dir = baseCfg.Dir
|
||||
cfg.Env = baseCfg.Env
|
||||
}
|
||||
|
||||
pkgs, err := packages.Load(&cfg, toFind...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading packages: %w", err)
|
||||
}
|
||||
var allErrs []error
|
||||
for _, pkg := range pkgs {
|
||||
results = append(results, pkg.PkgPath)
|
||||
|
||||
// pkg.Errors is not a slice of `error`, but concrete types. We have
|
||||
// to iteratively convert each one into `error`.
|
||||
var errs []error
|
||||
for _, e := range pkg.Errors {
|
||||
errs = append(errs, e)
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
allErrs = append(allErrs, fmt.Errorf("error(s) in %q:\n%w", pkg.PkgPath, errors.Join(errs...)))
|
||||
}
|
||||
}
|
||||
if len(allErrs) != 0 {
|
||||
return nil, errors.Join(allErrs...)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// LoadPackages loads and parses the specified Go packages. Specifically
|
||||
// named packages (without a trailing "/...") which do not exist or have no Go
|
||||
// files are an error.
|
||||
func (p *Parser) LoadPackages(patterns ...string) error {
|
||||
_, err := p.loadPackages(patterns...)
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadPackagesWithConfigForTesting loads and parses the specified Go packages with the
|
||||
// specified packages.Config as a starting point. This is for testing, and
|
||||
// only the .Dir and .Env fields of the Config will be considered.
|
||||
func (p *Parser) LoadPackagesWithConfigForTesting(cfg *packages.Config, patterns ...string) error {
|
||||
_, err := p.loadPackagesWithConfig(cfg, patterns...)
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadPackagesTo loads and parses the specified Go packages, and inserts them
|
||||
// into the specified Universe. It returns the packages which match the
|
||||
// patterns, but loads all packages and their imports, recursively, into the
|
||||
// universe. See NewUniverse for more.
|
||||
func (p *Parser) LoadPackagesTo(u *types.Universe, patterns ...string) ([]*types.Package, error) {
|
||||
// Load Packages.
|
||||
pkgs, err := p.loadPackages(patterns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load types in all packages (it will internally filter).
|
||||
if err := p.addPkgsToUniverse(pkgs, u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the results as gengo types.Packages.
|
||||
ret := make([]*types.Package, 0, len(pkgs))
|
||||
for _, pkg := range pkgs {
|
||||
ret = append(ret, u.Package(pkg.PkgPath))
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (p *Parser) loadPackages(patterns ...string) ([]*packages.Package, error) {
|
||||
return p.loadPackagesWithConfig(nil, patterns...)
|
||||
}
|
||||
|
||||
// baseCfg is an optional (may be nil) config which might be injected by tests.
|
||||
func (p *Parser) loadPackagesWithConfig(baseCfg *packages.Config, patterns ...string) ([]*packages.Package, error) {
|
||||
klog.V(5).Infof("loadPackages %q", patterns)
|
||||
|
||||
// Loading packages is slow - only do ones we know we have not already done
|
||||
// (e.g. if a tool calls LoadPackages itself).
|
||||
existingPkgs, netNewPkgs, err := p.alreadyLoaded(baseCfg, patterns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if vlog := klog.V(5); vlog.Enabled() {
|
||||
if len(existingPkgs) > 0 {
|
||||
keys := make([]string, 0, len(existingPkgs))
|
||||
for _, p := range existingPkgs {
|
||||
keys = append(keys, p.PkgPath)
|
||||
}
|
||||
vlog.Infof(" already have: %q", keys)
|
||||
}
|
||||
if len(netNewPkgs) > 0 {
|
||||
vlog.Infof(" to be loaded: %q", netNewPkgs)
|
||||
}
|
||||
}
|
||||
|
||||
// If these were not user-requested before, they are now.
|
||||
for _, pkg := range existingPkgs {
|
||||
if !p.userRequested[pkg.PkgPath] {
|
||||
p.userRequested[pkg.PkgPath] = true
|
||||
}
|
||||
}
|
||||
for _, pkg := range netNewPkgs {
|
||||
if !p.userRequested[pkg] {
|
||||
p.userRequested[pkg] = true
|
||||
}
|
||||
}
|
||||
|
||||
if len(netNewPkgs) == 0 {
|
||||
return existingPkgs, nil
|
||||
}
|
||||
|
||||
cfg := packages.Config{
|
||||
Mode: packages.NeedName |
|
||||
packages.NeedFiles | packages.NeedImports | packages.NeedDeps |
|
||||
packages.NeedModule | packages.NeedTypes | packages.NeedSyntax,
|
||||
BuildFlags: []string{"-tags", strings.Join(p.buildTags, ",")},
|
||||
Fset: p.fset,
|
||||
Tests: false,
|
||||
}
|
||||
if baseCfg != nil {
|
||||
// This is to support tests, e.g. to inject a fake GOPATH or CWD.
|
||||
cfg.Dir = baseCfg.Dir
|
||||
cfg.Env = baseCfg.Env
|
||||
}
|
||||
|
||||
tBefore := time.Now()
|
||||
pkgs, err := packages.Load(&cfg, netNewPkgs...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading packages: %w", err)
|
||||
}
|
||||
klog.V(5).Infof(" loaded %d pkg(s) in %v", len(pkgs), time.Since(tBefore))
|
||||
|
||||
// Handle any errors.
|
||||
collectErrors := func(pkg *packages.Package) error {
|
||||
var errs []error
|
||||
for _, e := range pkg.Errors {
|
||||
if e.Kind == packages.ListError || e.Kind == packages.ParseError {
|
||||
errs = append(errs, e)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("error(s) in %q:\n%w", pkg.PkgPath, errors.Join(errs...))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := forEachPackageRecursive(pkgs, collectErrors); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Finish integrating packages into our state.
|
||||
absorbPkg := func(pkg *packages.Package) error {
|
||||
p.goPkgs[pkg.PkgPath] = pkg
|
||||
|
||||
for _, f := range pkg.Syntax {
|
||||
for _, c := range f.Comments {
|
||||
// We need to do this on _every_ pkg, not just user-requested
|
||||
// ones, because some generators look at tags in other
|
||||
// packages.
|
||||
//
|
||||
// TODO: It would be nice if we only did this on user-requested
|
||||
// packages. The problem is that we don't always know which
|
||||
// other packages will need this information, and even when we
|
||||
// do we may have already loaded the package (as a transitive
|
||||
// dep) and might have stored pointers into it. Doing a
|
||||
// thorough "reload" without invalidating all those pointers is
|
||||
// a problem for another day.
|
||||
position := p.fset.Position(c.End()) // Fset is synchronized
|
||||
p.endLineToCommentGroup[fileLine{position.Filename, position.Line}] = c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
if err := forEachPackageRecursive(pkgs, absorbPkg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return append(existingPkgs, pkgs...), nil
|
||||
}
|
||||
|
||||
// alreadyLoaded figures out which of the specified patterns have already been loaded
|
||||
// and which have not, and returns those respectively.
|
||||
// baseCfg is an optional (may be nil) config which might be injected by tests.
|
||||
func (p *Parser) alreadyLoaded(baseCfg *packages.Config, patterns ...string) ([]*packages.Package, []string, error) {
|
||||
existingPkgs := make([]*packages.Package, 0, len(patterns))
|
||||
netNewPkgs := make([]string, 0, len(patterns))
|
||||
|
||||
// Expand and canonicalize the requested patterns. This should be fast.
|
||||
if pkgPaths, err := p.findPackages(baseCfg, patterns...); err != nil {
|
||||
return nil, nil, err
|
||||
} else {
|
||||
for _, pkgPath := range pkgPaths {
|
||||
if pkg := p.goPkgs[pkgPath]; pkg != nil {
|
||||
existingPkgs = append(existingPkgs, pkg)
|
||||
} else {
|
||||
netNewPkgs = append(netNewPkgs, pkgPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
return existingPkgs, netNewPkgs, nil
|
||||
}
|
||||
|
||||
// forEachPackageRecursive will run the provided function on all of the specified
|
||||
// packages, and on their imports recursively. Errors are accumulated and
|
||||
// returned as via errors.Join.
|
||||
func forEachPackageRecursive(pkgs []*packages.Package, fn func(pkg *packages.Package) error) error {
|
||||
seen := map[string]bool{} // PkgPaths we have already visited
|
||||
var errs []error
|
||||
for _, pkg := range pkgs {
|
||||
errs = append(errs, recursePackage(pkg, fn, seen)...)
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func recursePackage(pkg *packages.Package, fn func(pkg *packages.Package) error, seen map[string]bool) []error {
|
||||
if seen[pkg.PkgPath] {
|
||||
return nil
|
||||
}
|
||||
var errs []error
|
||||
seen[pkg.PkgPath] = true
|
||||
if err := fn(pkg); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
for _, imp := range pkg.Imports {
|
||||
errs = append(errs, recursePackage(imp, fn, seen)...)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// UserRequestedPackages fetches a list of the user-imported packages.
|
||||
func (p *Parser) UserRequestedPackages() []string {
|
||||
// Iterate packages in a predictable order.
|
||||
pkgPaths := make([]string, 0, len(p.userRequested))
|
||||
for k := range p.userRequested {
|
||||
pkgPaths = append(pkgPaths, string(k))
|
||||
}
|
||||
sort.Strings(pkgPaths)
|
||||
return pkgPaths
|
||||
}
|
||||
|
||||
// NewUniverse finalizes the loaded packages, searches through them for types
|
||||
// and produces a new Universe. The returned Universe has one types.Package
|
||||
// entry for each Go package that has been loaded, including all of their
|
||||
// dependencies, recursively. It also has one entry, whose key is "", which
|
||||
// represents "builtin" types.
|
||||
func (p *Parser) NewUniverse() (types.Universe, error) {
|
||||
u := types.Universe{}
|
||||
|
||||
pkgs := []*packages.Package{}
|
||||
for _, path := range p.UserRequestedPackages() {
|
||||
pkgs = append(pkgs, p.goPkgs[path])
|
||||
}
|
||||
if err := p.addPkgsToUniverse(pkgs, &u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
|
||||
// packageDir tries to figure out the directory of the specified package.
|
||||
func packageDir(pkg *packages.Package) (string, error) {
|
||||
// Sometimes Module is present but has no Dir, e.g. when it is vendored.
|
||||
if pkg.Module != nil && pkg.Module.Dir != "" {
|
||||
// NOTE: this will not work if tests are loaded, because Go mutates the
|
||||
// Package.PkgPath.
|
||||
subdir := strings.TrimPrefix(pkg.PkgPath, pkg.Module.Path)
|
||||
return filepath.Join(pkg.Module.Dir, subdir), nil
|
||||
}
|
||||
if len(pkg.GoFiles) > 0 {
|
||||
return filepath.Dir(pkg.GoFiles[0]), nil
|
||||
}
|
||||
if len(pkg.IgnoredFiles) > 0 {
|
||||
return filepath.Dir(pkg.IgnoredFiles[0]), nil
|
||||
}
|
||||
return "", fmt.Errorf("can't find package dir for %q - no module info and no Go files", pkg.PkgPath)
|
||||
}
|
||||
|
||||
// addPkgsToUniverse adds the packages, and all of their deps, recursively, to
|
||||
// the universe and (if needed) searches through them for types.
|
||||
func (p *Parser) addPkgsToUniverse(pkgs []*packages.Package, u *types.Universe) error {
|
||||
addOne := func(pkg *packages.Package) error {
|
||||
if err := p.addPkgToUniverse(pkg, u); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := forEachPackageRecursive(pkgs, addOne); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// addPkgToUniverse adds one package to the universe and (if needed) searches
|
||||
// through it for types.
|
||||
func (p *Parser) addPkgToUniverse(pkg *packages.Package, u *types.Universe) error {
|
||||
pkgPath := pkg.PkgPath
|
||||
if p.fullyProcessed[pkgPath] {
|
||||
return nil
|
||||
}
|
||||
|
||||
// This will get-or-create the Package.
|
||||
gengoPkg := u.Package(pkgPath)
|
||||
|
||||
if gengoPkg.Dir == "" {
|
||||
// We're keeping this package, though we might not fully process it.
|
||||
if vlog := klog.V(5); vlog.Enabled() {
|
||||
why := "user-requested"
|
||||
if !p.userRequested[pkgPath] {
|
||||
why = "dependency"
|
||||
}
|
||||
vlog.Infof("addPkgToUniverse %q (%s)", pkgPath, why)
|
||||
}
|
||||
|
||||
absPath := ""
|
||||
if dir, err := packageDir(pkg); err != nil {
|
||||
return err
|
||||
} else {
|
||||
absPath = dir
|
||||
}
|
||||
|
||||
gengoPkg.Path = pkg.PkgPath
|
||||
gengoPkg.Dir = absPath
|
||||
}
|
||||
|
||||
// If the package was not user-requested, we can stop here.
|
||||
if !p.userRequested[pkgPath] {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mark it as done, so we don't ever re-process it.
|
||||
p.fullyProcessed[pkgPath] = true
|
||||
gengoPkg.Name = pkg.Name
|
||||
|
||||
// For historical reasons we treat files named "doc.go" specially.
|
||||
// TODO: It would be nice to not do this and instead treat package
|
||||
// doc-comments as the "global" config place. This would require changing
|
||||
// most generators and input files.
|
||||
for _, f := range pkg.Syntax {
|
||||
// This gets the filename for the ast.File. Iterating pkg.GoFiles is
|
||||
// documented as unreliable.
|
||||
pos := p.fset.Position(f.FileStart)
|
||||
if filepath.Base(pos.Filename) == "doc.go" {
|
||||
gengoPkg.Comments = []string{}
|
||||
for i := range f.Comments {
|
||||
gengoPkg.Comments = append(gengoPkg.Comments, splitLines(f.Comments[i].Text())...)
|
||||
}
|
||||
if f.Doc != nil {
|
||||
gengoPkg.DocComments = splitLines(f.Doc.Text())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Walk all the types, recursively and save them for later access.
|
||||
s := pkg.Types.Scope()
|
||||
for _, n := range s.Names() {
|
||||
switch obj := s.Lookup(n).(type) {
|
||||
case *gotypes.TypeName:
|
||||
t := p.walkType(*u, nil, obj.Type())
|
||||
p.addCommentsToType(obj, t)
|
||||
case *gotypes.Func:
|
||||
// We only care about functions, not concrete/abstract methods.
|
||||
if obj.Type() != nil && obj.Type().(*gotypes.Signature).Recv() == nil {
|
||||
t := p.addFunction(*u, nil, obj)
|
||||
p.addCommentsToType(obj, t)
|
||||
}
|
||||
case *gotypes.Var:
|
||||
if !obj.IsField() {
|
||||
t := p.addVariable(*u, nil, obj)
|
||||
p.addCommentsToType(obj, t)
|
||||
}
|
||||
case *gotypes.Const:
|
||||
t := p.addConstant(*u, nil, obj)
|
||||
p.addCommentsToType(obj, t)
|
||||
default:
|
||||
klog.Infof("addPkgToUniverse %q: unhandled object of type %T: %v", pkgPath, obj, obj)
|
||||
}
|
||||
}
|
||||
|
||||
// Add all of this package's imports.
|
||||
importedPkgs := []string{}
|
||||
for _, imp := range pkg.Imports {
|
||||
if err := p.addPkgToUniverse(imp, u); err != nil {
|
||||
return err
|
||||
}
|
||||
importedPkgs = append(importedPkgs, imp.PkgPath)
|
||||
}
|
||||
sort.Strings(importedPkgs)
|
||||
u.AddImports(pkg.PkgPath, importedPkgs...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the specified position has a "doc comment", return that.
|
||||
func (p *Parser) docComment(pos token.Pos) []string {
|
||||
// An object's doc comment always ends on the line before the object's own
|
||||
// declaration.
|
||||
c1 := p.priorCommentLines(pos, 1)
|
||||
return splitLines(c1.Text()) // safe even if c1 is nil
|
||||
}
|
||||
|
||||
// If there is a detached (not immediately before a declaration) comment,
|
||||
// return that.
|
||||
func (p *Parser) priorDetachedComment(pos token.Pos) []string {
|
||||
// An object's doc comment always ends on the line before the object's own
|
||||
// declaration.
|
||||
c1 := p.priorCommentLines(pos, 1)
|
||||
|
||||
// Using a literal "2" here is brittle in theory (it means literally 2
|
||||
// lines), but in practice Go code is gofmt'ed (which elides repeated blank
|
||||
// lines), so it works.
|
||||
var c2 *ast.CommentGroup
|
||||
if c1 == nil {
|
||||
c2 = p.priorCommentLines(pos, 2)
|
||||
} else {
|
||||
c2 = p.priorCommentLines(c1.List[0].Slash, 2)
|
||||
}
|
||||
return splitLines(c2.Text()) // safe even if c1 is nil
|
||||
}
|
||||
|
||||
// If there's a comment block which ends nlines before pos, return it.
|
||||
func (p *Parser) priorCommentLines(pos token.Pos, lines int) *ast.CommentGroup {
|
||||
position := p.fset.Position(pos)
|
||||
key := fileLine{position.Filename, position.Line - lines}
|
||||
return p.endLineToCommentGroup[key]
|
||||
}
|
||||
|
||||
func splitLines(str string) []string {
|
||||
return strings.Split(strings.TrimRight(str, "\n"), "\n")
|
||||
}
|
||||
|
||||
func goFuncNameToName(in string) types.Name {
|
||||
name := strings.TrimPrefix(in, "func ")
|
||||
nameParts := strings.Split(name, "(")
|
||||
return goNameToName(nameParts[0])
|
||||
}
|
||||
|
||||
func goVarNameToName(in string) types.Name {
|
||||
nameParts := strings.Split(in, " ")
|
||||
// nameParts[0] is "var".
|
||||
// nameParts[2:] is the type of the variable, we ignore it for now.
|
||||
return goNameToName(nameParts[1])
|
||||
}
|
||||
|
||||
func goNameToName(in string) types.Name {
|
||||
// Detect anonymous type names. (These may have '.' characters because
|
||||
// embedded types may have packages, so we detect them specially.)
|
||||
if strings.HasPrefix(in, "struct{") ||
|
||||
strings.HasPrefix(in, "<-chan") ||
|
||||
strings.HasPrefix(in, "chan<-") ||
|
||||
strings.HasPrefix(in, "chan ") ||
|
||||
strings.HasPrefix(in, "func(") ||
|
||||
strings.HasPrefix(in, "func (") ||
|
||||
strings.HasPrefix(in, "*") ||
|
||||
strings.HasPrefix(in, "map[") ||
|
||||
strings.HasPrefix(in, "[") {
|
||||
return types.Name{Name: in}
|
||||
}
|
||||
|
||||
// Otherwise, if there are '.' characters present, the name has a
|
||||
// package path in front.
|
||||
nameParts := strings.Split(in, ".")
|
||||
name := types.Name{Name: in}
|
||||
if n := len(nameParts); n >= 2 {
|
||||
// The final "." is the name of the type--previous ones must
|
||||
// have been in the package path.
|
||||
name.Package, name.Name = strings.Join(nameParts[:n-1], "."), nameParts[n-1]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (p *Parser) convertSignature(u types.Universe, t *gotypes.Signature) *types.Signature {
|
||||
signature := &types.Signature{}
|
||||
for i := 0; i < t.Params().Len(); i++ {
|
||||
signature.Parameters = append(signature.Parameters, p.walkType(u, nil, t.Params().At(i).Type()))
|
||||
signature.ParameterNames = append(signature.ParameterNames, t.Params().At(i).Name())
|
||||
}
|
||||
for i := 0; i < t.Results().Len(); i++ {
|
||||
signature.Results = append(signature.Results, p.walkType(u, nil, t.Results().At(i).Type()))
|
||||
signature.ResultNames = append(signature.ResultNames, t.Results().At(i).Name())
|
||||
}
|
||||
if r := t.Recv(); r != nil {
|
||||
signature.Receiver = p.walkType(u, nil, r.Type())
|
||||
}
|
||||
signature.Variadic = t.Variadic()
|
||||
return signature
|
||||
}
|
||||
|
||||
// walkType adds the type, and any necessary child types.
|
||||
func (p *Parser) walkType(u types.Universe, useName *types.Name, in gotypes.Type) *types.Type {
|
||||
// Most of the cases are underlying types of the named type.
|
||||
name := goNameToName(in.String())
|
||||
if useName != nil {
|
||||
name = *useName
|
||||
}
|
||||
|
||||
switch t := in.(type) {
|
||||
case *gotypes.Struct:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Struct
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
f := t.Field(i)
|
||||
m := types.Member{
|
||||
Name: f.Name(),
|
||||
Embedded: f.Anonymous(),
|
||||
Tags: t.Tag(i),
|
||||
Type: p.walkType(u, nil, f.Type()),
|
||||
CommentLines: p.docComment(f.Pos()),
|
||||
}
|
||||
out.Members = append(out.Members, m)
|
||||
}
|
||||
return out
|
||||
case *gotypes.Map:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Map
|
||||
out.Elem = p.walkType(u, nil, t.Elem())
|
||||
out.Key = p.walkType(u, nil, t.Key())
|
||||
return out
|
||||
case *gotypes.Pointer:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Pointer
|
||||
out.Elem = p.walkType(u, nil, t.Elem())
|
||||
return out
|
||||
case *gotypes.Slice:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Slice
|
||||
out.Elem = p.walkType(u, nil, t.Elem())
|
||||
return out
|
||||
case *gotypes.Array:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Array
|
||||
out.Elem = p.walkType(u, nil, t.Elem())
|
||||
out.Len = in.(*gotypes.Array).Len()
|
||||
return out
|
||||
case *gotypes.Chan:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Chan
|
||||
out.Elem = p.walkType(u, nil, t.Elem())
|
||||
// TODO: need to store direction, otherwise raw type name
|
||||
// cannot be properly written.
|
||||
return out
|
||||
case *gotypes.Basic:
|
||||
out := u.Type(types.Name{
|
||||
Package: "", // This is a magic package name in the Universe.
|
||||
Name: t.Name(),
|
||||
})
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Unsupported
|
||||
return out
|
||||
case *gotypes.Signature:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Func
|
||||
out.Signature = p.convertSignature(u, t)
|
||||
return out
|
||||
case *gotypes.Interface:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Interface
|
||||
t.Complete()
|
||||
for i := 0; i < t.NumMethods(); i++ {
|
||||
if out.Methods == nil {
|
||||
out.Methods = map[string]*types.Type{}
|
||||
}
|
||||
method := t.Method(i)
|
||||
name := goNameToName(method.String())
|
||||
mt := p.walkType(u, &name, method.Type())
|
||||
mt.CommentLines = p.docComment(method.Pos())
|
||||
out.Methods[method.Name()] = mt
|
||||
}
|
||||
return out
|
||||
case *gotypes.Named:
|
||||
var out *types.Type
|
||||
switch t.Underlying().(type) {
|
||||
case *gotypes.Named, *gotypes.Basic, *gotypes.Map, *gotypes.Slice:
|
||||
name := goNameToName(t.String())
|
||||
out = u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Alias
|
||||
out.Underlying = p.walkType(u, nil, t.Underlying())
|
||||
default:
|
||||
// gotypes package makes everything "named" with an
|
||||
// underlying anonymous type--we remove that annoying
|
||||
// "feature" for users. This flattens those types
|
||||
// together.
|
||||
name := goNameToName(t.String())
|
||||
if out := u.Type(name); out.Kind != types.Unknown {
|
||||
return out // short circuit if we've already made this.
|
||||
}
|
||||
out = p.walkType(u, &name, t.Underlying())
|
||||
}
|
||||
// If the underlying type didn't already add methods, add them.
|
||||
// (Interface types will have already added methods.)
|
||||
if len(out.Methods) == 0 {
|
||||
for i := 0; i < t.NumMethods(); i++ {
|
||||
if out.Methods == nil {
|
||||
out.Methods = map[string]*types.Type{}
|
||||
}
|
||||
method := t.Method(i)
|
||||
name := goNameToName(method.String())
|
||||
mt := p.walkType(u, &name, method.Type())
|
||||
mt.CommentLines = p.docComment(method.Pos())
|
||||
out.Methods[method.Name()] = mt
|
||||
}
|
||||
}
|
||||
return out
|
||||
default:
|
||||
out := u.Type(name)
|
||||
if out.Kind != types.Unknown {
|
||||
return out
|
||||
}
|
||||
out.Kind = types.Unsupported
|
||||
klog.Warningf("Making unsupported type entry %q for: %#v\n", out, t)
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) addFunction(u types.Universe, useName *types.Name, in *gotypes.Func) *types.Type {
|
||||
name := goFuncNameToName(in.String())
|
||||
if useName != nil {
|
||||
name = *useName
|
||||
}
|
||||
out := u.Function(name)
|
||||
out.Kind = types.DeclarationOf
|
||||
out.Underlying = p.walkType(u, nil, in.Type())
|
||||
return out
|
||||
}
|
||||
|
||||
func (p *Parser) addVariable(u types.Universe, useName *types.Name, in *gotypes.Var) *types.Type {
|
||||
name := goVarNameToName(in.String())
|
||||
if useName != nil {
|
||||
name = *useName
|
||||
}
|
||||
out := u.Variable(name)
|
||||
out.Kind = types.DeclarationOf
|
||||
out.Underlying = p.walkType(u, nil, in.Type())
|
||||
return out
|
||||
}
|
||||
|
||||
func (p *Parser) addConstant(u types.Universe, useName *types.Name, in *gotypes.Const) *types.Type {
|
||||
name := goVarNameToName(in.String())
|
||||
if useName != nil {
|
||||
name = *useName
|
||||
}
|
||||
out := u.Constant(name)
|
||||
out.Kind = types.DeclarationOf
|
||||
out.Underlying = p.walkType(u, nil, in.Type())
|
||||
|
||||
var constval string
|
||||
|
||||
// For strings, we use `StringVal()` to get the un-truncated,
|
||||
// un-quoted string. For other values, `.String()` is preferable to
|
||||
// get something relatively human readable (especially since for
|
||||
// floating point types, `ExactString()` will generate numeric
|
||||
// expressions using `big.(*Float).Text()`.
|
||||
switch in.Val().Kind() {
|
||||
case constant.String:
|
||||
constval = constant.StringVal(in.Val())
|
||||
default:
|
||||
constval = in.Val().String()
|
||||
}
|
||||
|
||||
out.ConstValue = &constval
|
||||
return out
|
||||
}
|
||||
2
vendor/k8s.io/gengo/types/doc.go → vendor/k8s.io/gengo/v2/types/doc.go
generated
vendored
2
vendor/k8s.io/gengo/types/doc.go → vendor/k8s.io/gengo/v2/types/doc.go
generated
vendored
@@ -16,4 +16,4 @@ limitations under the License.
|
||||
|
||||
// Package types contains go type information, packaged in a way that makes
|
||||
// auto-generation convenient, whether by template or straight go functions.
|
||||
package types // import "k8s.io/gengo/types"
|
||||
package types // import "k8s.io/gengo/v2/types"
|
||||
12
vendor/k8s.io/gengo/types/types.go → vendor/k8s.io/gengo/v2/types/types.go
generated
vendored
12
vendor/k8s.io/gengo/types/types.go → vendor/k8s.io/gengo/v2/types/types.go
generated
vendored
@@ -108,14 +108,13 @@ const (
|
||||
// templates (for example). But it is strongly encouraged for code to build by
|
||||
// using the provided functions.
|
||||
type Package struct {
|
||||
// Canonical name of this package-- its path.
|
||||
// Canonical import-path of this package.
|
||||
Path string
|
||||
|
||||
// The location this package was loaded from
|
||||
SourcePath string
|
||||
// The location (on disk) of this package.
|
||||
Dir string
|
||||
|
||||
// Short name of this package; the name that appears in the
|
||||
// 'package x' line.
|
||||
// Short name of this package, as in the 'package x' line.
|
||||
Name string
|
||||
|
||||
// The comment right above the package declaration in doc.go, if any.
|
||||
@@ -359,6 +358,9 @@ type Type struct {
|
||||
|
||||
// String returns the name of the type.
|
||||
func (t *Type) String() string {
|
||||
if t == nil {
|
||||
return "" // makes tests easier
|
||||
}
|
||||
return t.Name.String()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user