aboutsummaryrefslogtreecommitdiff
path: root/go/tools/gopackagesdriver/flatpackage.go
diff options
context:
space:
mode:
Diffstat (limited to 'go/tools/gopackagesdriver/flatpackage.go')
-rw-r--r--go/tools/gopackagesdriver/flatpackage.go159
1 files changed, 159 insertions, 0 deletions
diff --git a/go/tools/gopackagesdriver/flatpackage.go b/go/tools/gopackagesdriver/flatpackage.go
new file mode 100644
index 00000000..9c22132a
--- /dev/null
+++ b/go/tools/gopackagesdriver/flatpackage.go
@@ -0,0 +1,159 @@
+// Copyright 2021 The Bazel Authors. All rights reserved.
+//
+// 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 main
+
+import (
+ "encoding/json"
+ "fmt"
+ "go/parser"
+ "go/token"
+ "os"
+ "strconv"
+ "strings"
+)
+
+type ResolvePkgFunc func(importPath string) string
+
+// Copy and pasted from golang.org/x/tools/go/packages
+type FlatPackagesError struct {
+ Pos string // "file:line:col" or "file:line" or "" or "-"
+ Msg string
+ Kind FlatPackagesErrorKind
+}
+
+type FlatPackagesErrorKind int
+
+const (
+ UnknownError FlatPackagesErrorKind = iota
+ ListError
+ ParseError
+ TypeError
+)
+
+func (err FlatPackagesError) Error() string {
+ pos := err.Pos
+ if pos == "" {
+ pos = "-" // like token.Position{}.String()
+ }
+ return pos + ": " + err.Msg
+}
+
+// FlatPackage is the JSON form of Package
+// It drops all the type and syntax fields, and transforms the Imports
+type FlatPackage struct {
+ ID string
+ Name string `json:",omitempty"`
+ PkgPath string `json:",omitempty"`
+ Errors []FlatPackagesError `json:",omitempty"`
+ GoFiles []string `json:",omitempty"`
+ CompiledGoFiles []string `json:",omitempty"`
+ OtherFiles []string `json:",omitempty"`
+ ExportFile string `json:",omitempty"`
+ Imports map[string]string `json:",omitempty"`
+ Standard bool `json:",omitempty"`
+}
+
+type (
+ PackageFunc func(pkg *FlatPackage)
+ PathResolverFunc func(path string) string
+)
+
+func resolvePathsInPlace(prf PathResolverFunc, paths []string) {
+ for i, path := range paths {
+ paths[i] = prf(path)
+ }
+}
+
+func WalkFlatPackagesFromJSON(jsonFile string, onPkg PackageFunc) error {
+ f, err := os.Open(jsonFile)
+ if err != nil {
+ return fmt.Errorf("unable to open package JSON file: %w", err)
+ }
+ defer f.Close()
+
+ decoder := json.NewDecoder(f)
+ for decoder.More() {
+ pkg := &FlatPackage{}
+ if err := decoder.Decode(&pkg); err != nil {
+ return fmt.Errorf("unable to decode package in %s: %w", f.Name(), err)
+ }
+
+ onPkg(pkg)
+ }
+ return nil
+}
+
+func (fp *FlatPackage) ResolvePaths(prf PathResolverFunc) error {
+ resolvePathsInPlace(prf, fp.CompiledGoFiles)
+ resolvePathsInPlace(prf, fp.GoFiles)
+ resolvePathsInPlace(prf, fp.OtherFiles)
+ fp.ExportFile = prf(fp.ExportFile)
+ return nil
+}
+
+// FilterFilesForBuildTags filters the source files given the current build
+// tags.
+func (fp *FlatPackage) FilterFilesForBuildTags() {
+ fp.GoFiles = filterSourceFilesForTags(fp.GoFiles)
+ fp.CompiledGoFiles = filterSourceFilesForTags(fp.CompiledGoFiles)
+}
+
+func (fp *FlatPackage) IsStdlib() bool {
+ return fp.Standard
+}
+
+func (fp *FlatPackage) ResolveImports(resolve ResolvePkgFunc) error {
+ // Stdlib packages are already complete import wise
+ if fp.IsStdlib() {
+ return nil
+ }
+
+ fset := token.NewFileSet()
+
+ for _, file := range fp.CompiledGoFiles {
+ f, err := parser.ParseFile(fset, file, nil, parser.ImportsOnly)
+ if err != nil {
+ return err
+ }
+ // If the name is not provided, fetch it from the sources
+ if fp.Name == "" {
+ fp.Name = f.Name.Name
+ }
+
+ for _, rawImport := range f.Imports {
+ imp, err := strconv.Unquote(rawImport.Path.Value)
+ if err != nil {
+ continue
+ }
+ // We don't handle CGo for now
+ if imp == "C" {
+ continue
+ }
+ if _, ok := fp.Imports[imp]; ok {
+ continue
+ }
+
+ if pkgID := resolve(imp); pkgID != "" {
+ fp.Imports[imp] = pkgID
+ }
+ }
+ }
+
+ return nil
+}
+
+func (fp *FlatPackage) IsRoot() bool {
+ return strings.HasPrefix(fp.ID, "//")
+}