Custom resource definition
Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
This commit is contained in:
parent
cfaf47c8a2
commit
4c060a78cc
1348 changed files with 92364 additions and 55766 deletions
202
vendor/k8s.io/gengo/LICENSE
generated
vendored
Normal file
202
vendor/k8s.io/gengo/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014 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.
|
199
vendor/k8s.io/gengo/args/args.go
generated
vendored
Normal file
199
vendor/k8s.io/gengo/args/args.go
generated
vendored
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
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"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"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
|
||||
|
||||
// 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{}
|
||||
|
||||
// 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.")
|
||||
}
|
||||
|
||||
// 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().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()
|
||||
// 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
|
||||
}
|
||||
|
||||
// InputIncludes returns true if the given package is a (sub) package of one of
|
||||
// the InputDirs.
|
||||
func (g *GeneratorArgs) InputIncludes(p *types.Package) bool {
|
||||
for _, dir := range g.InputDirs {
|
||||
d := dir
|
||||
if strings.HasSuffix(d, "...") {
|
||||
d = strings.TrimSuffix(d, "...")
|
||||
}
|
||||
if strings.HasPrefix(p.Path, d) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
c, err := generator.NewContext(b, nameSystems, defaultSystem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed making a context: %v", err)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
912
vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go
generated
vendored
Normal file
912
vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go
generated
vendored
Normal file
|
@ -0,0 +1,912 @@
|
|||
/*
|
||||
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"
|
||||
)
|
||||
|
||||
// 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("// +build !%s\n\n", 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.
|
||||
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) {
|
||||
klog.Fatalf("Type %v requests deepcopy generation but is not copyable", t)
|
||||
}
|
||||
pkgNeedsGeneration = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
c.AddDir(t.Package)
|
||||
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.", uet)
|
||||
}
|
||||
|
||||
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:
|
||||
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.", uet)
|
||||
}
|
||||
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 {
|
||||
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.", uet)
|
||||
}
|
||||
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.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:
|
||||
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.", uft)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.", uet)
|
||||
}
|
||||
}
|
828
vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go
generated
vendored
Normal file
828
vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go
generated
vendored
Normal file
|
@ -0,0 +1,828 @@
|
|||
/*
|
||||
Copyright 2016 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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// CustomArgs is used tby the go2idl framework to pass args specific to this
|
||||
// generator.
|
||||
type CustomArgs struct {
|
||||
ExtraPeerDirs []string // Always consider these as last-ditch possibilities for conversions.
|
||||
}
|
||||
|
||||
// These are the comment tags that carry parameters for defaulter generation.
|
||||
const tagName = "k8s:defaulter-gen"
|
||||
const intputTagName = "k8s:defaulter-gen-input"
|
||||
|
||||
func extractTag(comments []string) []string {
|
||||
return types.ExtractCommentTags("+", comments)[tagName]
|
||||
}
|
||||
|
||||
func extractInputTag(comments []string) []string {
|
||||
return types.ExtractCommentTags("+", comments)[intputTagName]
|
||||
}
|
||||
|
||||
func checkTag(comments []string, require ...string) bool {
|
||||
values := types.ExtractCommentTags("+", comments)[tagName]
|
||||
if len(require) == 0 {
|
||||
return len(values) == 1 && values[0] == ""
|
||||
}
|
||||
return reflect.DeepEqual(values, require)
|
||||
}
|
||||
|
||||
func defaultFnNamer() *namer.NameStrategy {
|
||||
return &namer.NameStrategy{
|
||||
Prefix: "SetDefaults_",
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return pre + strings.Join(in, "_") + post
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func objectDefaultFnNamer() *namer.NameStrategy {
|
||||
return &namer.NameStrategy{
|
||||
Prefix: "SetObjectDefaults_",
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return pre + strings.Join(in, "_") + post
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"public": namer.NewPublicNamer(1),
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
"defaultfn": defaultFnNamer(),
|
||||
"objectdefaultfn": objectDefaultFnNamer(),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "public"
|
||||
}
|
||||
|
||||
// defaults holds the declared defaulting functions for a given type (all defaulting functions
|
||||
// are expected to be func(1))
|
||||
type defaults struct {
|
||||
// object is the defaulter function for a top level type (typically one with TypeMeta) that
|
||||
// invokes all child defaulters. May be nil if the object defaulter has not yet been generated.
|
||||
object *types.Type
|
||||
// base is a defaulter function defined for a type SetDefaults_Pod which does not invoke all
|
||||
// child defaults - the base defaulter alone is insufficient to default a type
|
||||
base *types.Type
|
||||
// additional is zero or more defaulter functions of the form SetDefaults_Pod_XXXX that can be
|
||||
// included in the Object defaulter.
|
||||
additional []*types.Type
|
||||
}
|
||||
|
||||
// All of the types in conversions map are of type "DeclarationOf" with
|
||||
// the underlying type being "Func".
|
||||
type defaulterFuncMap map[*types.Type]defaults
|
||||
|
||||
// Returns all manually-defined defaulting functions in the package.
|
||||
func getManualDefaultingFunctions(context *generator.Context, pkg *types.Package, manualMap defaulterFuncMap) {
|
||||
buffer := &bytes.Buffer{}
|
||||
sw := generator.NewSnippetWriter(buffer, context, "$", "$")
|
||||
|
||||
for _, f := range pkg.Functions {
|
||||
if f.Underlying == nil || f.Underlying.Kind != types.Func {
|
||||
klog.Errorf("Malformed function: %#v", f)
|
||||
continue
|
||||
}
|
||||
if f.Underlying.Signature == nil {
|
||||
klog.Errorf("Function without signature: %#v", f)
|
||||
continue
|
||||
}
|
||||
signature := f.Underlying.Signature
|
||||
// Check whether the function is defaulting function.
|
||||
// Note that all of them have signature:
|
||||
// object: func SetObjectDefaults_inType(*inType)
|
||||
// base: func SetDefaults_inType(*inType)
|
||||
// additional: func SetDefaults_inType_Qualifier(*inType)
|
||||
if signature.Receiver != nil {
|
||||
continue
|
||||
}
|
||||
if len(signature.Parameters) != 1 {
|
||||
continue
|
||||
}
|
||||
if len(signature.Results) != 0 {
|
||||
continue
|
||||
}
|
||||
inType := signature.Parameters[0]
|
||||
if inType.Kind != types.Pointer {
|
||||
continue
|
||||
}
|
||||
// Check if this is the primary defaulter.
|
||||
args := defaultingArgsFromType(inType.Elem)
|
||||
sw.Do("$.inType|defaultfn$", args)
|
||||
switch {
|
||||
case f.Name.Name == buffer.String():
|
||||
key := inType.Elem
|
||||
// We might scan the same package twice, and that's OK.
|
||||
v, ok := manualMap[key]
|
||||
if ok && v.base != nil && v.base.Name.Package != pkg.Path {
|
||||
panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key))
|
||||
}
|
||||
v.base = f
|
||||
manualMap[key] = v
|
||||
klog.V(6).Infof("found base defaulter function for %s from %s", key.Name, f.Name)
|
||||
// Is one of the additional defaulters - a top level defaulter on a type that is
|
||||
// also invoked.
|
||||
case strings.HasPrefix(f.Name.Name, buffer.String()+"_"):
|
||||
key := inType.Elem
|
||||
v, ok := manualMap[key]
|
||||
if ok {
|
||||
exists := false
|
||||
for _, existing := range v.additional {
|
||||
if existing.Name == f.Name {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
}
|
||||
v.additional = append(v.additional, f)
|
||||
manualMap[key] = v
|
||||
klog.V(6).Infof("found additional defaulter function for %s from %s", key.Name, f.Name)
|
||||
}
|
||||
buffer.Reset()
|
||||
sw.Do("$.inType|objectdefaultfn$", args)
|
||||
if f.Name.Name == buffer.String() {
|
||||
key := inType.Elem
|
||||
// We might scan the same package twice, and that's OK.
|
||||
v, ok := manualMap[key]
|
||||
if ok && v.base != nil && v.base.Name.Package != pkg.Path {
|
||||
panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key))
|
||||
}
|
||||
v.object = f
|
||||
manualMap[key] = v
|
||||
klog.V(6).Infof("found object defaulter function for %s from %s", key.Name, f.Name)
|
||||
}
|
||||
buffer.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
boilerplate, err := arguments.LoadGoBoilerplate()
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed loading boilerplate: %v", err)
|
||||
}
|
||||
|
||||
packages := generator.Packages{}
|
||||
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
|
||||
|
||||
// Accumulate pre-existing default functions.
|
||||
// TODO: This is too ad-hoc. We need a better way.
|
||||
existingDefaulters := defaulterFuncMap{}
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
sw := generator.NewSnippetWriter(buffer, context, "$", "$")
|
||||
|
||||
// We are generating defaults only for packages that are explicitly
|
||||
// passed as InputDir.
|
||||
for _, i := range context.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
|
||||
}
|
||||
// typesPkg is where the types that needs defaulter are defined.
|
||||
// Sometimes it is different from pkg. For example, kubernetes core/v1
|
||||
// types are defined in vendor/k8s.io/api/core/v1, while pkg is at
|
||||
// pkg/api/v1.
|
||||
typesPkg := pkg
|
||||
|
||||
// Add defaulting functions.
|
||||
getManualDefaultingFunctions(context, pkg, existingDefaulters)
|
||||
|
||||
var peerPkgs []string
|
||||
if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
|
||||
for _, pkg := range customArgs.ExtraPeerDirs {
|
||||
if i := strings.Index(pkg, "/vendor/"); i != -1 {
|
||||
pkg = pkg[i+len("/vendor/"):]
|
||||
}
|
||||
peerPkgs = append(peerPkgs, pkg)
|
||||
}
|
||||
}
|
||||
// Make sure our peer-packages are added and fully parsed.
|
||||
for _, pp := range peerPkgs {
|
||||
context.AddDir(pp)
|
||||
getManualDefaultingFunctions(context, context.Universe[pp], existingDefaulters)
|
||||
}
|
||||
|
||||
typesWith := extractTag(pkg.Comments)
|
||||
shouldCreateObjectDefaulterFn := func(t *types.Type) bool {
|
||||
if defaults, ok := existingDefaulters[t]; ok && defaults.object != nil {
|
||||
// A default generator is defined
|
||||
klog.V(5).Infof(" an object defaulter already exists as %s", defaults.base.Name)
|
||||
return false
|
||||
}
|
||||
// opt-out
|
||||
if checkTag(t.SecondClosestCommentLines, "false") {
|
||||
return false
|
||||
}
|
||||
// opt-in
|
||||
if checkTag(t.SecondClosestCommentLines, "true") {
|
||||
return true
|
||||
}
|
||||
// For every k8s:defaulter-gen tag at the package level, interpret the value as a
|
||||
// field name (like TypeMeta, ListMeta, ObjectMeta) and trigger defaulter generation
|
||||
// for any type with any of the matching field names. Provides a more useful package
|
||||
// level defaulting than global (because we only need defaulters on a subset of objects -
|
||||
// usually those with TypeMeta).
|
||||
if t.Kind == types.Struct && len(typesWith) > 0 {
|
||||
for _, field := range t.Members {
|
||||
for _, s := range typesWith {
|
||||
if field.Name == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// if the types are not in the same package where the defaulter functions to be generated
|
||||
inputTags := extractInputTag(pkg.Comments)
|
||||
if len(inputTags) > 1 {
|
||||
panic(fmt.Sprintf("there could only be one input tag, got %#v", inputTags))
|
||||
}
|
||||
if len(inputTags) == 1 {
|
||||
var err error
|
||||
typesPkg, err = context.AddDirectory(filepath.Join(pkg.Path, inputTags[0]))
|
||||
if err != nil {
|
||||
klog.Fatalf("cannot import package %s", inputTags[0])
|
||||
}
|
||||
// update context.Order to the latest context.Universe
|
||||
orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)}
|
||||
context.Order = orderer.OrderUniverse(context.Universe)
|
||||
}
|
||||
|
||||
newDefaulters := defaulterFuncMap{}
|
||||
for _, t := range typesPkg.Types {
|
||||
if !shouldCreateObjectDefaulterFn(t) {
|
||||
continue
|
||||
}
|
||||
if namer.IsPrivateGoName(t.Name.Name) {
|
||||
// We won't be able to convert to a private type.
|
||||
klog.V(5).Infof(" found a type %v, but it is a private name", t)
|
||||
continue
|
||||
}
|
||||
|
||||
// create a synthetic type we can use during generation
|
||||
newDefaulters[t] = defaults{}
|
||||
}
|
||||
|
||||
// only generate defaulters for objects that actually have defined defaulters
|
||||
// prevents empty defaulters from being registered
|
||||
for {
|
||||
promoted := 0
|
||||
for t, d := range newDefaulters {
|
||||
if d.object != nil {
|
||||
continue
|
||||
}
|
||||
if newCallTreeForType(existingDefaulters, newDefaulters).build(t, true) != nil {
|
||||
args := defaultingArgsFromType(t)
|
||||
sw.Do("$.inType|objectdefaultfn$", args)
|
||||
newDefaulters[t] = defaults{
|
||||
object: &types.Type{
|
||||
Name: types.Name{
|
||||
Package: pkg.Path,
|
||||
Name: buffer.String(),
|
||||
},
|
||||
Kind: types.Func,
|
||||
},
|
||||
}
|
||||
buffer.Reset()
|
||||
promoted++
|
||||
}
|
||||
}
|
||||
if promoted != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// prune any types that were not used
|
||||
for t, d := range newDefaulters {
|
||||
if d.object == nil {
|
||||
klog.V(6).Infof("did not generate defaulter for %s because no child defaulters were registered", t.Name)
|
||||
delete(newDefaulters, t)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if len(newDefaulters) == 0 {
|
||||
klog.V(5).Infof("no defaulters in package %s", pkg.Name)
|
||||
}
|
||||
|
||||
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: filepath.Base(pkg.Path),
|
||||
PackagePath: path,
|
||||
HeaderText: header,
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
return []generator.Generator{
|
||||
NewGenDefaulter(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, existingDefaulters, newDefaulters, peerPkgs),
|
||||
}
|
||||
},
|
||||
FilterFunc: func(c *generator.Context, t *types.Type) bool {
|
||||
return t.Name.Package == typesPkg.Path
|
||||
},
|
||||
})
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
// callTreeForType contains fields necessary to build a tree for types.
|
||||
type callTreeForType struct {
|
||||
existingDefaulters defaulterFuncMap
|
||||
newDefaulters defaulterFuncMap
|
||||
currentlyBuildingTypes map[*types.Type]bool
|
||||
}
|
||||
|
||||
func newCallTreeForType(existingDefaulters, newDefaulters defaulterFuncMap) *callTreeForType {
|
||||
return &callTreeForType{
|
||||
existingDefaulters: existingDefaulters,
|
||||
newDefaulters: newDefaulters,
|
||||
currentlyBuildingTypes: make(map[*types.Type]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// build creates a tree of paths to fields (based on how they would be accessed in Go - pointer, elem,
|
||||
// slice, or key) and the functions that should be invoked on each field. An in-order traversal of the resulting tree
|
||||
// can be used to generate a Go function that invokes each nested function on the appropriate type. The return
|
||||
// value may be nil if there are no functions to call on type or the type is a primitive (Defaulters can only be
|
||||
// invoked on structs today). When root is true this function will not use a newDefaulter. existingDefaulters should
|
||||
// contain all defaulting functions by type defined in code - newDefaulters should contain all object defaulters
|
||||
// that could be or will be generated. If newDefaulters has an entry for a type, but the 'object' field is nil,
|
||||
// this function skips adding that defaulter - this allows us to avoid generating object defaulter functions for
|
||||
// list types that call empty defaulters.
|
||||
func (c *callTreeForType) build(t *types.Type, root bool) *callNode {
|
||||
parent := &callNode{}
|
||||
|
||||
if root {
|
||||
// the root node is always a pointer
|
||||
parent.elem = true
|
||||
}
|
||||
|
||||
defaults, _ := c.existingDefaulters[t]
|
||||
newDefaults, generated := c.newDefaulters[t]
|
||||
switch {
|
||||
case !root && generated && newDefaults.object != nil:
|
||||
parent.call = append(parent.call, newDefaults.object)
|
||||
// if we will be generating the defaulter, it by definition is a covering
|
||||
// defaulter, so we halt recursion
|
||||
klog.V(6).Infof("the defaulter %s will be generated as an object defaulter", t.Name)
|
||||
return parent
|
||||
|
||||
case defaults.object != nil:
|
||||
// object defaulters are always covering
|
||||
parent.call = append(parent.call, defaults.object)
|
||||
return parent
|
||||
|
||||
case defaults.base != nil:
|
||||
parent.call = append(parent.call, defaults.base)
|
||||
// if the base function indicates it "covers" (it already includes defaulters)
|
||||
// we can halt recursion
|
||||
if checkTag(defaults.base.CommentLines, "covers") {
|
||||
klog.V(6).Infof("the defaulter %s indicates it covers all sub generators", t.Name)
|
||||
return parent
|
||||
}
|
||||
}
|
||||
|
||||
// base has been added already, now add any additional defaulters defined for this object
|
||||
parent.call = append(parent.call, defaults.additional...)
|
||||
|
||||
// if the type already exists, don't build the tree for it and don't generate anything.
|
||||
// This is used to avoid recursion for nested recursive types.
|
||||
if c.currentlyBuildingTypes[t] {
|
||||
return nil
|
||||
}
|
||||
// if type doesn't exist, mark it as existing
|
||||
c.currentlyBuildingTypes[t] = true
|
||||
|
||||
defer func() {
|
||||
// The type will now acts as a parent, not a nested recursive type.
|
||||
// We can now build the tree for it safely.
|
||||
c.currentlyBuildingTypes[t] = false
|
||||
}()
|
||||
|
||||
switch t.Kind {
|
||||
case types.Pointer:
|
||||
if child := c.build(t.Elem, false); child != nil {
|
||||
child.elem = true
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
case types.Slice, types.Array:
|
||||
if child := c.build(t.Elem, false); child != nil {
|
||||
child.index = true
|
||||
if t.Elem.Kind == types.Pointer {
|
||||
child.elem = true
|
||||
}
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
case types.Map:
|
||||
if child := c.build(t.Elem, false); child != nil {
|
||||
child.key = true
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
case types.Struct:
|
||||
for _, field := range t.Members {
|
||||
name := field.Name
|
||||
if len(name) == 0 {
|
||||
if field.Type.Kind == types.Pointer {
|
||||
name = field.Type.Elem.Name.Name
|
||||
} else {
|
||||
name = field.Type.Name.Name
|
||||
}
|
||||
}
|
||||
if child := c.build(field.Type, false); child != nil {
|
||||
child.field = name
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
}
|
||||
case types.Alias:
|
||||
if child := c.build(t.Underlying, false); child != nil {
|
||||
parent.children = append(parent.children, *child)
|
||||
}
|
||||
}
|
||||
if len(parent.children) == 0 && len(parent.call) == 0 {
|
||||
//klog.V(6).Infof("decided type %s needs no generation", t.Name)
|
||||
return nil
|
||||
}
|
||||
return parent
|
||||
}
|
||||
|
||||
const (
|
||||
runtimePackagePath = "k8s.io/apimachinery/pkg/runtime"
|
||||
conversionPackagePath = "k8s.io/apimachinery/pkg/conversion"
|
||||
)
|
||||
|
||||
// genDefaulter produces a file with a autogenerated conversions.
|
||||
type genDefaulter struct {
|
||||
generator.DefaultGen
|
||||
typesPackage string
|
||||
outputPackage string
|
||||
peerPackages []string
|
||||
newDefaulters defaulterFuncMap
|
||||
existingDefaulters defaulterFuncMap
|
||||
imports namer.ImportTracker
|
||||
typesForInit []*types.Type
|
||||
}
|
||||
|
||||
func NewGenDefaulter(sanitizedName, typesPackage, outputPackage string, existingDefaulters, newDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator {
|
||||
return &genDefaulter{
|
||||
DefaultGen: generator.DefaultGen{
|
||||
OptionalName: sanitizedName,
|
||||
},
|
||||
typesPackage: typesPackage,
|
||||
outputPackage: outputPackage,
|
||||
peerPackages: peerPkgs,
|
||||
newDefaulters: newDefaulters,
|
||||
existingDefaulters: existingDefaulters,
|
||||
imports: generator.NewImportTracker(),
|
||||
typesForInit: make([]*types.Type, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDefaulter) Namers(c *generator.Context) namer.NameSystems {
|
||||
// Have the raw namer for this file track what it imports.
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDefaulter) isOtherPackage(pkg string) bool {
|
||||
if pkg == g.outputPackage {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(pkg, `"`+g.outputPackage+`"`) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genDefaulter) Filter(c *generator.Context, t *types.Type) bool {
|
||||
defaults, ok := g.newDefaulters[t]
|
||||
if !ok || defaults.object == nil {
|
||||
return false
|
||||
}
|
||||
g.typesForInit = append(g.typesForInit, t)
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genDefaulter) Imports(c *generator.Context) (imports []string) {
|
||||
var importLines []string
|
||||
for _, singleImport := range g.imports.ImportLines() {
|
||||
if g.isOtherPackage(singleImport) {
|
||||
importLines = append(importLines, singleImport)
|
||||
}
|
||||
}
|
||||
return importLines
|
||||
}
|
||||
|
||||
func (g *genDefaulter) Init(c *generator.Context, w io.Writer) error {
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
|
||||
scheme := c.Universe.Type(types.Name{Package: runtimePackagePath, Name: "Scheme"})
|
||||
schemePtr := &types.Type{
|
||||
Kind: types.Pointer,
|
||||
Elem: scheme,
|
||||
}
|
||||
sw.Do("// RegisterDefaults adds defaulters functions to the given scheme.\n", nil)
|
||||
sw.Do("// Public to allow building arbitrary schemes.\n", nil)
|
||||
sw.Do("// All generated defaulters are covering - they call all nested defaulters.\n", nil)
|
||||
sw.Do("func RegisterDefaults(scheme $.|raw$) error {\n", schemePtr)
|
||||
for _, t := range g.typesForInit {
|
||||
args := defaultingArgsFromType(t)
|
||||
sw.Do("scheme.AddTypeDefaultingFunc(&$.inType|raw${}, func(obj interface{}) { $.inType|objectdefaultfn$(obj.(*$.inType|raw$)) })\n", args)
|
||||
}
|
||||
sw.Do("return nil\n", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func (g *genDefaulter) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
if _, ok := g.newDefaulters[t]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
klog.V(5).Infof("generating for type %v", t)
|
||||
|
||||
callTree := newCallTreeForType(g.existingDefaulters, g.newDefaulters).build(t, true)
|
||||
if callTree == nil {
|
||||
klog.V(5).Infof(" no defaulters defined")
|
||||
return nil
|
||||
}
|
||||
i := 0
|
||||
callTree.VisitInOrder(func(ancestors []*callNode, current *callNode) {
|
||||
if len(current.call) == 0 {
|
||||
return
|
||||
}
|
||||
path := callPath(append(ancestors, current))
|
||||
klog.V(5).Infof(" %d: %s", i, path)
|
||||
i++
|
||||
})
|
||||
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
g.generateDefaulter(t, callTree, sw)
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func defaultingArgsFromType(inType *types.Type) generator.Args {
|
||||
return generator.Args{
|
||||
"inType": inType,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genDefaulter) generateDefaulter(inType *types.Type, callTree *callNode, sw *generator.SnippetWriter) {
|
||||
sw.Do("func $.inType|objectdefaultfn$(in *$.inType|raw$) {\n", defaultingArgsFromType(inType))
|
||||
callTree.WriteMethod("in", 0, nil, sw)
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
|
||||
// callNode represents an entry in a tree of Go type accessors - the path from the root to a leaf represents
|
||||
// how in Go code an access would be performed. For example, if a defaulting function exists on a container
|
||||
// lifecycle hook, to invoke that defaulter correctly would require this Go code:
|
||||
//
|
||||
// for i := range pod.Spec.Containers {
|
||||
// o := &pod.Spec.Containers[i]
|
||||
// if o.LifecycleHook != nil {
|
||||
// SetDefaults_LifecycleHook(o.LifecycleHook)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// That would be represented by a call tree like:
|
||||
//
|
||||
// callNode
|
||||
// field: "Spec"
|
||||
// children:
|
||||
// - field: "Containers"
|
||||
// children:
|
||||
// - index: true
|
||||
// children:
|
||||
// - field: "LifecycleHook"
|
||||
// elem: true
|
||||
// call:
|
||||
// - SetDefaults_LifecycleHook
|
||||
//
|
||||
// which we can traverse to build that Go struct (you must call the field Spec, then Containers, then range over
|
||||
// that field, then check whether the LifecycleHook field is nil, before calling SetDefaults_LifecycleHook on
|
||||
// the pointer to that field).
|
||||
type callNode struct {
|
||||
// field is the name of the Go member to access
|
||||
field string
|
||||
// key is true if this is a map and we must range over the key and values
|
||||
key bool
|
||||
// index is true if this is a slice and we must range over the slice values
|
||||
index bool
|
||||
// elem is true if the previous elements refer to a pointer (typically just field)
|
||||
elem bool
|
||||
|
||||
// call is all of the functions that must be invoked on this particular node, in order
|
||||
call []*types.Type
|
||||
// children is the child call nodes that must also be traversed
|
||||
children []callNode
|
||||
}
|
||||
|
||||
// CallNodeVisitorFunc is a function for visiting a call tree. ancestors is the list of all parents
|
||||
// of this node to the root of the tree - will be empty at the root.
|
||||
type CallNodeVisitorFunc func(ancestors []*callNode, node *callNode)
|
||||
|
||||
func (n *callNode) VisitInOrder(fn CallNodeVisitorFunc) {
|
||||
n.visitInOrder(nil, fn)
|
||||
}
|
||||
|
||||
func (n *callNode) visitInOrder(ancestors []*callNode, fn CallNodeVisitorFunc) {
|
||||
fn(ancestors, n)
|
||||
ancestors = append(ancestors, n)
|
||||
for i := range n.children {
|
||||
n.children[i].visitInOrder(ancestors, fn)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
indexVariables = "ijklmnop"
|
||||
localVariables = "abcdefgh"
|
||||
)
|
||||
|
||||
// varsForDepth creates temporary variables guaranteed to be unique within lexical Go scopes
|
||||
// of this depth in a function. It uses canonical Go loop variables for the first 7 levels
|
||||
// and then resorts to uglier prefixes.
|
||||
func varsForDepth(depth int) (index, local string) {
|
||||
if depth > len(indexVariables) {
|
||||
index = fmt.Sprintf("i%d", depth)
|
||||
} else {
|
||||
index = indexVariables[depth : depth+1]
|
||||
}
|
||||
if depth > len(localVariables) {
|
||||
local = fmt.Sprintf("local%d", depth)
|
||||
} else {
|
||||
local = localVariables[depth : depth+1]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// writeCalls generates a list of function calls based on the calls field for the provided variable
|
||||
// name and pointer.
|
||||
func (n *callNode) writeCalls(varName string, isVarPointer bool, sw *generator.SnippetWriter) {
|
||||
accessor := varName
|
||||
if !isVarPointer {
|
||||
accessor = "&" + accessor
|
||||
}
|
||||
for _, fn := range n.call {
|
||||
sw.Do("$.fn|raw$($.var$)\n", generator.Args{
|
||||
"fn": fn,
|
||||
"var": accessor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// WriteMethod performs an in-order traversal of the calltree, generating loops and if blocks as necessary
|
||||
// to correctly turn the call tree into a method body that invokes all calls on all child nodes of the call tree.
|
||||
// Depth is used to generate local variables at the proper depth.
|
||||
func (n *callNode) WriteMethod(varName string, depth int, ancestors []*callNode, sw *generator.SnippetWriter) {
|
||||
// if len(n.call) > 0 {
|
||||
// sw.Do(fmt.Sprintf("// %s\n", callPath(append(ancestors, n)).String()), nil)
|
||||
// }
|
||||
|
||||
if len(n.field) > 0 {
|
||||
varName = varName + "." + n.field
|
||||
}
|
||||
|
||||
index, local := varsForDepth(depth)
|
||||
vars := generator.Args{
|
||||
"index": index,
|
||||
"local": local,
|
||||
"var": varName,
|
||||
}
|
||||
|
||||
isPointer := n.elem && !n.index
|
||||
if isPointer && len(ancestors) > 0 {
|
||||
sw.Do("if $.var$ != nil {\n", vars)
|
||||
}
|
||||
|
||||
switch {
|
||||
case n.index:
|
||||
sw.Do("for $.index$ := range $.var$ {\n", vars)
|
||||
if n.elem {
|
||||
sw.Do("$.local$ := $.var$[$.index$]\n", vars)
|
||||
} else {
|
||||
sw.Do("$.local$ := &$.var$[$.index$]\n", vars)
|
||||
}
|
||||
|
||||
n.writeCalls(local, true, sw)
|
||||
for i := range n.children {
|
||||
n.children[i].WriteMethod(local, depth+1, append(ancestors, n), sw)
|
||||
}
|
||||
sw.Do("}\n", nil)
|
||||
case n.key:
|
||||
default:
|
||||
n.writeCalls(varName, isPointer, sw)
|
||||
for i := range n.children {
|
||||
n.children[i].WriteMethod(varName, depth, append(ancestors, n), sw)
|
||||
}
|
||||
}
|
||||
|
||||
if isPointer && len(ancestors) > 0 {
|
||||
sw.Do("}\n", nil)
|
||||
}
|
||||
}
|
||||
|
||||
type callPath []*callNode
|
||||
|
||||
// String prints a representation of a callPath that roughly approximates what a Go accessor
|
||||
// would look like. Used for debugging only.
|
||||
func (path callPath) String() string {
|
||||
if len(path) == 0 {
|
||||
return "<none>"
|
||||
}
|
||||
var parts []string
|
||||
for _, p := range path {
|
||||
last := len(parts) - 1
|
||||
switch {
|
||||
case p.elem:
|
||||
if len(parts) > 0 {
|
||||
parts[last] = "*" + parts[last]
|
||||
} else {
|
||||
parts = append(parts, "*")
|
||||
}
|
||||
case p.index:
|
||||
if len(parts) > 0 {
|
||||
parts[last] = parts[last] + "[i]"
|
||||
} else {
|
||||
parts = append(parts, "[i]")
|
||||
}
|
||||
case p.key:
|
||||
if len(parts) > 0 {
|
||||
parts[last] = parts[last] + "[key]"
|
||||
} else {
|
||||
parts = append(parts, "[key]")
|
||||
}
|
||||
default:
|
||||
if len(p.field) > 0 {
|
||||
parts = append(parts, p.field)
|
||||
} else {
|
||||
parts = append(parts, "<root>")
|
||||
}
|
||||
}
|
||||
}
|
||||
var calls []string
|
||||
for _, fn := range path[len(path)-1].call {
|
||||
calls = append(calls, fn.Name.String())
|
||||
}
|
||||
if len(calls) == 0 {
|
||||
calls = append(calls, "<none>")
|
||||
}
|
||||
|
||||
return strings.Join(parts, ".") + " calls " + strings.Join(calls, ", ")
|
||||
}
|
203
vendor/k8s.io/gengo/examples/set-gen/sets/byte.go
generated
vendored
Normal file
203
vendor/k8s.io/gengo/examples/set-gen/sets/byte.go
generated
vendored
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
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 := Byte{}
|
||||
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) {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Byte) Delete(items ...byte) {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 (s Byte) Difference(s2 Byte) Byte {
|
||||
result := NewByte()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 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 := NewByte()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
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
Normal file
20
vendor/k8s.io/gengo/examples/set-gen/sets/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
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
Normal file
23
vendor/k8s.io/gengo/examples/set-gen/sets/empty.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
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{}
|
203
vendor/k8s.io/gengo/examples/set-gen/sets/int.go
generated
vendored
Normal file
203
vendor/k8s.io/gengo/examples/set-gen/sets/int.go
generated
vendored
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
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 := Int{}
|
||||
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) {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Int) Delete(items ...int) {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 (s Int) Difference(s2 Int) Int {
|
||||
result := NewInt()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 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 := NewInt()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
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
|
||||
}
|
203
vendor/k8s.io/gengo/examples/set-gen/sets/int64.go
generated
vendored
Normal file
203
vendor/k8s.io/gengo/examples/set-gen/sets/int64.go
generated
vendored
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
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 := Int64{}
|
||||
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) {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s Int64) Delete(items ...int64) {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 (s Int64) Difference(s2 Int64) Int64 {
|
||||
result := NewInt64()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 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 := NewInt64()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
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
|
||||
}
|
203
vendor/k8s.io/gengo/examples/set-gen/sets/string.go
generated
vendored
Normal file
203
vendor/k8s.io/gengo/examples/set-gen/sets/string.go
generated
vendored
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
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 := String{}
|
||||
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) {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s String) Delete(items ...string) {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 (s String) Difference(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 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 := NewString()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
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
Normal file
62
vendor/k8s.io/gengo/generator/default_generator.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
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{})
|
||||
)
|
72
vendor/k8s.io/gengo/generator/default_package.go
generated
vendored
Normal file
72
vendor/k8s.io/gengo/generator/default_package.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
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
|
||||
|
||||
// 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) 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{})
|
||||
)
|
31
vendor/k8s.io/gengo/generator/doc.go
generated
vendored
Normal file
31
vendor/k8s.io/gengo/generator/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
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 defines an interface for code generators to implement.
|
||||
//
|
||||
// To use this package, you'll implement the "Package" and "Generator"
|
||||
// interfaces; you'll call NewContext to load up the types you want to work
|
||||
// with, and then you'll call one or more of the Execute methods. See the
|
||||
// interface definitions for explanations. All output will have gofmt called on
|
||||
// it automatically, so you do not need to worry about generating correct
|
||||
// indentation.
|
||||
//
|
||||
// This package also exposes SnippetWriter. SnippetWriter reduces to a minimum
|
||||
// the boilerplate involved in setting up a template from go's text/template
|
||||
// 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"
|
50
vendor/k8s.io/gengo/generator/error_tracker.go
generated
vendored
Normal file
50
vendor/k8s.io/gengo/generator/error_tracker.go
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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"
|
||||
)
|
||||
|
||||
// ErrorTracker tracks errors to the underlying writer, so that you can ignore
|
||||
// them until you're ready to return.
|
||||
type ErrorTracker struct {
|
||||
io.Writer
|
||||
err error
|
||||
}
|
||||
|
||||
// NewErrorTracker makes a new error tracker; note that it implements io.Writer.
|
||||
func NewErrorTracker(w io.Writer) *ErrorTracker {
|
||||
return &ErrorTracker{Writer: w}
|
||||
}
|
||||
|
||||
// Write intercepts calls to Write.
|
||||
func (et *ErrorTracker) Write(p []byte) (n int, err error) {
|
||||
if et.err != nil {
|
||||
return 0, et.err
|
||||
}
|
||||
n, err = et.Writer.Write(p)
|
||||
if err != nil {
|
||||
et.err = err
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Error returns nil if no error has occurred, otherwise it returns the error.
|
||||
func (et *ErrorTracker) Error() error {
|
||||
return et.err
|
||||
}
|
312
vendor/k8s.io/gengo/generator/execute.go
generated
vendored
Normal file
312
vendor/k8s.io/gengo/generator/execute.go
generated
vendored
Normal file
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/imports"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
func errs2strings(errors []error) []string {
|
||||
strs := make([]string, len(errors))
|
||||
for i := range errors {
|
||||
strs[i] = errors[i].Error()
|
||||
}
|
||||
return strs
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return fmt.Errorf("some packages had errors:\n%v\n", strings.Join(errs2strings(errors), "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DefaultFileType struct {
|
||||
Format func([]byte) ([]byte, error)
|
||||
Assemble func(io.Writer, *File)
|
||||
}
|
||||
|
||||
func (ft DefaultFileType) AssembleFile(f *File, pathname string) error {
|
||||
klog.V(2).Infof("Assembling file %q", pathname)
|
||||
destFile, err := os.Create(pathname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
et := NewErrorTracker(b)
|
||||
ft.Assemble(et, f)
|
||||
if et.Error() != nil {
|
||||
return et.Error()
|
||||
}
|
||||
if formatted, err := ft.Format(b.Bytes()); err != nil {
|
||||
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
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
_, err = destFile.Write(formatted)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (ft DefaultFileType) VerifyFile(f *File, pathname string) error {
|
||||
klog.V(2).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) {
|
||||
w.Write(f.Header)
|
||||
fmt.Fprintf(w, "package %v\n\n", f.PackageName)
|
||||
|
||||
if len(f.Imports) > 0 {
|
||||
fmt.Fprint(w, "import (\n")
|
||||
for i := range f.Imports {
|
||||
if strings.Contains(i, "\"") {
|
||||
// they included quotes, or are using the
|
||||
// `name "path/to/pkg"` format.
|
||||
fmt.Fprintf(w, "\t%s\n", i)
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t%q\n", i)
|
||||
}
|
||||
}
|
||||
fmt.Fprint(w, ")\n\n")
|
||||
}
|
||||
|
||||
if f.Vars.Len() > 0 {
|
||||
fmt.Fprint(w, "var (\n")
|
||||
w.Write(f.Vars.Bytes())
|
||||
fmt.Fprint(w, ")\n\n")
|
||||
}
|
||||
|
||||
if f.Consts.Len() > 0 {
|
||||
fmt.Fprint(w, "const (\n")
|
||||
w.Write(f.Consts.Bytes())
|
||||
fmt.Fprint(w, ")\n\n")
|
||||
}
|
||||
|
||||
w.Write(f.Body.Bytes())
|
||||
}
|
||||
|
||||
func importsWrapper(src []byte) ([]byte, error) {
|
||||
return imports.Process("", src, nil)
|
||||
}
|
||||
|
||||
func NewGolangFile() *DefaultFileType {
|
||||
return &DefaultFileType{
|
||||
Format: importsWrapper,
|
||||
Assemble: assembleGolangFile,
|
||||
}
|
||||
}
|
||||
|
||||
// format should be one line only, and not end with \n.
|
||||
func addIndentHeaderComment(b *bytes.Buffer, format string, args ...interface{}) {
|
||||
if b.Len() > 0 {
|
||||
fmt.Fprintf(b, "\n// "+format+"\n", args...)
|
||||
} else {
|
||||
fmt.Fprintf(b, "// "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) filteredBy(f func(*Context, *types.Type) bool) *Context {
|
||||
c2 := *c
|
||||
c2.Order = []*types.Type{}
|
||||
for _, t := range c.Order {
|
||||
if f(c, t) {
|
||||
c2.Order = append(c2.Order, t)
|
||||
}
|
||||
}
|
||||
return &c2
|
||||
}
|
||||
|
||||
// make a new context; inheret c.Namers, but add on 'namers'. In case of a name
|
||||
// collision, the namer in 'namers' wins.
|
||||
func (c *Context) addNameSystems(namers namer.NameSystems) *Context {
|
||||
if namers == nil {
|
||||
return c
|
||||
}
|
||||
c2 := *c
|
||||
// Copy the existing name systems so we don't corrupt a parent context
|
||||
c2.Namers = namer.NameSystems{}
|
||||
for k, v := range c.Namers {
|
||||
c2.Namers[k] = v
|
||||
}
|
||||
|
||||
for name, namer := range namers {
|
||||
c2.Namers[name] = namer
|
||||
}
|
||||
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())
|
||||
klog.V(2).Infof("Processing package %q, disk location %q", p.Name(), path)
|
||||
// Filter out any types the *package* doesn't care about.
|
||||
packageContext := c.filteredBy(p.Filter)
|
||||
os.MkdirAll(path, 0755)
|
||||
files := map[string]*File{}
|
||||
for _, g := range p.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
|
||||
genContext = genContext.addNameSystems(g.Namers(genContext))
|
||||
|
||||
fileType := g.FileType()
|
||||
if len(fileType) == 0 {
|
||||
return fmt.Errorf("generator %q must specify a file type", g.Name())
|
||||
}
|
||||
f := files[g.Filename()]
|
||||
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(),
|
||||
Header: p.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())
|
||||
}
|
||||
}
|
||||
|
||||
if vars := g.PackageVars(genContext); len(vars) > 0 {
|
||||
addIndentHeaderComment(&f.Vars, "Package-wide variables from generator %q.", g.Name())
|
||||
for _, v := range vars {
|
||||
if _, err := fmt.Fprintf(&f.Vars, "%s\n", v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if consts := g.PackageConsts(genContext); len(consts) > 0 {
|
||||
addIndentHeaderComment(&f.Consts, "Package-wide consts from generator %q.", g.Name())
|
||||
for _, v := range consts {
|
||||
if _, err := fmt.Fprintf(&f.Consts, "%s\n", v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := genContext.executeBody(&f.Body, g); err != nil {
|
||||
return err
|
||||
}
|
||||
if imports := g.Imports(genContext); len(imports) > 0 {
|
||||
for _, i := range imports {
|
||||
f.Imports[i] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var errors []error
|
||||
for _, f := range files {
|
||||
finalPath := filepath.Join(path, 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 len(errors) > 0 {
|
||||
return fmt.Errorf("errors in package %q:\n%v\n", p.Path(), strings.Join(errs2strings(errors), "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Context) executeBody(w io.Writer, generator Generator) error {
|
||||
et := NewErrorTracker(w)
|
||||
if err := generator.Init(c, et); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, t := range c.Order {
|
||||
if err := generator.GenerateType(c, t, et); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := generator.Finalize(c, et); err != nil {
|
||||
return err
|
||||
}
|
||||
return et.Error()
|
||||
}
|
219
vendor/k8s.io/gengo/generator/generator.go
generated
vendored
Normal file
219
vendor/k8s.io/gengo/generator/generator.go
generated
vendored
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
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 (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/parser"
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
// Package contains the contract for generating a package.
|
||||
type Package interface {
|
||||
// Name returns the package short name.
|
||||
Name() string
|
||||
// Path returns the package import path.
|
||||
Path() string
|
||||
|
||||
// Filter should return true if this package cares about this type.
|
||||
// Otherwise, this type will be omitted from the type ordering for
|
||||
// this package.
|
||||
Filter(*Context, *types.Type) bool
|
||||
|
||||
// Header should return a header for the file, including comment markers.
|
||||
// Useful for copyright notices and doc strings. Include an
|
||||
// autogeneration notice! Do not include the "package x" line.
|
||||
Header(filename string) []byte
|
||||
|
||||
// Generators returns the list of generators for this package. It is
|
||||
// allowed for more than one generator to write to the same file.
|
||||
// A Context is passed in case the list of generators depends on the
|
||||
// input types.
|
||||
Generators(*Context) []Generator
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Name string
|
||||
FileType string
|
||||
PackageName string
|
||||
Header []byte
|
||||
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,
|
||||
// making more readable code.
|
||||
//
|
||||
// The call order for the functions that take a Context is:
|
||||
// 1. Filter() // Subsequent calls see only types that pass this.
|
||||
// 2. Namers() // Subsequent calls see the namers provided by this.
|
||||
// 3. PackageVars()
|
||||
// 4. PackageConsts()
|
||||
// 5. Init()
|
||||
// 6. GenerateType() // Called N times, once per type in the context's Order.
|
||||
// 7. Imports()
|
||||
//
|
||||
// You may have multiple generators for the same file.
|
||||
type Generator interface {
|
||||
// The name of this generator. Will be included in generated comments.
|
||||
Name() string
|
||||
|
||||
// Filter should return true if this generator cares about this type.
|
||||
// (otherwise, GenerateType will not be called.)
|
||||
//
|
||||
// Filter is called before any of the generator's other functions;
|
||||
// subsequent calls will get a context with only the types that passed
|
||||
// this filter.
|
||||
Filter(*Context, *types.Type) bool
|
||||
|
||||
// If this generator needs special namers, return them here. These will
|
||||
// override the original namers in the context if there is a collision.
|
||||
// You may return nil if you don't need special names. These names will
|
||||
// be available in the context passed to the rest of the generator's
|
||||
// functions.
|
||||
//
|
||||
// A use case for this is to return a namer that tracks imports.
|
||||
Namers(*Context) namer.NameSystems
|
||||
|
||||
// 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
|
||||
// Generators.)
|
||||
Init(*Context, io.Writer) error
|
||||
|
||||
// Finalize should write finish up functions, and any other content that's not
|
||||
// generated per-type.
|
||||
Finalize(*Context, io.Writer) error
|
||||
|
||||
// PackageVars should emit an array of variable lines. They will be
|
||||
// placed in a var ( ... ) block. There's no need to include a leading
|
||||
// \t or trailing \n.
|
||||
PackageVars(*Context) []string
|
||||
|
||||
// PackageConsts should emit an array of constant lines. They will be
|
||||
// placed in a const ( ... ) block. There's no need to include a leading
|
||||
// \t or trailing \n.
|
||||
PackageConsts(*Context) []string
|
||||
|
||||
// GenerateType should emit the code for a particular type.
|
||||
GenerateType(*Context, *types.Type, io.Writer) error
|
||||
|
||||
// Imports should return a list of necessary imports. They will be
|
||||
// formatted correctly. You do not need to include quotation marks,
|
||||
// return only the package name; alternatively, you can also return
|
||||
// imports in the format `name "path/to/pkg"`. Imports will be called
|
||||
// after Init, PackageVars, PackageConsts, and GenerateType, to allow
|
||||
// you to keep track of what imports you actually need.
|
||||
Imports(*Context) []string
|
||||
|
||||
// Preferred file name of this generator, not including a path. It is
|
||||
// allowed for multiple generators to use the same filename, but it's
|
||||
// up to you to make sure they don't have colliding import names.
|
||||
// TODO: provide per-file import tracking, removing the requirement
|
||||
// that generators coordinate..
|
||||
Filename() string
|
||||
|
||||
// A registered file type in the context to generate this file with. If
|
||||
// the FileType is not found in the context, execution will stop.
|
||||
FileType() string
|
||||
}
|
||||
|
||||
// Context is global context for individual generators to consume.
|
||||
type Context struct {
|
||||
// A map from the naming system to the names for that system. E.g., you
|
||||
// might have public names and several private naming systems.
|
||||
Namers namer.NameSystems
|
||||
|
||||
// All the types, in case you want to look up something.
|
||||
Universe types.Universe
|
||||
|
||||
// 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).
|
||||
Order []*types.Type
|
||||
|
||||
// A set of types this context can process. If this is empty or nil,
|
||||
// the default "golang" 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
|
||||
}
|
||||
|
||||
// NewContext generates a context from the given builder, 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()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Context{
|
||||
Namers: namer.NameSystems{},
|
||||
Universe: universe,
|
||||
Inputs: b.FindPackages(),
|
||||
FileTypes: map[string]FileType{
|
||||
GolangFileType: NewGolangFile(),
|
||||
},
|
||||
builder: b,
|
||||
}
|
||||
|
||||
for name, systemNamer := range nameSystems {
|
||||
c.Namers[name] = systemNamer
|
||||
if name == canonicalOrderName {
|
||||
orderer := namer.Orderer{Namer: systemNamer}
|
||||
c.Order = orderer.OrderUniverse(universe)
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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) {
|
||||
return ctxt.builder.AddDirectoryTo(path, &ctxt.Universe)
|
||||
}
|
64
vendor/k8s.io/gengo/generator/import_tracker.go
generated
vendored
Normal file
64
vendor/k8s.io/gengo/generator/import_tracker.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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 (
|
||||
"strings"
|
||||
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
func NewImportTracker(typesToAdd ...*types.Type) namer.ImportTracker {
|
||||
tracker := namer.NewDefaultImportTracker(types.Name{})
|
||||
tracker.IsInvalidType = func(*types.Type) bool { return false }
|
||||
tracker.LocalName = func(name types.Name) string { return golangTrackerLocalName(&tracker, name) }
|
||||
tracker.PrintImport = func(path, name string) string { return name + " \"" + path + "\"" }
|
||||
|
||||
tracker.AddTypes(typesToAdd...)
|
||||
return &tracker
|
||||
|
||||
}
|
||||
|
||||
func golangTrackerLocalName(tracker namer.ImportTracker, t types.Name) string {
|
||||
path := t.Package
|
||||
|
||||
// Using backslashes in package names causes gengo to produce Go code which
|
||||
// will not compile with the gc compiler. See the comment on GoSeperator.
|
||||
if strings.ContainsRune(path, '\\') {
|
||||
klog.Warningf("Warning: backslash used in import path '%v', this is unsupported.\n", path)
|
||||
}
|
||||
|
||||
dirs := strings.Split(path, namer.GoSeperator)
|
||||
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)
|
||||
// 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)
|
||||
if _, found := tracker.PathOf(name); found {
|
||||
// This name collides with some other package
|
||||
continue
|
||||
}
|
||||
return name
|
||||
}
|
||||
panic("can't find import for " + path)
|
||||
}
|
154
vendor/k8s.io/gengo/generator/snippet_writer.go
generated
vendored
Normal file
154
vendor/k8s.io/gengo/generator/snippet_writer.go
generated
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// SnippetWriter is an attempt to make the template library usable.
|
||||
// Methods are chainable, and you don't have to check Error() until you're all
|
||||
// done.
|
||||
type SnippetWriter struct {
|
||||
w io.Writer
|
||||
context *Context
|
||||
// Left & right delimiters. text/template defaults to "{{" and "}}"
|
||||
// which is totally unusable for go code based templates.
|
||||
left, right string
|
||||
funcMap template.FuncMap
|
||||
err error
|
||||
}
|
||||
|
||||
// w is the destination; left and right are the delimiters; @ and $ are both
|
||||
// reasonable choices.
|
||||
//
|
||||
// c is used to make a function for every naming system, to which you can pass
|
||||
// a type and get the corresponding name.
|
||||
func NewSnippetWriter(w io.Writer, c *Context, left, right string) *SnippetWriter {
|
||||
sw := &SnippetWriter{
|
||||
w: w,
|
||||
context: c,
|
||||
left: left,
|
||||
right: right,
|
||||
funcMap: template.FuncMap{},
|
||||
}
|
||||
for name, namer := range c.Namers {
|
||||
sw.funcMap[name] = namer.Name
|
||||
}
|
||||
return sw
|
||||
}
|
||||
|
||||
// Do parses format and runs args through it. You can have arbitrary logic in
|
||||
// the format (see the text/template documentation), but consider running many
|
||||
// short templaces, with ordinary go logic in between--this may be more
|
||||
// readable. Do is chainable. Any error causes every other call to do to be
|
||||
// ignored, and the error will be returned by Error(). So you can check it just
|
||||
// once, at the end of your function.
|
||||
//
|
||||
// 'args' can be quite literally anything; read the text/template documentation
|
||||
// for details. Maps and structs work particularly nicely. Conveniently, the
|
||||
// types package is designed to have structs that are easily referencable from
|
||||
// the template language.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// sw := generator.NewSnippetWriter(outBuffer, context, "$", "$")
|
||||
// sw.Do(`The public type name is: $.type|public$`, map[string]interface{}{"type": t})
|
||||
// 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.
|
||||
//
|
||||
// The map is actually not necessary. The below does the same thing:
|
||||
//
|
||||
// sw.Do(`The public type name is: $.|public$`, t)
|
||||
//
|
||||
// You may or may not find it more readable to use the map with a descriptive
|
||||
// key, but if you want to pass more than one arg, the map or a custom struct
|
||||
// becomes a requirement. You can do arbitrary logic inside these templates,
|
||||
// but you should consider doing the logic in go and stitching them together
|
||||
// for the sake of your readers.
|
||||
//
|
||||
// TODO: Change Do() to optionally take a list of pairs of parameters (key, value)
|
||||
// and have it construct a combined map with that and args.
|
||||
func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter {
|
||||
if s.err != nil {
|
||||
return s
|
||||
}
|
||||
// Name the template by source file:line so it can be found when
|
||||
// there's an error.
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
tmpl, err := template.
|
||||
New(fmt.Sprintf("%s:%d", file, line)).
|
||||
Delims(s.left, s.right).
|
||||
Funcs(s.funcMap).
|
||||
Parse(format)
|
||||
if err != nil {
|
||||
s.err = err
|
||||
return s
|
||||
}
|
||||
err = tmpl.Execute(s.w, args)
|
||||
if err != nil {
|
||||
s.err = err
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Args exists to make it convenient to construct arguments for
|
||||
// SnippetWriter.Do.
|
||||
type Args map[interface{}]interface{}
|
||||
|
||||
// With makes a copy of a and adds the given key, value pair.
|
||||
func (a Args) With(key, value interface{}) Args {
|
||||
a2 := Args{key: value}
|
||||
for k, v := range a {
|
||||
a2[k] = v
|
||||
}
|
||||
return a2
|
||||
}
|
||||
|
||||
// WithArgs makes a copy of a and adds the given arguments.
|
||||
func (a Args) WithArgs(rhs Args) Args {
|
||||
a2 := Args{}
|
||||
for k, v := range rhs {
|
||||
a2[k] = v
|
||||
}
|
||||
for k, v := range a {
|
||||
a2[k] = v
|
||||
}
|
||||
return a2
|
||||
}
|
||||
|
||||
func (s *SnippetWriter) Out() io.Writer {
|
||||
return s.w
|
||||
}
|
||||
|
||||
// Error returns any encountered error.
|
||||
func (s *SnippetWriter) Error() error {
|
||||
return s.err
|
||||
}
|
31
vendor/k8s.io/gengo/namer/doc.go
generated
vendored
Normal file
31
vendor/k8s.io/gengo/namer/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
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 namer has support for making different type naming systems.
|
||||
//
|
||||
// This is because sometimes you want to refer to the literal type, sometimes
|
||||
// you want to make a name for the thing you're generating, and you want to
|
||||
// make the name based on the type. For example, if you have `type foo string`,
|
||||
// you want to be able to generate something like `func FooPrinter(f *foo) {
|
||||
// Print(string(*f)) }`; that is, you want to refer to a public name, a literal
|
||||
// name, and the underlying literal name.
|
||||
//
|
||||
// This package supports the idea of a "Namer" and a set of "NameSystems" to
|
||||
// support these use cases.
|
||||
//
|
||||
// Additionally, a "RawNamer" can optionally keep track of what needs to be
|
||||
// imported.
|
||||
package namer // import "k8s.io/gengo/namer"
|
112
vendor/k8s.io/gengo/namer/import_tracker.go
generated
vendored
Normal file
112
vendor/k8s.io/gengo/namer/import_tracker.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
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 namer
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
// ImportTracker may be passed to a namer.RawNamer, to track the imports needed
|
||||
// for the types it names.
|
||||
//
|
||||
// TODO: pay attention to the package name (instead of renaming every package).
|
||||
type DefaultImportTracker struct {
|
||||
pathToName map[string]string
|
||||
// forbidden names are in here. (e.g. "go" is a directory in which
|
||||
// there is code, but "go" is not a legal name for a package, so we put
|
||||
// it here to prevent us from naming any package "go")
|
||||
nameToPath map[string]string
|
||||
local types.Name
|
||||
|
||||
// Returns true if a given types is an invalid type and should be ignored.
|
||||
IsInvalidType func(*types.Type) bool
|
||||
// Returns the final local name for the given name
|
||||
LocalName func(types.Name) string
|
||||
// Returns the "import" line for a given (path, name).
|
||||
PrintImport func(string, string) string
|
||||
}
|
||||
|
||||
func NewDefaultImportTracker(local types.Name) DefaultImportTracker {
|
||||
return DefaultImportTracker{
|
||||
pathToName: map[string]string{},
|
||||
nameToPath: map[string]string{},
|
||||
local: local,
|
||||
}
|
||||
}
|
||||
|
||||
func (tracker *DefaultImportTracker) AddTypes(types ...*types.Type) {
|
||||
for _, t := range types {
|
||||
tracker.AddType(t)
|
||||
}
|
||||
}
|
||||
func (tracker *DefaultImportTracker) AddType(t *types.Type) {
|
||||
if tracker.local.Package == t.Name.Package {
|
||||
return
|
||||
}
|
||||
|
||||
if tracker.IsInvalidType(t) {
|
||||
if t.Kind == types.Builtin {
|
||||
return
|
||||
}
|
||||
if _, ok := tracker.nameToPath[t.Name.Package]; !ok {
|
||||
tracker.nameToPath[t.Name.Package] = ""
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if len(t.Name.Package) == 0 {
|
||||
return
|
||||
}
|
||||
path := t.Name.Path
|
||||
if len(path) == 0 {
|
||||
path = t.Name.Package
|
||||
}
|
||||
if _, ok := tracker.pathToName[path]; ok {
|
||||
return
|
||||
}
|
||||
name := tracker.LocalName(t.Name)
|
||||
tracker.nameToPath[name] = path
|
||||
tracker.pathToName[path] = name
|
||||
}
|
||||
|
||||
func (tracker *DefaultImportTracker) ImportLines() []string {
|
||||
importPaths := []string{}
|
||||
for path := range tracker.pathToName {
|
||||
importPaths = append(importPaths, path)
|
||||
}
|
||||
sort.Sort(sort.StringSlice(importPaths))
|
||||
out := []string{}
|
||||
for _, path := range importPaths {
|
||||
out = append(out, tracker.PrintImport(path, tracker.pathToName[path]))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// LocalNameOf returns the name you would use to refer to the package at the
|
||||
// specified path within the body of a file.
|
||||
func (tracker *DefaultImportTracker) LocalNameOf(path string) string {
|
||||
return tracker.pathToName[path]
|
||||
}
|
||||
|
||||
// PathOf returns the path that a given localName is referring to within the
|
||||
// body of a file.
|
||||
func (tracker *DefaultImportTracker) PathOf(localName string) (string, bool) {
|
||||
name, ok := tracker.nameToPath[localName]
|
||||
return name, ok
|
||||
}
|
383
vendor/k8s.io/gengo/namer/namer.go
generated
vendored
Normal file
383
vendor/k8s.io/gengo/namer/namer.go
generated
vendored
Normal file
|
@ -0,0 +1,383 @@
|
|||
/*
|
||||
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 namer
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// GoSeperator is used to split go import paths.
|
||||
// Forward slash is used instead of filepath.Seperator because it is the
|
||||
// only universally-accepted path delimiter and the only delimiter not
|
||||
// potentially forbidden by Go compilers. (In particular gc does not allow
|
||||
// the use of backslashes in import paths.)
|
||||
// See https://golang.org/ref/spec#Import_declarations.
|
||||
// See also https://github.com/kubernetes/gengo/issues/83#issuecomment-367040772.
|
||||
GoSeperator = "/"
|
||||
)
|
||||
|
||||
// Returns whether a name is a private Go name.
|
||||
func IsPrivateGoName(name string) bool {
|
||||
return len(name) == 0 || strings.ToLower(name[:1]) == name[:1]
|
||||
}
|
||||
|
||||
// NewPublicNamer is a helper function that returns a namer that makes
|
||||
// CamelCase names. See the NameStrategy struct for an explanation of the
|
||||
// arguments to this constructor.
|
||||
func NewPublicNamer(prependPackageNames int, ignoreWords ...string) *NameStrategy {
|
||||
n := &NameStrategy{
|
||||
Join: Joiner(IC, IC),
|
||||
IgnoreWords: map[string]bool{},
|
||||
PrependPackageNames: prependPackageNames,
|
||||
}
|
||||
for _, w := range ignoreWords {
|
||||
n.IgnoreWords[w] = true
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// NewPrivateNamer is a helper function that returns a namer that makes
|
||||
// camelCase names. See the NameStrategy struct for an explanation of the
|
||||
// arguments to this constructor.
|
||||
func NewPrivateNamer(prependPackageNames int, ignoreWords ...string) *NameStrategy {
|
||||
n := &NameStrategy{
|
||||
Join: Joiner(IL, IC),
|
||||
IgnoreWords: map[string]bool{},
|
||||
PrependPackageNames: prependPackageNames,
|
||||
}
|
||||
for _, w := range ignoreWords {
|
||||
n.IgnoreWords[w] = true
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// NewRawNamer will return a Namer that makes a name by which you would
|
||||
// directly refer to a type, optionally keeping track of the import paths
|
||||
// necessary to reference the names it provides. Tracker may be nil.
|
||||
// The 'pkg' is the full package name, in which the Namer is used - all
|
||||
// types from that package will be referenced by just type name without
|
||||
// referencing the package.
|
||||
//
|
||||
// For example, if the type is map[string]int, a raw namer will literally
|
||||
// return "map[string]int".
|
||||
//
|
||||
// Or if the type, in package foo, is "type Bar struct { ... }", then the raw
|
||||
// namer will return "foo.Bar" as the name of the type, and if 'tracker' was
|
||||
// not nil, will record that package foo needs to be imported.
|
||||
func NewRawNamer(pkg string, tracker ImportTracker) *rawNamer {
|
||||
return &rawNamer{pkg: pkg, tracker: tracker}
|
||||
}
|
||||
|
||||
// Names is a map from Type to name, as defined by some Namer.
|
||||
type Names map[*types.Type]string
|
||||
|
||||
// Namer takes a type, and assigns a name.
|
||||
//
|
||||
// The purpose of this complexity is so that you can assign coherent
|
||||
// side-by-side systems of names for the types. For example, you might want a
|
||||
// public interface, a private implementation struct, and also to reference
|
||||
// literally the type name.
|
||||
//
|
||||
// Note that it is safe to call your own Name() function recursively to find
|
||||
// the names of keys, elements, etc. This is because anonymous types can't have
|
||||
// cycles in their names, and named types don't require the sort of recursion
|
||||
// that would be problematic.
|
||||
type Namer interface {
|
||||
Name(*types.Type) string
|
||||
}
|
||||
|
||||
// NameSystems is a map of a system name to a namer for that system.
|
||||
type NameSystems map[string]Namer
|
||||
|
||||
// NameStrategy is a general Namer. The easiest way to use it is to copy the
|
||||
// Public/PrivateNamer variables, and modify the members you wish to change.
|
||||
//
|
||||
// The Name method produces a name for the given type, of the forms:
|
||||
// Anonymous types: <Prefix><Type description><Suffix>
|
||||
// Named types: <Prefix><Optional Prepended Package name(s)><Original name><Suffix>
|
||||
//
|
||||
// In all cases, every part of the name is run through the capitalization
|
||||
// functions.
|
||||
//
|
||||
// The IgnoreWords map can be set if you have directory names that are
|
||||
// semantically meaningless for naming purposes, e.g. "proto".
|
||||
//
|
||||
// Prefix and Suffix can be used to disambiguate parallel systems of type
|
||||
// names. For example, if you want to generate an interface and an
|
||||
// implementation, you might want to suffix one with "Interface" and the other
|
||||
// with "Implementation". Another common use-- if you want to generate private
|
||||
// types, and one of your source types could be "string", you can't use the
|
||||
// default lowercase private namer. You'll have to add a suffix or prefix.
|
||||
type NameStrategy struct {
|
||||
Prefix, Suffix string
|
||||
Join func(pre string, parts []string, post string) string
|
||||
|
||||
// Add non-meaningful package directory names here (e.g. "proto") and
|
||||
// they will be ignored.
|
||||
IgnoreWords map[string]bool
|
||||
|
||||
// If > 0, prepend exactly that many package directory names (or as
|
||||
// many as there are). Package names listed in "IgnoreWords" will be
|
||||
// ignored.
|
||||
//
|
||||
// For example, if Ignore words lists "proto" and type Foo is in
|
||||
// pkg/server/frobbing/proto, then a value of 1 will give a type name
|
||||
// of FrobbingFoo, 2 gives ServerFrobbingFoo, etc.
|
||||
PrependPackageNames int
|
||||
|
||||
// A cache of names thus far assigned by this namer.
|
||||
Names
|
||||
}
|
||||
|
||||
// IC ensures the first character is uppercase.
|
||||
func IC(in string) string {
|
||||
if in == "" {
|
||||
return in
|
||||
}
|
||||
return strings.ToUpper(in[:1]) + in[1:]
|
||||
}
|
||||
|
||||
// IL ensures the first character is lowercase.
|
||||
func IL(in string) string {
|
||||
if in == "" {
|
||||
return in
|
||||
}
|
||||
return strings.ToLower(in[:1]) + in[1:]
|
||||
}
|
||||
|
||||
// Joiner lets you specify functions that preprocess the various components of
|
||||
// a name before joining them. You can construct e.g. camelCase or CamelCase or
|
||||
// any other way of joining words. (See the IC and IL convenience functions.)
|
||||
func Joiner(first, others func(string) string) func(pre string, in []string, post string) string {
|
||||
return func(pre string, in []string, post string) string {
|
||||
tmp := []string{others(pre)}
|
||||
for i := range in {
|
||||
tmp = append(tmp, others(in[i]))
|
||||
}
|
||||
tmp = append(tmp, others(post))
|
||||
return first(strings.Join(tmp, ""))
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NameStrategy) removePrefixAndSuffix(s string) string {
|
||||
// The join function may have changed capitalization.
|
||||
lowerIn := strings.ToLower(s)
|
||||
lowerP := strings.ToLower(ns.Prefix)
|
||||
lowerS := strings.ToLower(ns.Suffix)
|
||||
b, e := 0, len(s)
|
||||
if strings.HasPrefix(lowerIn, lowerP) {
|
||||
b = len(ns.Prefix)
|
||||
}
|
||||
if strings.HasSuffix(lowerIn, lowerS) {
|
||||
e -= len(ns.Suffix)
|
||||
}
|
||||
return s[b:e]
|
||||
}
|
||||
|
||||
var (
|
||||
importPathNameSanitizer = strings.NewReplacer("-", "_", ".", "")
|
||||
)
|
||||
|
||||
// filters out unwanted directory names and sanitizes remaining names.
|
||||
func (ns *NameStrategy) filterDirs(path string) []string {
|
||||
allDirs := strings.Split(path, GoSeperator)
|
||||
dirs := make([]string, 0, len(allDirs))
|
||||
for _, p := range allDirs {
|
||||
if ns.IgnoreWords == nil || !ns.IgnoreWords[p] {
|
||||
dirs = append(dirs, importPathNameSanitizer.Replace(p))
|
||||
}
|
||||
}
|
||||
return dirs
|
||||
}
|
||||
|
||||
// See the comment on NameStrategy.
|
||||
func (ns *NameStrategy) Name(t *types.Type) string {
|
||||
if ns.Names == nil {
|
||||
ns.Names = Names{}
|
||||
}
|
||||
if s, ok := ns.Names[t]; ok {
|
||||
return s
|
||||
}
|
||||
|
||||
if t.Name.Package != "" {
|
||||
dirs := append(ns.filterDirs(t.Name.Package), t.Name.Name)
|
||||
i := ns.PrependPackageNames + 1
|
||||
dn := len(dirs)
|
||||
if i > dn {
|
||||
i = dn
|
||||
}
|
||||
name := ns.Join(ns.Prefix, dirs[dn-i:], ns.Suffix)
|
||||
ns.Names[t] = name
|
||||
return name
|
||||
}
|
||||
|
||||
// Only anonymous types remain.
|
||||
var name string
|
||||
switch t.Kind {
|
||||
case types.Builtin:
|
||||
name = ns.Join(ns.Prefix, []string{t.Name.Name}, ns.Suffix)
|
||||
case types.Map:
|
||||
name = ns.Join(ns.Prefix, []string{
|
||||
"Map",
|
||||
ns.removePrefixAndSuffix(ns.Name(t.Key)),
|
||||
"To",
|
||||
ns.removePrefixAndSuffix(ns.Name(t.Elem)),
|
||||
}, ns.Suffix)
|
||||
case types.Slice:
|
||||
name = ns.Join(ns.Prefix, []string{
|
||||
"Slice",
|
||||
ns.removePrefixAndSuffix(ns.Name(t.Elem)),
|
||||
}, ns.Suffix)
|
||||
case types.Pointer:
|
||||
name = ns.Join(ns.Prefix, []string{
|
||||
"Pointer",
|
||||
ns.removePrefixAndSuffix(ns.Name(t.Elem)),
|
||||
}, ns.Suffix)
|
||||
case types.Struct:
|
||||
names := []string{"Struct"}
|
||||
for _, m := range t.Members {
|
||||
names = append(names, ns.removePrefixAndSuffix(ns.Name(m.Type)))
|
||||
}
|
||||
name = ns.Join(ns.Prefix, names, ns.Suffix)
|
||||
case types.Chan:
|
||||
name = ns.Join(ns.Prefix, []string{
|
||||
"Chan",
|
||||
ns.removePrefixAndSuffix(ns.Name(t.Elem)),
|
||||
}, ns.Suffix)
|
||||
case types.Interface:
|
||||
// TODO: add to name test
|
||||
names := []string{"Interface"}
|
||||
for _, m := range t.Methods {
|
||||
// TODO: include function signature
|
||||
names = append(names, m.Name.Name)
|
||||
}
|
||||
name = ns.Join(ns.Prefix, names, ns.Suffix)
|
||||
case types.Func:
|
||||
// TODO: add to name test
|
||||
parts := []string{"Func"}
|
||||
for _, pt := range t.Signature.Parameters {
|
||||
parts = append(parts, ns.removePrefixAndSuffix(ns.Name(pt)))
|
||||
}
|
||||
parts = append(parts, "Returns")
|
||||
for _, rt := range t.Signature.Results {
|
||||
parts = append(parts, ns.removePrefixAndSuffix(ns.Name(rt)))
|
||||
}
|
||||
name = ns.Join(ns.Prefix, parts, ns.Suffix)
|
||||
default:
|
||||
name = "unnameable_" + string(t.Kind)
|
||||
}
|
||||
ns.Names[t] = name
|
||||
return name
|
||||
}
|
||||
|
||||
// ImportTracker allows a raw namer to keep track of the packages needed for
|
||||
// import. You can implement yourself or use the one in the generation package.
|
||||
type ImportTracker interface {
|
||||
AddType(*types.Type)
|
||||
LocalNameOf(packagePath string) string
|
||||
PathOf(localName string) (string, bool)
|
||||
ImportLines() []string
|
||||
}
|
||||
|
||||
type rawNamer struct {
|
||||
pkg string
|
||||
tracker ImportTracker
|
||||
Names
|
||||
}
|
||||
|
||||
// Name makes a name the way you'd write it to literally refer to type t,
|
||||
// making ordinary assumptions about how you've imported t's package (or using
|
||||
// r.tracker to specifically track the package imports).
|
||||
func (r *rawNamer) Name(t *types.Type) string {
|
||||
if r.Names == nil {
|
||||
r.Names = Names{}
|
||||
}
|
||||
if name, ok := r.Names[t]; ok {
|
||||
return name
|
||||
}
|
||||
if t.Name.Package != "" {
|
||||
var name string
|
||||
if r.tracker != nil {
|
||||
r.tracker.AddType(t)
|
||||
if t.Name.Package == r.pkg {
|
||||
name = t.Name.Name
|
||||
} else {
|
||||
name = r.tracker.LocalNameOf(t.Name.Package) + "." + t.Name.Name
|
||||
}
|
||||
} else {
|
||||
if t.Name.Package == r.pkg {
|
||||
name = t.Name.Name
|
||||
} else {
|
||||
name = filepath.Base(t.Name.Package) + "." + t.Name.Name
|
||||
}
|
||||
}
|
||||
r.Names[t] = name
|
||||
return name
|
||||
}
|
||||
var name string
|
||||
switch t.Kind {
|
||||
case types.Builtin:
|
||||
name = t.Name.Name
|
||||
case types.Map:
|
||||
name = "map[" + r.Name(t.Key) + "]" + r.Name(t.Elem)
|
||||
case types.Slice:
|
||||
name = "[]" + r.Name(t.Elem)
|
||||
case types.Pointer:
|
||||
name = "*" + r.Name(t.Elem)
|
||||
case types.Struct:
|
||||
elems := []string{}
|
||||
for _, m := range t.Members {
|
||||
elems = append(elems, m.Name+" "+r.Name(m.Type))
|
||||
}
|
||||
name = "struct{" + strings.Join(elems, "; ") + "}"
|
||||
case types.Chan:
|
||||
// TODO: include directionality
|
||||
name = "chan " + r.Name(t.Elem)
|
||||
case types.Interface:
|
||||
// TODO: add to name test
|
||||
elems := []string{}
|
||||
for _, m := range t.Methods {
|
||||
// TODO: include function signature
|
||||
elems = append(elems, m.Name.Name)
|
||||
}
|
||||
name = "interface{" + strings.Join(elems, "; ") + "}"
|
||||
case types.Func:
|
||||
// TODO: add to name test
|
||||
params := []string{}
|
||||
for _, pt := range t.Signature.Parameters {
|
||||
params = append(params, r.Name(pt))
|
||||
}
|
||||
results := []string{}
|
||||
for _, rt := range t.Signature.Results {
|
||||
results = append(results, r.Name(rt))
|
||||
}
|
||||
name = "func(" + strings.Join(params, ",") + ")"
|
||||
if len(results) == 1 {
|
||||
name += " " + results[0]
|
||||
} else if len(results) > 1 {
|
||||
name += " (" + strings.Join(results, ",") + ")"
|
||||
}
|
||||
default:
|
||||
name = "unnameable_" + string(t.Kind)
|
||||
}
|
||||
r.Names[t] = name
|
||||
return name
|
||||
}
|
69
vendor/k8s.io/gengo/namer/order.go
generated
vendored
Normal file
69
vendor/k8s.io/gengo/namer/order.go
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
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 namer
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
// Orderer produces an ordering of types given a Namer.
|
||||
type Orderer struct {
|
||||
Namer
|
||||
}
|
||||
|
||||
// OrderUniverse assigns a name to every type in the Universe, including Types,
|
||||
// Functions and Variables, and returns a list sorted by those names.
|
||||
func (o *Orderer) OrderUniverse(u types.Universe) []*types.Type {
|
||||
list := tList{
|
||||
namer: o.Namer,
|
||||
}
|
||||
for _, p := range u {
|
||||
for _, t := range p.Types {
|
||||
list.types = append(list.types, t)
|
||||
}
|
||||
for _, f := range p.Functions {
|
||||
list.types = append(list.types, f)
|
||||
}
|
||||
for _, v := range p.Variables {
|
||||
list.types = append(list.types, v)
|
||||
}
|
||||
}
|
||||
sort.Sort(list)
|
||||
return list.types
|
||||
}
|
||||
|
||||
// OrderTypes assigns a name to every type, and returns a list sorted by those
|
||||
// names.
|
||||
func (o *Orderer) OrderTypes(typeList []*types.Type) []*types.Type {
|
||||
list := tList{
|
||||
namer: o.Namer,
|
||||
types: typeList,
|
||||
}
|
||||
sort.Sort(list)
|
||||
return list.types
|
||||
}
|
||||
|
||||
type tList struct {
|
||||
namer Namer
|
||||
types []*types.Type
|
||||
}
|
||||
|
||||
func (t tList) Len() int { return len(t.types) }
|
||||
func (t tList) Less(i, j int) bool { return t.namer.Name(t.types[i]) < t.namer.Name(t.types[j]) }
|
||||
func (t tList) Swap(i, j int) { t.types[i], t.types[j] = t.types[j], t.types[i] }
|
120
vendor/k8s.io/gengo/namer/plural_namer.go
generated
vendored
Normal file
120
vendor/k8s.io/gengo/namer/plural_namer.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
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 namer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
var consonants = "bcdfghjklmnpqrsttvwxyz"
|
||||
|
||||
type pluralNamer struct {
|
||||
// key is the case-sensitive type name, value is the case-insensitive
|
||||
// intended output.
|
||||
exceptions map[string]string
|
||||
finalize func(string) string
|
||||
}
|
||||
|
||||
// NewPublicPluralNamer returns a namer that returns the plural form of the input
|
||||
// type's name, starting with a uppercase letter.
|
||||
func NewPublicPluralNamer(exceptions map[string]string) *pluralNamer {
|
||||
return &pluralNamer{exceptions, IC}
|
||||
}
|
||||
|
||||
// NewPrivatePluralNamer returns a namer that returns the plural form of the input
|
||||
// type's name, starting with a lowercase letter.
|
||||
func NewPrivatePluralNamer(exceptions map[string]string) *pluralNamer {
|
||||
return &pluralNamer{exceptions, IL}
|
||||
}
|
||||
|
||||
// NewAllLowercasePluralNamer returns a namer that returns the plural form of the input
|
||||
// type's name, with all letters in lowercase.
|
||||
func NewAllLowercasePluralNamer(exceptions map[string]string) *pluralNamer {
|
||||
return &pluralNamer{exceptions, strings.ToLower}
|
||||
}
|
||||
|
||||
// Name returns the plural form of the type's name. If the type's name is found
|
||||
// in the exceptions map, the map value is returned.
|
||||
func (r *pluralNamer) Name(t *types.Type) string {
|
||||
singular := t.Name.Name
|
||||
var plural string
|
||||
var ok bool
|
||||
if plural, ok = r.exceptions[singular]; ok {
|
||||
return r.finalize(plural)
|
||||
}
|
||||
if len(singular) < 2 {
|
||||
return r.finalize(singular)
|
||||
}
|
||||
|
||||
switch rune(singular[len(singular)-1]) {
|
||||
case 's', 'x', 'z':
|
||||
plural = esPlural(singular)
|
||||
case 'y':
|
||||
sl := rune(singular[len(singular)-2])
|
||||
if isConsonant(sl) {
|
||||
plural = iesPlural(singular)
|
||||
} else {
|
||||
plural = sPlural(singular)
|
||||
}
|
||||
case 'h':
|
||||
sl := rune(singular[len(singular)-2])
|
||||
if sl == 'c' || sl == 's' {
|
||||
plural = esPlural(singular)
|
||||
} else {
|
||||
plural = sPlural(singular)
|
||||
}
|
||||
case 'e':
|
||||
sl := rune(singular[len(singular)-2])
|
||||
if sl == 'f' {
|
||||
plural = vesPlural(singular[:len(singular)-1])
|
||||
} else {
|
||||
plural = sPlural(singular)
|
||||
}
|
||||
case 'f':
|
||||
plural = vesPlural(singular)
|
||||
default:
|
||||
plural = sPlural(singular)
|
||||
}
|
||||
return r.finalize(plural)
|
||||
}
|
||||
|
||||
func iesPlural(singular string) string {
|
||||
return singular[:len(singular)-1] + "ies"
|
||||
}
|
||||
|
||||
func vesPlural(singular string) string {
|
||||
return singular[:len(singular)-1] + "ves"
|
||||
}
|
||||
|
||||
func esPlural(singular string) string {
|
||||
return singular + "es"
|
||||
}
|
||||
|
||||
func sPlural(singular string) string {
|
||||
return singular + "s"
|
||||
}
|
||||
|
||||
func isConsonant(char rune) bool {
|
||||
for _, c := range consonants {
|
||||
if char == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
19
vendor/k8s.io/gengo/parser/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/gengo/parser/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
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 provides code to parse go files, type-check them, extract the
|
||||
// types.
|
||||
package parser // import "k8s.io/gengo/parser"
|
813
vendor/k8s.io/gengo/parser/parse.go
generated
vendored
Normal file
813
vendor/k8s.io/gengo/parser/parse.go
generated
vendored
Normal file
|
@ -0,0 +1,813 @@
|
|||
/*
|
||||
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/parser"
|
||||
"go/token"
|
||||
tc "go/types"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
// 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.
|
||||
buildPackages map[string]*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[string]*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...)
|
||||
}
|
||||
|
||||
// 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.buildPackages[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.buildPackages[dir] = buildPkg
|
||||
canonicalPackage := canonicalizeImportPath(buildPkg.ImportPath)
|
||||
if dir != string(canonicalPackage) {
|
||||
// Since `dir` is not the canonical name, see if we knew it under another name.
|
||||
if buildPkg, ok := b.buildPackages[string(canonicalPackage)]; ok {
|
||||
return buildPkg, nil
|
||||
}
|
||||
// Must be new, save it under the canonical name, too.
|
||||
klog.V(5).Infof("saving buildPackage %s", canonicalPackage)
|
||||
b.buildPackages[string(canonicalPackage)] = 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)); 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 includes the root dir, but we already did that, so we'll
|
||||
// remove that prefix and rebuild a package import path.
|
||||
prefix := b.buildPackages[dir].Dir
|
||||
fn := func(filePath string, info os.FileInfo, err error) error {
|
||||
if info != nil && info.IsDir() {
|
||||
rel := filepath.ToSlash(strings.TrimPrefix(filePath, prefix))
|
||||
if rel != "" {
|
||||
// Make a pkg path.
|
||||
pkg := path.Join(string(canonicalizeImportPath(b.buildPackages[dir].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(b.buildPackages[dir].Dir, 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
|
||||
}
|
||||
return b.findTypesIn(canonicalizeImportPath(b.buildPackages[dir].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
|
||||
}
|
||||
path := canonicalizeImportPath(b.buildPackages[dir].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
|
||||
}
|
||||
|
||||
for _, n := range buildPkg.GoFiles {
|
||||
if !strings.HasSuffix(n, ".go") {
|
||||
continue
|
||||
}
|
||||
absPath := filepath.Join(buildPkg.Dir, n)
|
||||
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
|
||||
}
|
||||
|
||||
// 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.buildPackages[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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the canonical path now that it has been added.
|
||||
if buildPkg := b.buildPackages[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)
|
||||
if err != nil {
|
||||
switch {
|
||||
case ignoreError && pkg != nil:
|
||||
klog.V(2).Infof("type checking encountered some issues in %q, but ignoring.\n", pkgPath)
|
||||
case !ignoreError && pkg != nil:
|
||||
klog.V(2).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) (*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) {
|
||||
klog.V(2).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
|
||||
}
|
||||
|
||||
// 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())
|
||||
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())
|
||||
}
|
||||
}
|
||||
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)
|
||||
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())
|
||||
}
|
||||
}
|
||||
tv, ok := obj.(*tc.Var)
|
||||
if ok && !tv.IsField() {
|
||||
b.addVariable(*u, nil, tv)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
buildPkg, err := b.context.Import(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, "*") ||
|
||||
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()))
|
||||
}
|
||||
for i := 0; i < t.Results().Len(); i++ {
|
||||
signature.Results = append(signature.Results, b.walkType(u, nil, t.Results().At(i).Type()))
|
||||
}
|
||||
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())
|
||||
// TODO: need to store array length, otherwise raw type name
|
||||
// cannot be properly written.
|
||||
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{}
|
||||
}
|
||||
out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type())
|
||||
}
|
||||
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{}
|
||||
}
|
||||
out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type())
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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/"):])
|
||||
}
|
82
vendor/k8s.io/gengo/types/comments.go
generated
vendored
Normal file
82
vendor/k8s.io/gengo/types/comments.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
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 contains go type information, packaged in a way that makes
|
||||
// auto-generation convenient, whether by template or straight go functions.
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ExtractCommentTags parses comments for lines of the form:
|
||||
//
|
||||
// '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
|
||||
// a key, the value (a slice) is guaranteed to have at least 1 element.
|
||||
//
|
||||
// Example: if you pass "+" for 'marker', and the following lines are in
|
||||
// the comments:
|
||||
// +foo=value1
|
||||
// +bar
|
||||
// +foo=value2
|
||||
// +baz="qux"
|
||||
// Then this function will return:
|
||||
// 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 {
|
||||
line = strings.Trim(line, " ")
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(line, marker) {
|
||||
continue
|
||||
}
|
||||
// TODO: we could support multiple values per key if we split on spaces
|
||||
kv := strings.SplitN(line[len(marker):], "=", 2)
|
||||
if len(kv) == 2 {
|
||||
out[kv[0]] = append(out[kv[0]], kv[1])
|
||||
} else if len(kv) == 1 {
|
||||
out[kv[0]] = append(out[kv[0]], "")
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ExtractSingleBoolCommentTag parses comments for lines of the form:
|
||||
//
|
||||
// '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
|
||||
// to be returned. If the key has multiple values, the first one will be used.
|
||||
func ExtractSingleBoolCommentTag(marker string, key string, defaultVal bool, lines []string) (bool, error) {
|
||||
values := ExtractCommentTags(marker, lines)[key]
|
||||
if values == nil {
|
||||
return defaultVal, nil
|
||||
}
|
||||
if values[0] == "true" {
|
||||
return true, nil
|
||||
}
|
||||
if values[0] == "false" {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("tag value for %q is not boolean: %q", key, values[0])
|
||||
}
|
19
vendor/k8s.io/gengo/types/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/gengo/types/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
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 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"
|
57
vendor/k8s.io/gengo/types/flatten.go
generated
vendored
Normal file
57
vendor/k8s.io/gengo/types/flatten.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
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
|
||||
}
|
499
vendor/k8s.io/gengo/types/types.go
generated
vendored
Normal file
499
vendor/k8s.io/gengo/types/types.go
generated
vendored
Normal file
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
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
|
||||
|
||||
import "strings"
|
||||
|
||||
// Ref makes a reference to the given type. It can only be used for e.g.
|
||||
// passing to namers.
|
||||
func Ref(packageName, typeName string) *Type {
|
||||
return &Type{Name: Name{
|
||||
Name: typeName,
|
||||
Package: packageName,
|
||||
}}
|
||||
}
|
||||
|
||||
// A type name may have a package qualifier.
|
||||
type Name struct {
|
||||
// Empty if embedded or builtin. This is the package path unless Path is specified.
|
||||
Package string
|
||||
// The type name.
|
||||
Name string
|
||||
// An optional location of the type definition for languages that can have disjoint
|
||||
// packages and paths.
|
||||
Path string
|
||||
}
|
||||
|
||||
// String returns the name formatted as a string.
|
||||
func (n Name) String() string {
|
||||
if n.Package == "" {
|
||||
return n.Name
|
||||
}
|
||||
return n.Package + "." + n.Name
|
||||
}
|
||||
|
||||
// ParseFullyQualifiedName parses a name like k8s.io/kubernetes/pkg/api.Pod into a Name.
|
||||
func ParseFullyQualifiedName(fqn string) Name {
|
||||
cs := strings.Split(fqn, ".")
|
||||
pkg := ""
|
||||
if len(cs) > 1 {
|
||||
pkg = strings.Join(cs[0:len(cs)-1], ".")
|
||||
}
|
||||
return Name{
|
||||
Name: cs[len(cs)-1],
|
||||
Package: pkg,
|
||||
}
|
||||
}
|
||||
|
||||
// The possible classes of types.
|
||||
type Kind string
|
||||
|
||||
const (
|
||||
// Builtin is a primitive, like bool, string, int.
|
||||
Builtin Kind = "Builtin"
|
||||
Struct Kind = "Struct"
|
||||
Map Kind = "Map"
|
||||
Slice Kind = "Slice"
|
||||
Pointer Kind = "Pointer"
|
||||
|
||||
// Alias is an alias of another type, e.g. in:
|
||||
// type Foo string
|
||||
// type Bar Foo
|
||||
// Bar is an alias of Foo.
|
||||
//
|
||||
// In the real go type system, Foo is a "Named" string; but to simplify
|
||||
// generation, this type system will just say that Foo *is* a builtin.
|
||||
// We then need "Alias" as a way for us to say that Bar *is* a Foo.
|
||||
Alias Kind = "Alias"
|
||||
|
||||
// Interface is any type that could have differing types at run time.
|
||||
Interface Kind = "Interface"
|
||||
|
||||
// The remaining types are included for completeness, but are not well
|
||||
// supported.
|
||||
Array Kind = "Array" // Array is just like slice, but has a fixed length.
|
||||
Chan Kind = "Chan"
|
||||
Func Kind = "Func"
|
||||
|
||||
// DeclarationOf is different from other Kinds; it indicates that instead of
|
||||
// representing an actual Type, the type is a declaration of an instance of
|
||||
// a type. E.g., a top-level function, variable, or constant. See the
|
||||
// comment for Type.Name for more detail.
|
||||
DeclarationOf Kind = "DeclarationOf"
|
||||
Unknown Kind = ""
|
||||
Unsupported Kind = "Unsupported"
|
||||
|
||||
// Protobuf is protobuf type.
|
||||
Protobuf Kind = "Protobuf"
|
||||
)
|
||||
|
||||
// Package holds package-level information.
|
||||
// Fields are public, as everything in this package, to enable consumption by
|
||||
// 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.
|
||||
Path string
|
||||
|
||||
// The location this package was loaded from
|
||||
SourcePath string
|
||||
|
||||
// Short name of this package; the name that appears in the
|
||||
// 'package x' line.
|
||||
Name string
|
||||
|
||||
// The comment right above the package declaration in doc.go, if any.
|
||||
DocComments []string
|
||||
|
||||
// All comments from doc.go, if any.
|
||||
// TODO: remove Comments and use DocComments everywhere.
|
||||
Comments []string
|
||||
|
||||
// Types within this package, indexed by their name (*not* including
|
||||
// package name).
|
||||
Types map[string]*Type
|
||||
|
||||
// Functions within this package, indexed by their name (*not* including
|
||||
// package name).
|
||||
Functions map[string]*Type
|
||||
|
||||
// Global variables within this package, indexed by their name (*not* including
|
||||
// package name).
|
||||
Variables map[string]*Type
|
||||
|
||||
// Packages imported by this package, indexed by (canonicalized)
|
||||
// package path.
|
||||
Imports map[string]*Package
|
||||
}
|
||||
|
||||
// Has returns true if the given name references a type known to this package.
|
||||
func (p *Package) Has(name string) bool {
|
||||
_, has := p.Types[name]
|
||||
return has
|
||||
}
|
||||
|
||||
// Type gets the given Type in this Package. If the Type is not already
|
||||
// defined, this will add it and return the new Type value. The caller is
|
||||
// expected to finish initialization.
|
||||
func (p *Package) Type(typeName string) *Type {
|
||||
if t, ok := p.Types[typeName]; ok {
|
||||
return t
|
||||
}
|
||||
if p.Path == "" {
|
||||
// Import the standard builtin types!
|
||||
if t, ok := builtins.Types[typeName]; ok {
|
||||
p.Types[typeName] = t
|
||||
return t
|
||||
}
|
||||
}
|
||||
t := &Type{Name: Name{Package: p.Path, Name: typeName}}
|
||||
p.Types[typeName] = t
|
||||
return t
|
||||
}
|
||||
|
||||
// Function gets the given function Type in this Package. If the function is
|
||||
// not already defined, this will add it. If a function is added, it's the
|
||||
// caller's responsibility to finish construction of the function by setting
|
||||
// Underlying to the correct type.
|
||||
func (p *Package) Function(funcName string) *Type {
|
||||
if t, ok := p.Functions[funcName]; ok {
|
||||
return t
|
||||
}
|
||||
t := &Type{Name: Name{Package: p.Path, Name: funcName}}
|
||||
t.Kind = DeclarationOf
|
||||
p.Functions[funcName] = t
|
||||
return t
|
||||
}
|
||||
|
||||
// Variable gets the given variable Type in this Package. If the variable is
|
||||
// not already defined, this will add it. If a variable is added, it's the caller's
|
||||
// responsibility to finish construction of the variable by setting Underlying
|
||||
// to the correct type.
|
||||
func (p *Package) Variable(varName string) *Type {
|
||||
if t, ok := p.Variables[varName]; ok {
|
||||
return t
|
||||
}
|
||||
t := &Type{Name: Name{Package: p.Path, Name: varName}}
|
||||
t.Kind = DeclarationOf
|
||||
p.Variables[varName] = t
|
||||
return t
|
||||
}
|
||||
|
||||
// HasImport returns true if p imports packageName. Package names include the
|
||||
// package directory.
|
||||
func (p *Package) HasImport(packageName string) bool {
|
||||
_, has := p.Imports[packageName]
|
||||
return has
|
||||
}
|
||||
|
||||
// Universe is a map of all packages. The key is the package name, but you
|
||||
// should use Package(), Type(), Function(), or Variable() instead of direct
|
||||
// access.
|
||||
type Universe map[string]*Package
|
||||
|
||||
// Type returns the canonical type for the given fully-qualified name. Builtin
|
||||
// types will always be found, even if they haven't been explicitly added to
|
||||
// the map. If a non-existing type is requested, this will create (a marker for)
|
||||
// it.
|
||||
func (u Universe) Type(n Name) *Type {
|
||||
return u.Package(n.Package).Type(n.Name)
|
||||
}
|
||||
|
||||
// Function returns the canonical function for the given fully-qualified name.
|
||||
// If a non-existing function is requested, this will create (a marker for) it.
|
||||
// If a marker is created, it's the caller's responsibility to finish
|
||||
// construction of the function by setting Underlying to the correct type.
|
||||
func (u Universe) Function(n Name) *Type {
|
||||
return u.Package(n.Package).Function(n.Name)
|
||||
}
|
||||
|
||||
// Variable returns the canonical variable for the given fully-qualified name.
|
||||
// If a non-existing variable is requested, this will create (a marker for) it.
|
||||
// If a marker is created, it's the caller's responsibility to finish
|
||||
// construction of the variable by setting Underlying to the correct type.
|
||||
func (u Universe) Variable(n Name) *Type {
|
||||
return u.Package(n.Package).Variable(n.Name)
|
||||
}
|
||||
|
||||
// AddImports registers import lines for packageName. May be called multiple times.
|
||||
// You are responsible for canonicalizing all package paths.
|
||||
func (u Universe) AddImports(packagePath string, importPaths ...string) {
|
||||
p := u.Package(packagePath)
|
||||
for _, i := range importPaths {
|
||||
p.Imports[i] = u.Package(i)
|
||||
}
|
||||
}
|
||||
|
||||
// Package returns the Package for the given path.
|
||||
// If a non-existing package is requested, this will create (a marker for) it.
|
||||
// If a marker is created, it's the caller's responsibility to finish
|
||||
// construction of the package.
|
||||
func (u Universe) Package(packagePath string) *Package {
|
||||
if p, ok := u[packagePath]; ok {
|
||||
return p
|
||||
}
|
||||
p := &Package{
|
||||
Path: packagePath,
|
||||
Types: map[string]*Type{},
|
||||
Functions: map[string]*Type{},
|
||||
Variables: map[string]*Type{},
|
||||
Imports: map[string]*Package{},
|
||||
}
|
||||
u[packagePath] = p
|
||||
return p
|
||||
}
|
||||
|
||||
// Type represents a subset of possible go types.
|
||||
type Type struct {
|
||||
// There are two general categories of types, those explicitly named
|
||||
// and those anonymous. Named ones will have a non-empty package in the
|
||||
// name field.
|
||||
//
|
||||
// An exception: If Kind == DeclarationOf, then this name is the name of a
|
||||
// top-level function, variable, or const, and the type can be found in Underlying.
|
||||
// We do this to allow the naming system to work against these objects, even
|
||||
// though they aren't strictly speaking types.
|
||||
Name Name
|
||||
|
||||
// The general kind of this type.
|
||||
Kind Kind
|
||||
|
||||
// If there are comment lines immediately before the type definition,
|
||||
// they will be recorded here.
|
||||
CommentLines []string
|
||||
|
||||
// If there are comment lines preceding the `CommentLines`, they will be
|
||||
// recorded here. There are two cases:
|
||||
// ---
|
||||
// SecondClosestCommentLines
|
||||
// a blank line
|
||||
// CommentLines
|
||||
// type definition
|
||||
// ---
|
||||
//
|
||||
// or
|
||||
// ---
|
||||
// SecondClosestCommentLines
|
||||
// a blank line
|
||||
// type definition
|
||||
// ---
|
||||
SecondClosestCommentLines []string
|
||||
|
||||
// If Kind == Struct
|
||||
Members []Member
|
||||
|
||||
// If Kind == Map, Slice, Pointer, or Chan
|
||||
Elem *Type
|
||||
|
||||
// If Kind == Map, this is the map's key type.
|
||||
Key *Type
|
||||
|
||||
// If Kind == Alias, this is the underlying type.
|
||||
// If Kind == DeclarationOf, this is the type of the declaration.
|
||||
Underlying *Type
|
||||
|
||||
// If Kind == Interface, this is the set of all required functions.
|
||||
// Otherwise, if this is a named type, this is the list of methods that
|
||||
// type has. (All elements will have Kind=="Func")
|
||||
Methods map[string]*Type
|
||||
|
||||
// If Kind == func, this is the signature of the function.
|
||||
Signature *Signature
|
||||
|
||||
// TODO: Add:
|
||||
// * channel direction
|
||||
// * array length
|
||||
}
|
||||
|
||||
// String returns the name of the type.
|
||||
func (t *Type) String() string {
|
||||
return t.Name.String()
|
||||
}
|
||||
|
||||
// IsPrimitive returns whether the type is a built-in type or is an alias to a
|
||||
// built-in type. For example: strings and aliases of strings are primitives,
|
||||
// structs are not.
|
||||
func (t *Type) IsPrimitive() bool {
|
||||
if t.Kind == Builtin || (t.Kind == Alias && t.Underlying.Kind == Builtin) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsAssignable returns whether the type is deep-assignable. For example,
|
||||
// slices and maps and pointers are shallow copies, but ints and strings are
|
||||
// complete.
|
||||
func (t *Type) IsAssignable() bool {
|
||||
if t.IsPrimitive() {
|
||||
return true
|
||||
}
|
||||
if t.Kind == Struct {
|
||||
for _, m := range t.Members {
|
||||
if !m.Type.IsAssignable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsAnonymousStruct returns true if the type is an anonymous struct or an alias
|
||||
// to an anonymous struct.
|
||||
func (t *Type) IsAnonymousStruct() bool {
|
||||
return (t.Kind == Struct && t.Name.Name == "struct{}") || (t.Kind == Alias && t.Underlying.IsAnonymousStruct())
|
||||
}
|
||||
|
||||
// A single struct member
|
||||
type Member struct {
|
||||
// The name of the member.
|
||||
Name string
|
||||
|
||||
// If the member is embedded (anonymous) this will be true, and the
|
||||
// Name will be the type name.
|
||||
Embedded bool
|
||||
|
||||
// If there are comment lines immediately before the member in the type
|
||||
// definition, they will be recorded here.
|
||||
CommentLines []string
|
||||
|
||||
// If there are tags along with this member, they will be saved here.
|
||||
Tags string
|
||||
|
||||
// The type of this member.
|
||||
Type *Type
|
||||
}
|
||||
|
||||
// String returns the name and type of the member.
|
||||
func (m Member) String() string {
|
||||
return m.Name + " " + m.Type.String()
|
||||
}
|
||||
|
||||
// Signature is a function's signature.
|
||||
type Signature struct {
|
||||
// TODO: store the parameter names, not just types.
|
||||
|
||||
// If a method of some type, this is the type it's a member of.
|
||||
Receiver *Type
|
||||
Parameters []*Type
|
||||
Results []*Type
|
||||
|
||||
// True if the last in parameter is of the form ...T.
|
||||
Variadic bool
|
||||
|
||||
// If there are comment lines immediately before this
|
||||
// signature/method/function declaration, they will be recorded here.
|
||||
CommentLines []string
|
||||
}
|
||||
|
||||
// Built in types.
|
||||
var (
|
||||
String = &Type{
|
||||
Name: Name{Name: "string"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Int64 = &Type{
|
||||
Name: Name{Name: "int64"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Int32 = &Type{
|
||||
Name: Name{Name: "int32"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Int16 = &Type{
|
||||
Name: Name{Name: "int16"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Int = &Type{
|
||||
Name: Name{Name: "int"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Uint64 = &Type{
|
||||
Name: Name{Name: "uint64"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Uint32 = &Type{
|
||||
Name: Name{Name: "uint32"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Uint16 = &Type{
|
||||
Name: Name{Name: "uint16"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Uint = &Type{
|
||||
Name: Name{Name: "uint"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Uintptr = &Type{
|
||||
Name: Name{Name: "uintptr"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Float64 = &Type{
|
||||
Name: Name{Name: "float64"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Float32 = &Type{
|
||||
Name: Name{Name: "float32"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Float = &Type{
|
||||
Name: Name{Name: "float"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Bool = &Type{
|
||||
Name: Name{Name: "bool"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
Byte = &Type{
|
||||
Name: Name{Name: "byte"},
|
||||
Kind: Builtin,
|
||||
}
|
||||
|
||||
builtins = &Package{
|
||||
Types: map[string]*Type{
|
||||
"bool": Bool,
|
||||
"string": String,
|
||||
"int": Int,
|
||||
"int64": Int64,
|
||||
"int32": Int32,
|
||||
"int16": Int16,
|
||||
"int8": Byte,
|
||||
"uint": Uint,
|
||||
"uint64": Uint64,
|
||||
"uint32": Uint32,
|
||||
"uint16": Uint16,
|
||||
"uint8": Byte,
|
||||
"uintptr": Uintptr,
|
||||
"byte": Byte,
|
||||
"float": Float,
|
||||
"float64": Float64,
|
||||
"float32": Float32,
|
||||
},
|
||||
Imports: map[string]*Package{},
|
||||
Path: "",
|
||||
Name: "",
|
||||
}
|
||||
)
|
||||
|
||||
func IsInteger(t *Type) bool {
|
||||
switch t {
|
||||
case Int, Int64, Int32, Int16, Uint, Uint64, Uint32, Uint16, Byte:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue