mirror of https://github.com/kubernetes/kops.git
123 lines
3.4 KiB
Go
123 lines
3.4 KiB
Go
/*
|
|
Copyright 2019 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package codegen
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/build"
|
|
"go/importer"
|
|
"go/parser"
|
|
"go/token"
|
|
"go/types"
|
|
"log"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type GoParser struct {
|
|
Package *Package // Package we are scanning.
|
|
}
|
|
|
|
// File holds a single parsed file and associated data.
|
|
type File struct {
|
|
pkg *Package // Package to which this file belongs.
|
|
file *ast.File // Parsed AST.
|
|
// These fields are reset for each type being generated.
|
|
typeName string // Name of the constant type.
|
|
//values []Value // Accumulator for constant values of that type.
|
|
}
|
|
|
|
type Package struct {
|
|
dir string
|
|
Name string
|
|
defs map[*ast.Ident]types.Object
|
|
files []*File
|
|
typesPkg *types.Package
|
|
}
|
|
|
|
// prefixDirectory prepends the directory name on the beginning of each name in the list.
|
|
func prefixDirectory(directory string, names []string) []string {
|
|
if directory == "." {
|
|
return names
|
|
}
|
|
ret := make([]string, len(names))
|
|
for i, name := range names {
|
|
ret[i] = filepath.Join(directory, name)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// parsePackageDir parses the package residing in the directory.
|
|
func (g *GoParser) parsePackageDir(directory string) {
|
|
pkg, err := build.Default.ImportDir(directory, 0)
|
|
if err != nil {
|
|
log.Fatalf("cannot process directory %s: %s", directory, err)
|
|
}
|
|
var names []string
|
|
names = append(names, pkg.GoFiles...)
|
|
//names = append(names, pkg.CgoFiles...)
|
|
//names = append(names, pkg.SFiles...)
|
|
names = prefixDirectory(directory, names)
|
|
g.parsePackage(directory, names, nil)
|
|
}
|
|
|
|
// parsePackage analyzes the single package constructed from the named files.
|
|
// If text is non-nil, it is a string to be used instead of the content of the file,
|
|
// to be used for testing. parsePackage exits if there is an error.
|
|
func (g *GoParser) parsePackage(directory string, names []string, text interface{}) {
|
|
var files []*File
|
|
var astFiles []*ast.File
|
|
g.Package = new(Package)
|
|
fs := token.NewFileSet()
|
|
for _, name := range names {
|
|
if !strings.HasSuffix(name, ".go") {
|
|
continue
|
|
}
|
|
parsedFile, err := parser.ParseFile(fs, name, text, 0)
|
|
if err != nil {
|
|
log.Fatalf("parsing package: %s: %s", name, err)
|
|
}
|
|
astFiles = append(astFiles, parsedFile)
|
|
files = append(files, &File{
|
|
file: parsedFile,
|
|
pkg: g.Package,
|
|
})
|
|
}
|
|
if len(astFiles) == 0 {
|
|
log.Fatalf("%s: no buildable Go files", directory)
|
|
}
|
|
g.Package.Name = astFiles[0].Name.Name
|
|
g.Package.files = files
|
|
g.Package.dir = directory
|
|
// Type check the package.
|
|
g.Package.check(fs, astFiles)
|
|
}
|
|
|
|
// check type-checks the package. The package must be OK to proceed.
|
|
func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
|
|
pkg.defs = make(map[*ast.Ident]types.Object)
|
|
config := types.Config{Importer: importer.For("source", nil), FakeImportC: true}
|
|
info := &types.Info{
|
|
Defs: pkg.defs,
|
|
}
|
|
typesPkg, err := config.Check(pkg.dir, fs, astFiles, info)
|
|
if err != nil {
|
|
log.Fatalf("checking package: %s", err)
|
|
}
|
|
pkg.typesPkg = typesPkg
|
|
}
|