From 7766f5e99236af03302bbd746047a8145f0eeaa2 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 30 Aug 2016 10:09:09 -0700 Subject: [PATCH] remove gengo source --- cmd/libs/go2idl/args/args.go | 168 ----- .../go2idl/generator/default_generator.go | 62 -- cmd/libs/go2idl/generator/default_package.go | 72 -- cmd/libs/go2idl/generator/doc.go | 31 - cmd/libs/go2idl/generator/error_tracker.go | 50 -- cmd/libs/go2idl/generator/execute.go | 309 -------- cmd/libs/go2idl/generator/generator.go | 212 ------ cmd/libs/go2idl/generator/import_tracker.go | 56 -- cmd/libs/go2idl/generator/snippet_writer.go | 154 ---- .../go2idl/generator/snippet_writer_test.go | 88 --- cmd/libs/go2idl/namer/doc.go | 31 - cmd/libs/go2idl/namer/import_tracker.go | 112 --- cmd/libs/go2idl/namer/namer.go | 366 --------- cmd/libs/go2idl/namer/namer_test.go | 96 --- cmd/libs/go2idl/namer/order.go | 69 -- cmd/libs/go2idl/namer/plural_namer.go | 68 -- cmd/libs/go2idl/namer/plural_namer_test.go | 68 -- cmd/libs/go2idl/parser/doc.go | 19 - cmd/libs/go2idl/parser/parse.go | 713 ------------------ cmd/libs/go2idl/parser/parse_test.go | 420 ----------- cmd/libs/go2idl/types/comments.go | 82 -- cmd/libs/go2idl/types/comments_test.go | 86 --- cmd/libs/go2idl/types/doc.go | 19 - cmd/libs/go2idl/types/flatten.go | 57 -- cmd/libs/go2idl/types/flatten_test.go | 68 -- cmd/libs/go2idl/types/types.go | 480 ------------ cmd/libs/go2idl/types/types_test.go | 210 ------ 27 files changed, 4166 deletions(-) delete mode 100644 cmd/libs/go2idl/args/args.go delete mode 100644 cmd/libs/go2idl/generator/default_generator.go delete mode 100644 cmd/libs/go2idl/generator/default_package.go delete mode 100644 cmd/libs/go2idl/generator/doc.go delete mode 100644 cmd/libs/go2idl/generator/error_tracker.go delete mode 100644 cmd/libs/go2idl/generator/execute.go delete mode 100644 cmd/libs/go2idl/generator/generator.go delete mode 100644 cmd/libs/go2idl/generator/import_tracker.go delete mode 100644 cmd/libs/go2idl/generator/snippet_writer.go delete mode 100644 cmd/libs/go2idl/generator/snippet_writer_test.go delete mode 100644 cmd/libs/go2idl/namer/doc.go delete mode 100644 cmd/libs/go2idl/namer/import_tracker.go delete mode 100644 cmd/libs/go2idl/namer/namer.go delete mode 100644 cmd/libs/go2idl/namer/namer_test.go delete mode 100644 cmd/libs/go2idl/namer/order.go delete mode 100644 cmd/libs/go2idl/namer/plural_namer.go delete mode 100644 cmd/libs/go2idl/namer/plural_namer_test.go delete mode 100644 cmd/libs/go2idl/parser/doc.go delete mode 100644 cmd/libs/go2idl/parser/parse.go delete mode 100644 cmd/libs/go2idl/parser/parse_test.go delete mode 100644 cmd/libs/go2idl/types/comments.go delete mode 100644 cmd/libs/go2idl/types/comments_test.go delete mode 100644 cmd/libs/go2idl/types/doc.go delete mode 100644 cmd/libs/go2idl/types/flatten.go delete mode 100644 cmd/libs/go2idl/types/flatten_test.go delete mode 100644 cmd/libs/go2idl/types/types.go delete mode 100644 cmd/libs/go2idl/types/types_test.go diff --git a/cmd/libs/go2idl/args/args.go b/cmd/libs/go2idl/args/args.go deleted file mode 100644 index 8b20a77dca5..00000000000 --- a/cmd/libs/go2idl/args/args.go +++ /dev/null @@ -1,168 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package args has common command-line flags for generation programs. -package args - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strconv" - "strings" - "time" - - "k8s.io/kubernetes/cmd/libs/go2idl/generator" - "k8s.io/kubernetes/cmd/libs/go2idl/namer" - "k8s.io/kubernetes/cmd/libs/go2idl/parser" - "k8s.io/kubernetes/cmd/libs/go2idl/types" - utilflag "k8s.io/kubernetes/pkg/util/flag" - "k8s.io/kubernetes/pkg/util/logs" - - "github.com/spf13/pflag" -) - -// Default returns a defaulted GeneratorArgs. You may change the defaults -// before calling AddFlags. -func Default() *GeneratorArgs { - generatorArgs := &GeneratorArgs{ - OutputBase: DefaultSourceTree(), - GoHeaderFilePath: filepath.Join(DefaultSourceTree(), "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt"), - GeneratedBuildTag: "ignore_autogenerated", - } - generatorArgs.AddFlags(pflag.CommandLine) - return generatorArgs -} - -// 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 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{} -} - -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) - 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 { - if strings.HasPrefix(p.Path, dir) { - 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 { - utilflag.InitFlags() - logs.InitLogs() - - 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 -} diff --git a/cmd/libs/go2idl/generator/default_generator.go b/cmd/libs/go2idl/generator/default_generator.go deleted file mode 100644 index 9c88e219466..00000000000 --- a/cmd/libs/go2idl/generator/default_generator.go +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generator - -import ( - "io" - - "k8s.io/kubernetes/cmd/libs/go2idl/namer" - "k8s.io/kubernetes/cmd/libs/go2idl/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{}) -) diff --git a/cmd/libs/go2idl/generator/default_package.go b/cmd/libs/go2idl/generator/default_package.go deleted file mode 100644 index ce72e9fd925..00000000000 --- a/cmd/libs/go2idl/generator/default_package.go +++ /dev/null @@ -1,72 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generator - -import ( - "k8s.io/kubernetes/cmd/libs/go2idl/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{}) -) diff --git a/cmd/libs/go2idl/generator/doc.go b/cmd/libs/go2idl/generator/doc.go deleted file mode 100644 index a954341c419..00000000000 --- a/cmd/libs/go2idl/generator/doc.go +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package generator 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/kubernetes/cmd/libs/go2idl/generator" diff --git a/cmd/libs/go2idl/generator/error_tracker.go b/cmd/libs/go2idl/generator/error_tracker.go deleted file mode 100644 index 964dae37ba5..00000000000 --- a/cmd/libs/go2idl/generator/error_tracker.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generator - -import ( - "io" -) - -// 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 -} diff --git a/cmd/libs/go2idl/generator/execute.go b/cmd/libs/go2idl/generator/execute.go deleted file mode 100644 index bd882891800..00000000000 --- a/cmd/libs/go2idl/generator/execute.go +++ /dev/null @@ -1,309 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generator - -import ( - "bytes" - "fmt" - "go/format" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "k8s.io/kubernetes/cmd/libs/go2idl/namer" - "k8s.io/kubernetes/cmd/libs/go2idl/types" - - "github.com/golang/glog" -) - -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 { - glog.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 { - glog.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") - // TODO: sort imports like goimports does. - 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 NewGolangFile() *DefaultFileType { - return &DefaultFileType{ - Format: format.Source, - 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()) - glog.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.PackageVars(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() -} diff --git a/cmd/libs/go2idl/generator/generator.go b/cmd/libs/go2idl/generator/generator.go deleted file mode 100644 index 6dcf8acaf87..00000000000 --- a/cmd/libs/go2idl/generator/generator.go +++ /dev/null @@ -1,212 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generator - -import ( - "bytes" - "io" - - "k8s.io/kubernetes/cmd/libs/go2idl/namer" - "k8s.io/kubernetes/cmd/libs/go2idl/parser" - "k8s.io/kubernetes/cmd/libs/go2idl/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 codes, and any other content that's not - // generated per-type. For example if you are generating one block (function, - // type, etc) for all types, this function can be used to close the block. - 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. -func (ctxt *Context) AddDir(path string) error { - return ctxt.builder.AddDirTo(path, &ctxt.Universe) -} diff --git a/cmd/libs/go2idl/generator/import_tracker.go b/cmd/libs/go2idl/generator/import_tracker.go deleted file mode 100644 index 74ba484a718..00000000000 --- a/cmd/libs/go2idl/generator/import_tracker.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generator - -import ( - "path/filepath" - "strings" - - "k8s.io/kubernetes/cmd/libs/go2idl/namer" - "k8s.io/kubernetes/cmd/libs/go2idl/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 - dirs := strings.Split(path, string(filepath.Separator)) - for n := len(dirs) - 1; n >= 0; n-- { - // TODO: bikeshed about whether it's more readable to have an - // _, something else, or nothing between directory names. - name := strings.Join(dirs[n:], "_") - // 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) -} diff --git a/cmd/libs/go2idl/generator/snippet_writer.go b/cmd/libs/go2idl/generator/snippet_writer.go deleted file mode 100644 index eae917c1381..00000000000 --- a/cmd/libs/go2idl/generator/snippet_writer.go +++ /dev/null @@ -1,154 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generator - -import ( - "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 -} diff --git a/cmd/libs/go2idl/generator/snippet_writer_test.go b/cmd/libs/go2idl/generator/snippet_writer_test.go deleted file mode 100644 index 70ca703c83f..00000000000 --- a/cmd/libs/go2idl/generator/snippet_writer_test.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package generator_test - -import ( - "bytes" - "strings" - "testing" - - "k8s.io/kubernetes/cmd/libs/go2idl/generator" - "k8s.io/kubernetes/cmd/libs/go2idl/namer" - "k8s.io/kubernetes/cmd/libs/go2idl/parser" -) - -func construct(t *testing.T, files map[string]string) *generator.Context { - b := parser.New() - for name, src := range files { - if err := b.AddFile("/tmp/"+name, name, []byte(src)); err != nil { - t.Fatal(err) - } - } - c, err := generator.NewContext(b, namer.NameSystems{ - "public": namer.NewPublicNamer(0), - "private": namer.NewPrivateNamer(0), - }, "public") - if err != nil { - t.Fatal(err) - } - return c -} - -func TestSnippetWriter(t *testing.T) { - var structTest = map[string]string{ - "base/foo/proto/foo.go": ` -package foo - -// Blah is a test. -// A test, I tell you. -type Blah struct { - // A is the first field. - A int64 ` + "`" + `json:"a"` + "`" + ` - - // B is the second field. - // Multiline comments work. - B string ` + "`" + `json:"b"` + "`" + ` -} -`, - } - - c := construct(t, structTest) - b := &bytes.Buffer{} - err := generator.NewSnippetWriter(b, c, "$", "$"). - Do("$.|public$$.|private$", c.Order[0]). - Error() - if err != nil { - t.Errorf("Unexpected error %v", err) - } - if e, a := "Blahblah", b.String(); e != a { - t.Errorf("Expected %q, got %q", e, a) - } - - err = generator.NewSnippetWriter(b, c, "$", "$"). - Do("$.|public", c.Order[0]). - Error() - if err == nil { - t.Errorf("expected error on invalid template") - } else { - // Dear reader, I apologize for making the worst change - // detection test in the history of ever. - if e, a := "snippet_writer_test.go:78", err.Error(); !strings.Contains(a, e) { - t.Errorf("Expected %q but didn't find it in %q", e, a) - } - } -} diff --git a/cmd/libs/go2idl/namer/doc.go b/cmd/libs/go2idl/namer/doc.go deleted file mode 100644 index 0940380660b..00000000000 --- a/cmd/libs/go2idl/namer/doc.go +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package 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/kubernetes/cmd/libs/go2idl/namer" diff --git a/cmd/libs/go2idl/namer/import_tracker.go b/cmd/libs/go2idl/namer/import_tracker.go deleted file mode 100644 index b62080b3e5f..00000000000 --- a/cmd/libs/go2idl/namer/import_tracker.go +++ /dev/null @@ -1,112 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package namer - -import ( - "sort" - - "k8s.io/kubernetes/cmd/libs/go2idl/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 -} diff --git a/cmd/libs/go2idl/namer/namer.go b/cmd/libs/go2idl/namer/namer.go deleted file mode 100644 index 0c3639fece2..00000000000 --- a/cmd/libs/go2idl/namer/namer.go +++ /dev/null @@ -1,366 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package namer - -import ( - "path/filepath" - "strings" - - "k8s.io/kubernetes/cmd/libs/go2idl/types" -) - -// 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: -// Named types: -// -// 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, string(filepath.Separator)) - 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) - // TODO: add types.Chan - 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 { - if t.Name.Package == r.pkg { - name = t.Name.Name - } else { - r.tracker.AddType(t) - 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, "; ") + "}" - // TODO: add types.Chan - 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 -} diff --git a/cmd/libs/go2idl/namer/namer_test.go b/cmd/libs/go2idl/namer/namer_test.go deleted file mode 100644 index 909f6abdc48..00000000000 --- a/cmd/libs/go2idl/namer/namer_test.go +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package namer - -import ( - "reflect" - "testing" - - "k8s.io/kubernetes/cmd/libs/go2idl/types" -) - -func TestNameStrategy(t *testing.T) { - u := types.Universe{} - - // Add some types. - base := u.Type(types.Name{Package: "foo/bar", Name: "Baz"}) - base.Kind = types.Struct - - tmp := u.Type(types.Name{Package: "", Name: "[]bar.Baz"}) - tmp.Kind = types.Slice - tmp.Elem = base - - tmp = u.Type(types.Name{Package: "", Name: "map[string]bar.Baz"}) - tmp.Kind = types.Map - tmp.Key = types.String - tmp.Elem = base - - tmp = u.Type(types.Name{Package: "foo/other", Name: "Baz"}) - tmp.Kind = types.Struct - tmp.Members = []types.Member{{ - Embedded: true, - Type: base, - }} - - u.Type(types.Name{Package: "", Name: "string"}) - - o := Orderer{NewPublicNamer(0)} - order := o.OrderUniverse(u) - orderedNames := make([]string, len(order)) - for i, t := range order { - orderedNames[i] = o.Name(t) - } - expect := []string{"Baz", "Baz", "MapStringToBaz", "SliceBaz", "String"} - if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { - t.Errorf("Wanted %#v, got %#v", e, a) - } - - o = Orderer{NewRawNamer("my/package", nil)} - order = o.OrderUniverse(u) - orderedNames = make([]string, len(order)) - for i, t := range order { - orderedNames[i] = o.Name(t) - } - - expect = []string{"[]bar.Baz", "bar.Baz", "map[string]bar.Baz", "other.Baz", "string"} - if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { - t.Errorf("Wanted %#v, got %#v", e, a) - } - - o = Orderer{NewRawNamer("foo/bar", nil)} - order = o.OrderUniverse(u) - orderedNames = make([]string, len(order)) - for i, t := range order { - orderedNames[i] = o.Name(t) - } - - expect = []string{"Baz", "[]Baz", "map[string]Baz", "other.Baz", "string"} - if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { - t.Errorf("Wanted %#v, got %#v", e, a) - } - - o = Orderer{NewPublicNamer(1)} - order = o.OrderUniverse(u) - orderedNames = make([]string, len(order)) - for i, t := range order { - orderedNames[i] = o.Name(t) - } - expect = []string{"BarBaz", "MapStringToBarBaz", "OtherBaz", "SliceBarBaz", "String"} - if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { - t.Errorf("Wanted %#v, got %#v", e, a) - } -} diff --git a/cmd/libs/go2idl/namer/order.go b/cmd/libs/go2idl/namer/order.go deleted file mode 100644 index a0c5328e402..00000000000 --- a/cmd/libs/go2idl/namer/order.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package namer - -import ( - "sort" - - "k8s.io/kubernetes/cmd/libs/go2idl/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] } diff --git a/cmd/libs/go2idl/namer/plural_namer.go b/cmd/libs/go2idl/namer/plural_namer.go deleted file mode 100644 index 0d13ba567c5..00000000000 --- a/cmd/libs/go2idl/namer/plural_namer.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package namer - -import ( - "strings" - - "k8s.io/kubernetes/cmd/libs/go2idl/types" -) - -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) - } - switch string(singular[len(singular)-1]) { - case "s", "x": - plural = singular + "es" - case "y": - plural = singular[:len(singular)-1] + "ies" - default: - plural = singular + "s" - } - return r.finalize(plural) -} diff --git a/cmd/libs/go2idl/namer/plural_namer_test.go b/cmd/libs/go2idl/namer/plural_namer_test.go deleted file mode 100644 index e01e4d8d1c6..00000000000 --- a/cmd/libs/go2idl/namer/plural_namer_test.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package namer - -import ( - "testing" - - "k8s.io/kubernetes/cmd/libs/go2idl/types" -) - -func TestPluralNamer(t *testing.T) { - exceptions := map[string]string{ - // The type name is already in the plural form - "Endpoints": "endpoints", - } - public := NewPublicPluralNamer(exceptions) - private := NewPrivatePluralNamer(exceptions) - - cases := []struct { - typeName string - expectedPrivate string - expectedPublic string - }{ - { - "Pod", - "pods", - "Pods", - }, - { - "Entry", - "entries", - "Entries", - }, - { - "Endpoints", - "endpoints", - "Endpoints", - }, - { - "Bus", - "buses", - "Buses", - }, - } - for _, c := range cases { - testType := &types.Type{Name: types.Name{Name: c.typeName}} - if e, a := c.expectedPrivate, private.Name(testType); e != a { - t.Errorf("Unexpected result from private plural namer. Expected: %s, Got: %s", e, a) - } - if e, a := c.expectedPublic, public.Name(testType); e != a { - t.Errorf("Unexpected result from public plural namer. Expected: %s, Got: %s", e, a) - } - } -} diff --git a/cmd/libs/go2idl/parser/doc.go b/cmd/libs/go2idl/parser/doc.go deleted file mode 100644 index 4797daacc6d..00000000000 --- a/cmd/libs/go2idl/parser/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package parser provides code to parse go files, type-check them, extract the -// types. -package parser // import "k8s.io/kubernetes/cmd/libs/go2idl/parser" diff --git a/cmd/libs/go2idl/parser/parse.go b/cmd/libs/go2idl/parser/parse.go deleted file mode 100644 index 4ed9acc8d29..00000000000 --- a/cmd/libs/go2idl/parser/parse.go +++ /dev/null @@ -1,713 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package parser - -import ( - "fmt" - "go/ast" - "go/build" - "go/parser" - "go/token" - tc "go/types" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/golang/glog" - "k8s.io/kubernetes/cmd/libs/go2idl/types" -) - -// 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 - buildInfo map[string]*build.Package - - fset *token.FileSet - // map of package id to list of parsed files - parsed map[string][]parsedFile - // map of package id to absolute path (to prevent overlap) - absPaths map[string]string - - // Set by makePackage(), used by importer() and friends. - pkgs map[string]*tc.Package - - // Map of package path to whether the user requested it or it was from - // an import. - userRequested map[string]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[string]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 { - glog.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, - buildInfo: map[string]*build.Package{}, - fset: token.NewFileSet(), - parsed: map[string][]parsedFile{}, - absPaths: map[string]string{}, - userRequested: map[string]bool{}, - endLineToCommentGroup: map[fileLine]*ast.CommentGroup{}, - importGraph: map[string]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) buildPackage(pkgPath string) (*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. We assume that there is - // only one level of vendoring, and that the CWD is inside the GOPATH, so - // this should be safe. - cwd, err := os.Getwd() - if err != nil { - return nil, fmt.Errorf("unable to get current directory: %v", err) - } - - // First, find it, so we know what path to use. - pkg, err := b.context.Import(pkgPath, cwd, build.FindOnly) - if err != nil { - return nil, fmt.Errorf("unable to *find* %q: %v", pkgPath, err) - } - - pkgPath = pkg.ImportPath - - if pkg, ok := b.buildInfo[pkgPath]; ok { - return pkg, nil - } - pkg, err = b.context.Import(pkgPath, cwd, build.ImportComment) - if err != nil { - if _, ok := err.(*build.NoGoError); !ok { - return nil, fmt.Errorf("unable to import %q: %v", pkgPath, err) - } - } - b.buildInfo[pkgPath] = pkg - - if b.importGraph[pkgPath] == nil { - b.importGraph[pkgPath] = map[string]struct{}{} - } - for _, p := range pkg.Imports { - b.importGraph[pkgPath][p] = struct{}{} - } - return pkg, nil -} - -// AddFile adds a file to the set. The pkg must be of the form -// "canonical/pkg/path" and the path must be the absolute path to the file. -func (b *Builder) AddFile(pkg string, path string, src []byte) error { - return b.addFile(pkg, path, src, true) -} - -// addFile adds a file to the set. The pkg 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(pkg string, path string, src []byte, userRequested bool) error { - p, err := parser.ParseFile(b.fset, path, src, parser.DeclarationErrors|parser.ParseComments) - if err != nil { - return err - } - dirPath := filepath.Dir(path) - if prev, found := b.absPaths[pkg]; found { - if dirPath != prev { - return fmt.Errorf("package %q (%s) previously resolved to %s", pkg, dirPath, prev) - } - } else { - b.absPaths[pkg] = dirPath - } - - b.parsed[pkg] = append(b.parsed[pkg], parsedFile{path, p}) - b.userRequested[pkg] = userRequested - 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[pkg] == nil { - b.importGraph[pkg] = map[string]struct{}{} - } - for _, im := range p.Imports { - importedPath := strings.Trim(im.Path.Value, `"`) - b.importGraph[pkg][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 { - return b.addDir(dir, true) -} - -// 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 { - // 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. We assume that there is - // only one level of vendoring, and that the CWD is inside the GOPATH, so - // this should be safe. - cwd, err := os.Getwd() - if err != nil { - return fmt.Errorf("unable to get current directory: %v", err) - } - - // First, find it, so we know what path to use. - pkg, err := b.context.Import(dir, cwd, build.FindOnly) - if err != nil { - return fmt.Errorf("unable to *find* %q: %v", dir, err) - } - - if err := b.addDir(dir, true); err != nil { - glog.Warningf("Ignoring directory %v: %v", dir, err) - } - - prefix := strings.TrimSuffix(pkg.Dir, strings.TrimSuffix(dir, "/")) - filepath.Walk(pkg.Dir, func(path string, info os.FileInfo, err error) error { - if info != nil && info.IsDir() { - trimmed := strings.TrimPrefix(path, prefix) - if trimmed != "" { - if err := b.addDir(trimmed, true); err != nil { - glog.Warningf("Ignoring child directory %v: %v", trimmed, err) - } - } - } - return nil - }) - 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. -func (b *Builder) AddDirTo(dir string, u *types.Universe) error { - if _, found := b.parsed[dir]; !found { - // 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.addDir(dir, true); err != nil { - return err - } - } else { - // We already had this package, but we want it to be considered as if - // the user addid it directly. - b.userRequested[dir] = true - } - return b.findTypesIn(dir, u) -} - -// 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 { - pkg, err := b.buildPackage(dir) - if err != nil { - return err - } - // Check in case this package was added (maybe dir was not canonical) - if wasRequested, wasAdded := b.userRequested[dir]; wasAdded { - if !userRequested || userRequested == wasRequested { - return nil - } - } - - for _, n := range pkg.GoFiles { - if !strings.HasSuffix(n, ".go") { - continue - } - absPath := filepath.Join(pkg.Dir, n) - data, err := ioutil.ReadFile(absPath) - if err != nil { - return fmt.Errorf("while loading %q: %v", absPath, err) - } - err = b.addFile(dir, absPath, data, userRequested) - if err != nil { - return fmt.Errorf("while parsing %q: %v", absPath, err) - } - } - return nil -} - -// importer 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. go1.5 changes the -// interface, and importAdapter below implements the new interface in terms of -// the old one. -func (b *Builder) importer(imports map[string]*tc.Package, path string) (*tc.Package, error) { - if pkg, ok := imports[path]; ok { - return pkg, nil - } - ignoreError := false - if _, ours := b.parsed[path]; !ours { - // Ignore errors in paths that we're importing solely because - // they're referenced by other packages. - ignoreError = true - if err := b.addDir(path, false); err != nil { - return nil, err - } - } - pkg, err := b.typeCheckPackage(path) - if err != nil { - if ignoreError && pkg != nil { - glog.V(2).Infof("type checking encountered some errors in %q, but ignoring.\n", path) - } else { - return nil, err - } - } - imports[path] = pkg - return pkg, nil -} - -type importAdapter struct { - b *Builder -} - -func (a importAdapter) Import(path string) (*tc.Package, error) { - return a.b.importer(a.b.pkgs, path) -} - -// 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(id string) (*tc.Package, error) { - if pkg, ok := b.pkgs[id]; ok { - if pkg != nil { - 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", id) - } - parsedFiles, ok := b.parsed[id] - if !ok { - return nil, fmt.Errorf("No files for pkg %q: %#v", id, b.parsed) - } - files := make([]*ast.File, len(parsedFiles)) - for i := range parsedFiles { - files[i] = parsedFiles[i].file - } - b.pkgs[id] = nil - c := tc.Config{ - IgnoreFuncBodies: true, - // Note that importAdater can call b.import which calls this - // method. So there can't be cycles in the import graph. - Importer: importAdapter{b}, - Error: func(err error) { - glog.V(2).Infof("type checker error: %v\n", err) - }, - } - pkg, err := c.Check(id, b.fset, files, nil) - b.pkgs[id] = pkg // record the result whether or not there was an error - return pkg, err -} - -func (b *Builder) makeAllPackages() error { - // Take a snapshot to iterate, since this will recursively mutate b.parsed. - keys := []string{} - for id := range b.parsed { - keys = append(keys, id) - } - for _, id := range keys { - if _, err := b.makePackage(id); err != nil { - return err - } - } - return nil -} - -func (b *Builder) makePackage(id string) (*tc.Package, error) { - if b.pkgs == nil { - b.pkgs = map[string]*tc.Package{} - } - - // We have to check here even though we made a new one above, - // because typeCheckPackage follows the import graph, which may - // cause a package to be filled before we get to it in this - // loop. - if pkg, done := b.pkgs[id]; done { - return pkg, nil - } - return b.typeCheckPackage(id) -} - -// FindPackages fetches a list of the user-imported packages. -func (b *Builder) FindPackages() []string { - result := []string{} - for pkgPath := range b.pkgs { - if b.userRequested[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) { - if err := b.makeAllPackages(); err != nil { - return nil, err - } - - u := types.Universe{} - - for pkgPath := range b.parsed { - if err := b.findTypesIn(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 string, u *types.Universe) error { - pkg, err := b.makePackage(pkgPath) - if err != nil { - return err - } - 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. - return nil - } - - for _, f := range b.parsed[pkgPath] { - if strings.HasSuffix(f.name, "/doc.go") { - tp := u.Package(pkgPath) - 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) - 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 { - b.addFunction(*u, nil, tf) - } - tv, ok := obj.(*tc.Var) - if ok && !tv.IsField() { - b.addVariable(*u, nil, tv) - } - } - for p := range b.importGraph[pkgPath] { - u.AddImports(pkgPath, p) - } - u.Package(pkgPath).Name = pkg.Name() - return 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.TrimLeft(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: - 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()) - return out - 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 len(out.Methods) == 0 { - // If the underlying type didn't already add - // methods, add them. (Interface types will - // have already added methods.) - 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 - glog.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 -} diff --git a/cmd/libs/go2idl/parser/parse_test.go b/cmd/libs/go2idl/parser/parse_test.go deleted file mode 100644 index 7ffd198c432..00000000000 --- a/cmd/libs/go2idl/parser/parse_test.go +++ /dev/null @@ -1,420 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package parser_test - -import ( - "bytes" - "path/filepath" - "reflect" - "testing" - "text/template" - - "k8s.io/kubernetes/cmd/libs/go2idl/namer" - "k8s.io/kubernetes/cmd/libs/go2idl/parser" - "k8s.io/kubernetes/cmd/libs/go2idl/types" -) - -func construct(t *testing.T, files map[string]string, testNamer namer.Namer) (*parser.Builder, types.Universe, []*types.Type) { - b := parser.New() - for name, src := range files { - if err := b.AddFile(filepath.Dir(name), name, []byte(src)); err != nil { - t.Fatal(err) - } - } - u, err := b.FindTypes() - if err != nil { - t.Fatal(err) - } - orderer := namer.Orderer{Namer: testNamer} - o := orderer.OrderUniverse(u) - return b, u, o -} - -func TestBuilder(t *testing.T) { - var testFiles = map[string]string{ - "base/foo/proto/foo.go": ` -package foo - -import ( - "base/common/proto" -) - -type Blah struct { - common.Object - Count int64 - Frobbers map[string]*Frobber - Baz []Object - Nickname *string - NumberIsAFavorite map[int]bool -} - -type Frobber struct { - Name string - Amount int64 -} - -type Object struct { - common.Object -} - -func AFunc(obj1 common.Object, obj2 Object) Frobber { -} - -var AVar Frobber - -var ( - AnotherVar = Frobber{} -) -`, - "base/common/proto/common.go": ` -package common - -type Object struct { - ID int64 -} -`, - } - - var tmplText = ` -package o -{{define "Struct"}}type {{Name .}} interface { {{range $m := .Members}}{{$n := Name $m.Type}} - {{if $m.Embedded}}{{$n}}{{else}}{{$m.Name}}() {{$n}}{{if $m.Type.Elem}}{{else}} - Set{{$m.Name}}({{$n}}){{end}}{{end}}{{end}} -} - -{{end}} -{{define "Func"}}{{$s := .Underlying.Signature}}var {{Name .}} func({{range $index,$elem := $s.Parameters}}{{if $index}}, {{end}}{{Raw $elem}}{{end}}) {{if $s.Results|len |gt 1}}({{end}}{{range $index,$elem := $s.Results}}{{if $index}}, {{end}}{{Raw .}}{{end}}{{if $s.Results|len |gt 1}}){{end}} = {{Raw .}} - -{{end}} -{{define "Var"}}{{$t := .Underlying}}var {{Name .}} {{Raw $t}} = {{Raw .}} - -{{end}} -{{range $t := .}}{{if eq $t.Kind "Struct"}}{{template "Struct" $t}}{{end}}{{end}} -{{range $t := .}}{{if eq $t.Kind "DeclarationOf"}}{{if eq $t.Underlying.Kind "Func"}}{{template "Func" $t}}{{end}}{{end}}{{end}} -{{range $t := .}}{{if eq $t.Kind "DeclarationOf"}}{{if ne $t.Underlying.Kind "Func"}}{{template "Var" $t}}{{end}}{{end}}{{end}}` - - var expect = ` -package o - - - -type CommonObject interface { - ID() Int64 - SetID(Int64) -} - -type FooBlah interface { - CommonObject - Count() Int64 - SetCount(Int64) - Frobbers() MapStringToPointerFooFrobber - Baz() SliceFooObject - Nickname() PointerString - NumberIsAFavorite() MapIntToBool -} - -type FooFrobber interface { - Name() String - SetName(String) - Amount() Int64 - SetAmount(Int64) -} - -type FooObject interface { - CommonObject -} - - -var FooAFunc func(proto.Object, proto.Object) proto.Frobber = proto.AFunc - - -var FooAVar proto.Frobber = proto.AVar - -var FooAnotherVar proto.Frobber = proto.AnotherVar - -` - testNamer := namer.NewPublicNamer(1, "proto") - rawNamer := namer.NewRawNamer("o", nil) - _, u, o := construct(t, testFiles, testNamer) - t.Logf("\n%v\n\n", o) - args := map[string]interface{}{ - "Name": testNamer.Name, - "Raw": rawNamer.Name, - } - tmpl := template.Must( - template.New(""). - Funcs(args). - Parse(tmplText), - ) - buf := &bytes.Buffer{} - tmpl.Execute(buf, o) - if e, a := expect, buf.String(); e != a { - t.Errorf("Wanted, got:\n%v\n-----\n%v\n", e, a) - } - if p := u.Package("base/foo/proto"); !p.HasImport("base/common/proto") { - t.Errorf("Unexpected lack of import line: %s", p.Imports) - } -} - -func TestStructParse(t *testing.T) { - var structTest = map[string]string{ - "base/foo/proto/foo.go": ` -package foo - -// Blah is a test. -// A test, I tell you. -type Blah struct { - // A is the first field. - A int64 ` + "`" + `json:"a"` + "`" + ` - - // B is the second field. - // Multiline comments work. - B string ` + "`" + `json:"b"` + "`" + ` -} -`, - } - - _, u, o := construct(t, structTest, namer.NewPublicNamer(0)) - t.Logf("%#v", o) - blahT := u.Type(types.Name{Package: "base/foo/proto", Name: "Blah"}) - if blahT == nil { - t.Fatal("type not found") - } - if e, a := types.Struct, blahT.Kind; e != a { - t.Errorf("struct kind wrong, wanted %v, got %v", e, a) - } - if e, a := []string{"Blah is a test.", "A test, I tell you."}, blahT.CommentLines; !reflect.DeepEqual(e, a) { - t.Errorf("struct comment wrong, wanted %q, got %q", e, a) - } - m := types.Member{ - Name: "B", - Embedded: false, - CommentLines: []string{"B is the second field.", "Multiline comments work."}, - Tags: `json:"b"`, - Type: types.String, - } - if e, a := m, blahT.Members[1]; !reflect.DeepEqual(e, a) { - t.Errorf("wanted, got:\n%#v\n%#v", e, a) - } -} - -func TestParseSecondClosestCommentLines(t *testing.T) { - const fileName = "base/foo/proto/foo.go" - testCases := []struct { - testFile map[string]string - expected []string - }{ - { - map[string]string{fileName: `package foo -// Blah's SecondClosestCommentLines. -// Another line. - -// Blah is a test. -// A test, I tell you. -type Blah struct { - a int -} -`}, - []string{"Blah's SecondClosestCommentLines.", "Another line."}, - }, - { - map[string]string{fileName: `package foo -// Blah's SecondClosestCommentLines. -// Another line. - -type Blah struct { - a int -} -`}, - []string{"Blah's SecondClosestCommentLines.", "Another line."}, - }, - } - for _, test := range testCases { - _, u, o := construct(t, test.testFile, namer.NewPublicNamer(0)) - t.Logf("%#v", o) - blahT := u.Type(types.Name{Package: "base/foo/proto", Name: "Blah"}) - if e, a := test.expected, blahT.SecondClosestCommentLines; !reflect.DeepEqual(e, a) { - t.Errorf("struct second closest comment wrong, wanted %q, got %q", e, a) - } - } -} - -func TestTypeKindParse(t *testing.T) { - var testFiles = map[string]string{ - "a/foo.go": "package a\ntype Test string\n", - "b/foo.go": "package b\ntype Test map[int]string\n", - "c/foo.go": "package c\ntype Test []string\n", - "d/foo.go": "package d\ntype Test struct{a int; b struct{a int}; c map[int]string; d *string}\n", - "e/foo.go": "package e\ntype Test *string\n", - "f/foo.go": ` -package f -import ( - "a" - "b" -) -type Test []a.Test -type Test2 *a.Test -type Test3 map[a.Test]b.Test -type Test4 struct { - a struct {a a.Test; b b.Test} - b map[a.Test]b.Test - c *a.Test - d []a.Test - e []string -} -`, - "g/foo.go": ` -package g -type Test func(a, b string) (c, d string) -func (t Test) Method(a, b string) (c, d string) { return t(a, b) } -type Interface interface{Method(a, b string) (c, d string)} -`, - } - - // Check that the right types are found, and the namers give the expected names. - - assertions := []struct { - Package, Name string - k types.Kind - names []string - }{ - { - Package: "a", Name: "Test", k: types.Alias, - names: []string{"Test", "ATest", "test", "aTest", "a.Test"}, - }, - { - Package: "b", Name: "Test", k: types.Map, - names: []string{"Test", "BTest", "test", "bTest", "b.Test"}, - }, - { - Package: "c", Name: "Test", k: types.Slice, - names: []string{"Test", "CTest", "test", "cTest", "c.Test"}, - }, - { - Package: "d", Name: "Test", k: types.Struct, - names: []string{"Test", "DTest", "test", "dTest", "d.Test"}, - }, - { - Package: "e", Name: "Test", k: types.Pointer, - names: []string{"Test", "ETest", "test", "eTest", "e.Test"}, - }, - { - Package: "f", Name: "Test", k: types.Slice, - names: []string{"Test", "FTest", "test", "fTest", "f.Test"}, - }, - { - Package: "g", Name: "Test", k: types.Func, - names: []string{"Test", "GTest", "test", "gTest", "g.Test"}, - }, - { - Package: "g", Name: "Interface", k: types.Interface, - names: []string{"Interface", "GInterface", "interface", "gInterface", "g.Interface"}, - }, - { - Package: "", Name: "string", k: types.Builtin, - names: []string{"String", "String", "string", "string", "string"}, - }, - { - Package: "", Name: "int", k: types.Builtin, - names: []string{"Int", "Int", "int", "int", "int"}, - }, - { - Package: "", Name: "struct{a int}", k: types.Struct, - names: []string{"StructInt", "StructInt", "structInt", "structInt", "struct{a int}"}, - }, - { - Package: "", Name: "struct{a a.Test; b b.Test}", k: types.Struct, - names: []string{"StructTestTest", "StructATestBTest", "structTestTest", "structATestBTest", "struct{a a.Test; b b.Test}"}, - }, - { - Package: "", Name: "map[int]string", k: types.Map, - names: []string{"MapIntToString", "MapIntToString", "mapIntToString", "mapIntToString", "map[int]string"}, - }, - { - Package: "", Name: "map[a.Test]b.Test", k: types.Map, - names: []string{"MapTestToTest", "MapATestToBTest", "mapTestToTest", "mapATestToBTest", "map[a.Test]b.Test"}, - }, - { - Package: "", Name: "[]string", k: types.Slice, - names: []string{"SliceString", "SliceString", "sliceString", "sliceString", "[]string"}, - }, - { - Package: "", Name: "[]a.Test", k: types.Slice, - names: []string{"SliceTest", "SliceATest", "sliceTest", "sliceATest", "[]a.Test"}, - }, - { - Package: "", Name: "*string", k: types.Pointer, - names: []string{"PointerString", "PointerString", "pointerString", "pointerString", "*string"}, - }, - { - Package: "", Name: "*a.Test", k: types.Pointer, - names: []string{"PointerTest", "PointerATest", "pointerTest", "pointerATest", "*a.Test"}, - }, - } - - namers := []namer.Namer{ - namer.NewPublicNamer(0), - namer.NewPublicNamer(1), - namer.NewPrivateNamer(0), - namer.NewPrivateNamer(1), - namer.NewRawNamer("", nil), - } - - for nameIndex, namer := range namers { - _, u, _ := construct(t, testFiles, namer) - t.Logf("Found types:\n") - for pkgName, pkg := range u { - for typeName, cur := range pkg.Types { - t.Logf("%q-%q: %s %s", pkgName, typeName, cur.Name, cur.Kind) - } - } - t.Logf("\n\n") - - for _, item := range assertions { - n := types.Name{Package: item.Package, Name: item.Name} - thisType := u.Type(n) - if thisType == nil { - t.Errorf("type %s not found", n) - continue - } - underlyingType := thisType - if item.k != types.Alias && thisType.Kind == types.Alias { - underlyingType = thisType.Underlying - if underlyingType == nil { - t.Errorf("underlying type %s not found", n) - continue - } - } - if e, a := item.k, underlyingType.Kind; e != a { - t.Errorf("%v-%s: type kind wrong, wanted %v, got %v (%#v)", nameIndex, n, e, a, underlyingType) - } - if e, a := item.names[nameIndex], namer.Name(thisType); e != a { - t.Errorf("%v-%s: Expected %q, got %q", nameIndex, n, e, a) - } - } - - // Also do some one-off checks - gtest := u.Type(types.Name{Package: "g", Name: "Test"}) - if e, a := 1, len(gtest.Methods); e != a { - t.Errorf("expected %v but found %v methods: %#v", e, a, gtest) - } - iface := u.Type(types.Name{Package: "g", Name: "Interface"}) - if e, a := 1, len(iface.Methods); e != a { - t.Errorf("expected %v but found %v methods: %#v", e, a, iface) - } - } -} diff --git a/cmd/libs/go2idl/types/comments.go b/cmd/libs/go2idl/types/comments.go deleted file mode 100644 index 8150c383875..00000000000 --- a/cmd/libs/go2idl/types/comments.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package types 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]) -} diff --git a/cmd/libs/go2idl/types/comments_test.go b/cmd/libs/go2idl/types/comments_test.go deleted file mode 100644 index 161f4a6e98c..00000000000 --- a/cmd/libs/go2idl/types/comments_test.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -import ( - "reflect" - "strings" - "testing" -) - -func TestExtractCommentTags(t *testing.T) { - commentLines := []string{ - "Human comment that is ignored.", - "+foo=value1", - "+bar", - "+foo=value2", - "+baz=qux,zrb=true", - } - - a := ExtractCommentTags("+", commentLines) - e := map[string][]string{ - "foo": {"value1", "value2"}, - "bar": {""}, - "baz": {"qux,zrb=true"}, - } - if !reflect.DeepEqual(e, a) { - t.Errorf("Wanted %q, got %q", e, a) - } -} - -func TestExtractSingleBoolCommentTag(t *testing.T) { - commentLines := []string{ - "Human comment that is ignored.", - "+TRUE=true", - "+FALSE=false", - "+MULTI=true", - "+MULTI=false", - "+MULTI=multi", - "+NOTBOOL=blue", - "+EMPTY", - } - - testCases := []struct { - key string - def bool - exp bool - err string // if set, ignore exp. - }{ - {"TRUE", false, true, ""}, - {"FALSE", true, false, ""}, - {"MULTI", false, true, ""}, - {"NOTBOOL", false, true, "is not boolean"}, - {"EMPTY", false, true, "is not boolean"}, - {"ABSENT", true, true, ""}, - {"ABSENT", false, false, ""}, - } - - for i, tc := range testCases { - v, err := ExtractSingleBoolCommentTag("+", tc.key, tc.def, commentLines) - if err != nil && tc.err == "" { - t.Errorf("[%d]: unexpected failure: %v", i, err) - } else if err == nil && tc.err != "" { - t.Errorf("[%d]: expected failure: %v", i, tc.err) - } else if err != nil { - if !strings.Contains(err.Error(), tc.err) { - t.Errorf("[%d]: unexpected error: expected %q, got %q", i, tc.err, err) - } - } else if v != tc.exp { - t.Errorf("[%d]: unexpected value: expected %t, got %t", i, tc.exp, v) - } - } -} diff --git a/cmd/libs/go2idl/types/doc.go b/cmd/libs/go2idl/types/doc.go deleted file mode 100644 index 8a5ff0f367b..00000000000 --- a/cmd/libs/go2idl/types/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package types 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/kubernetes/cmd/libs/go2idl/types" diff --git a/cmd/libs/go2idl/types/flatten.go b/cmd/libs/go2idl/types/flatten.go deleted file mode 100644 index 585014e8ba0..00000000000 --- a/cmd/libs/go2idl/types/flatten.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -// FlattenMembers recursively takes any embedded members and puts them in the -// top level, correctly hiding them if the top level hides them. There must not -// be a cycle-- that implies infinite members. -// -// This is useful for e.g. computing all the valid keys in a json struct, -// properly considering any configuration of embedded structs. -func FlattenMembers(m []Member) []Member { - embedded := []Member{} - normal := []Member{} - type nameInfo struct { - top bool - i int - } - names := map[string]nameInfo{} - for i := range m { - if m[i].Embedded && m[i].Type.Kind == Struct { - embedded = append(embedded, m[i]) - } else { - normal = append(normal, m[i]) - names[m[i].Name] = nameInfo{true, len(normal) - 1} - } - } - for i := range embedded { - for _, e := range FlattenMembers(embedded[i].Type.Members) { - if info, found := names[e.Name]; found { - if info.top { - continue - } - if n := normal[info.i]; n.Name == e.Name && n.Type == e.Type { - continue - } - panic("conflicting members") - } - normal = append(normal, e) - names[e.Name] = nameInfo{false, len(normal) - 1} - } - } - return normal -} diff --git a/cmd/libs/go2idl/types/flatten_test.go b/cmd/libs/go2idl/types/flatten_test.go deleted file mode 100644 index 9da34e56169..00000000000 --- a/cmd/libs/go2idl/types/flatten_test.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -import ( - "reflect" - "testing" -) - -func TestFlatten(t *testing.T) { - mapType := &Type{ - Name: Name{Package: "", Name: "map[string]string"}, - Kind: Map, - Key: String, - Elem: String, - } - m := []Member{ - { - Name: "Baz", - Embedded: true, - Type: &Type{ - Name: Name{Package: "pkg", Name: "Baz"}, - Kind: Struct, - Members: []Member{ - {Name: "Foo", Type: String}, - { - Name: "Qux", - Embedded: true, - Type: &Type{ - Name: Name{Package: "pkg", Name: "Qux"}, - Kind: Struct, - Members: []Member{{Name: "Zot", Type: String}}, - }, - }, - }, - }, - }, - {Name: "Bar", Type: String}, - { - Name: "NotSureIfLegal", - Embedded: true, - Type: mapType, - }, - } - e := []Member{ - {Name: "Bar", Type: String}, - {Name: "NotSureIfLegal", Type: mapType, Embedded: true}, - {Name: "Foo", Type: String}, - {Name: "Zot", Type: String}, - } - if a := FlattenMembers(m); !reflect.DeepEqual(e, a) { - t.Errorf("Expected \n%#v\n, got \n%#v\n", e, a) - } -} diff --git a/cmd/libs/go2idl/types/types.go b/cmd/libs/go2idl/types/types.go deleted file mode 100644 index 89523433e7d..00000000000 --- a/cmd/libs/go2idl/types/types.go +++ /dev/null @@ -1,480 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -// 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 -} - -// 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 - - // Short name of this package; the name that appears in the - // 'package x' line. - Name string - - // DocComments from doc.go, if any. - DocComments []string - - // Comments from doc.go, if any. - 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 varaible 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 - } -} diff --git a/cmd/libs/go2idl/types/types_test.go b/cmd/libs/go2idl/types/types_test.go deleted file mode 100644 index 35cc4d61d73..00000000000 --- a/cmd/libs/go2idl/types/types_test.go +++ /dev/null @@ -1,210 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -import ( - "testing" -) - -func TestGetBuiltin(t *testing.T) { - u := Universe{} - if builtinPkg := u.Package(""); builtinPkg.Has("string") { - t.Errorf("Expected builtin package to not have builtins until they're asked for explicitly. %#v", builtinPkg) - } - s := u.Type(Name{Package: "", Name: "string"}) - if s != String { - t.Errorf("Expected canonical string type.") - } - if builtinPkg := u.Package(""); !builtinPkg.Has("string") { - t.Errorf("Expected builtin package to exist and have builtins by default. %#v", builtinPkg) - } - if builtinPkg := u.Package(""); len(builtinPkg.Types) != 1 { - t.Errorf("Expected builtin package to not have builtins until they're asked for explicitly. %#v", builtinPkg) - } -} - -func TestGetMarker(t *testing.T) { - u := Universe{} - n := Name{Package: "path/to/package", Name: "Foo"} - f := u.Type(n) - if f == nil || f.Name != n { - t.Errorf("Expected marker type.") - } -} - -func Test_Type_IsPrimitive(t *testing.T) { - testCases := []struct { - typ Type - expect bool - }{ - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Builtin, - }, - expect: true, - }, - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Alias, - Underlying: &Type{ - Name: Name{Package: "pkgname", Name: "underlying"}, - Kind: Builtin, - }, - }, - expect: true, - }, - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Pointer, - Elem: &Type{ - Name: Name{Package: "pkgname", Name: "pointee"}, - Kind: Builtin, - }, - }, - expect: false, - }, - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Struct, - }, - expect: false, - }, - } - - for i, tc := range testCases { - r := tc.typ.IsPrimitive() - if r != tc.expect { - t.Errorf("case[%d]: expected %t, got %t", i, tc.expect, r) - } - } -} - -func Test_Type_IsAssignable(t *testing.T) { - testCases := []struct { - typ Type - expect bool - }{ - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Builtin, - }, - expect: true, - }, - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Alias, - Underlying: &Type{ - Name: Name{Package: "pkgname", Name: "underlying"}, - Kind: Builtin, - }, - }, - expect: true, - }, - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Pointer, - Elem: &Type{ - Name: Name{Package: "pkgname", Name: "pointee"}, - Kind: Builtin, - }, - }, - expect: false, - }, - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Struct, // Empty struct - }, - expect: true, - }, - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Struct, - Members: []Member{ - { - Name: "m1", - Type: &Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Builtin, - }, - }, - { - Name: "m2", - Type: &Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Alias, - Underlying: &Type{ - Name: Name{Package: "pkgname", Name: "underlying"}, - Kind: Builtin, - }, - }, - }, - { - Name: "m3", - Type: &Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Struct, // Empty struct - }, - }, - }, - }, - expect: true, - }, - { - typ: Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Struct, - Members: []Member{ - { - Name: "m1", - Type: &Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Builtin, - }, - }, - { - Name: "m2", - Type: &Type{ - Name: Name{Package: "pkgname", Name: "typename"}, - Kind: Pointer, - Elem: &Type{ - Name: Name{Package: "pkgname", Name: "pointee"}, - Kind: Builtin, - }, - }, - }, - }, - }, - expect: false, - }, - } - - for i, tc := range testCases { - r := tc.typ.IsAssignable() - if r != tc.expect { - t.Errorf("case[%d]: expected %t, got %t", i, tc.expect, r) - } - } -}