xref: /aosp_15_r20/external/bazelbuild-rules_go/go/tools/gopackagesdriver/flatpackage.go (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das// Copyright 2021 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das//
3*9bb1b549SSpandan Das// Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das// you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das// You may obtain a copy of the License at
6*9bb1b549SSpandan Das//
7*9bb1b549SSpandan Das//    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das//
9*9bb1b549SSpandan Das// Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das// distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das// See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das// limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Daspackage main
16*9bb1b549SSpandan Das
17*9bb1b549SSpandan Dasimport (
18*9bb1b549SSpandan Das	"encoding/json"
19*9bb1b549SSpandan Das	"fmt"
20*9bb1b549SSpandan Das	"go/parser"
21*9bb1b549SSpandan Das	"go/token"
22*9bb1b549SSpandan Das	"os"
23*9bb1b549SSpandan Das	"strconv"
24*9bb1b549SSpandan Das	"strings"
25*9bb1b549SSpandan Das)
26*9bb1b549SSpandan Das
27*9bb1b549SSpandan Dastype ResolvePkgFunc func(importPath string) string
28*9bb1b549SSpandan Das
29*9bb1b549SSpandan Das// Copy and pasted from golang.org/x/tools/go/packages
30*9bb1b549SSpandan Dastype FlatPackagesError struct {
31*9bb1b549SSpandan Das	Pos  string // "file:line:col" or "file:line" or "" or "-"
32*9bb1b549SSpandan Das	Msg  string
33*9bb1b549SSpandan Das	Kind FlatPackagesErrorKind
34*9bb1b549SSpandan Das}
35*9bb1b549SSpandan Das
36*9bb1b549SSpandan Dastype FlatPackagesErrorKind int
37*9bb1b549SSpandan Das
38*9bb1b549SSpandan Dasconst (
39*9bb1b549SSpandan Das	UnknownError FlatPackagesErrorKind = iota
40*9bb1b549SSpandan Das	ListError
41*9bb1b549SSpandan Das	ParseError
42*9bb1b549SSpandan Das	TypeError
43*9bb1b549SSpandan Das)
44*9bb1b549SSpandan Das
45*9bb1b549SSpandan Dasfunc (err FlatPackagesError) Error() string {
46*9bb1b549SSpandan Das	pos := err.Pos
47*9bb1b549SSpandan Das	if pos == "" {
48*9bb1b549SSpandan Das		pos = "-" // like token.Position{}.String()
49*9bb1b549SSpandan Das	}
50*9bb1b549SSpandan Das	return pos + ": " + err.Msg
51*9bb1b549SSpandan Das}
52*9bb1b549SSpandan Das
53*9bb1b549SSpandan Das// FlatPackage is the JSON form of Package
54*9bb1b549SSpandan Das// It drops all the type and syntax fields, and transforms the Imports
55*9bb1b549SSpandan Dastype FlatPackage struct {
56*9bb1b549SSpandan Das	ID              string
57*9bb1b549SSpandan Das	Name            string              `json:",omitempty"`
58*9bb1b549SSpandan Das	PkgPath         string              `json:",omitempty"`
59*9bb1b549SSpandan Das	Errors          []FlatPackagesError `json:",omitempty"`
60*9bb1b549SSpandan Das	GoFiles         []string            `json:",omitempty"`
61*9bb1b549SSpandan Das	CompiledGoFiles []string            `json:",omitempty"`
62*9bb1b549SSpandan Das	OtherFiles      []string            `json:",omitempty"`
63*9bb1b549SSpandan Das	ExportFile      string              `json:",omitempty"`
64*9bb1b549SSpandan Das	Imports         map[string]string   `json:",omitempty"`
65*9bb1b549SSpandan Das	Standard        bool                `json:",omitempty"`
66*9bb1b549SSpandan Das}
67*9bb1b549SSpandan Das
68*9bb1b549SSpandan Dastype (
69*9bb1b549SSpandan Das	PackageFunc      func(pkg *FlatPackage)
70*9bb1b549SSpandan Das	PathResolverFunc func(path string) string
71*9bb1b549SSpandan Das)
72*9bb1b549SSpandan Das
73*9bb1b549SSpandan Dasfunc resolvePathsInPlace(prf PathResolverFunc, paths []string) {
74*9bb1b549SSpandan Das	for i, path := range paths {
75*9bb1b549SSpandan Das		paths[i] = prf(path)
76*9bb1b549SSpandan Das	}
77*9bb1b549SSpandan Das}
78*9bb1b549SSpandan Das
79*9bb1b549SSpandan Dasfunc WalkFlatPackagesFromJSON(jsonFile string, onPkg PackageFunc) error {
80*9bb1b549SSpandan Das	f, err := os.Open(jsonFile)
81*9bb1b549SSpandan Das	if err != nil {
82*9bb1b549SSpandan Das		return fmt.Errorf("unable to open package JSON file: %w", err)
83*9bb1b549SSpandan Das	}
84*9bb1b549SSpandan Das	defer f.Close()
85*9bb1b549SSpandan Das
86*9bb1b549SSpandan Das	decoder := json.NewDecoder(f)
87*9bb1b549SSpandan Das	for decoder.More() {
88*9bb1b549SSpandan Das		pkg := &FlatPackage{}
89*9bb1b549SSpandan Das		if err := decoder.Decode(&pkg); err != nil {
90*9bb1b549SSpandan Das			return fmt.Errorf("unable to decode package in %s: %w", f.Name(), err)
91*9bb1b549SSpandan Das		}
92*9bb1b549SSpandan Das
93*9bb1b549SSpandan Das		onPkg(pkg)
94*9bb1b549SSpandan Das	}
95*9bb1b549SSpandan Das	return nil
96*9bb1b549SSpandan Das}
97*9bb1b549SSpandan Das
98*9bb1b549SSpandan Dasfunc (fp *FlatPackage) ResolvePaths(prf PathResolverFunc) error {
99*9bb1b549SSpandan Das	resolvePathsInPlace(prf, fp.CompiledGoFiles)
100*9bb1b549SSpandan Das	resolvePathsInPlace(prf, fp.GoFiles)
101*9bb1b549SSpandan Das	resolvePathsInPlace(prf, fp.OtherFiles)
102*9bb1b549SSpandan Das	fp.ExportFile = prf(fp.ExportFile)
103*9bb1b549SSpandan Das	return nil
104*9bb1b549SSpandan Das}
105*9bb1b549SSpandan Das
106*9bb1b549SSpandan Das// FilterFilesForBuildTags filters the source files given the current build
107*9bb1b549SSpandan Das// tags.
108*9bb1b549SSpandan Dasfunc (fp *FlatPackage) FilterFilesForBuildTags() {
109*9bb1b549SSpandan Das	fp.GoFiles = filterSourceFilesForTags(fp.GoFiles)
110*9bb1b549SSpandan Das	fp.CompiledGoFiles = filterSourceFilesForTags(fp.CompiledGoFiles)
111*9bb1b549SSpandan Das}
112*9bb1b549SSpandan Das
113*9bb1b549SSpandan Dasfunc (fp *FlatPackage) IsStdlib() bool {
114*9bb1b549SSpandan Das	return fp.Standard
115*9bb1b549SSpandan Das}
116*9bb1b549SSpandan Das
117*9bb1b549SSpandan Dasfunc (fp *FlatPackage) ResolveImports(resolve ResolvePkgFunc) error {
118*9bb1b549SSpandan Das	// Stdlib packages are already complete import wise
119*9bb1b549SSpandan Das	if fp.IsStdlib() {
120*9bb1b549SSpandan Das		return nil
121*9bb1b549SSpandan Das	}
122*9bb1b549SSpandan Das
123*9bb1b549SSpandan Das	fset := token.NewFileSet()
124*9bb1b549SSpandan Das
125*9bb1b549SSpandan Das	for _, file := range fp.CompiledGoFiles {
126*9bb1b549SSpandan Das		f, err := parser.ParseFile(fset, file, nil, parser.ImportsOnly)
127*9bb1b549SSpandan Das		if err != nil {
128*9bb1b549SSpandan Das			return err
129*9bb1b549SSpandan Das		}
130*9bb1b549SSpandan Das		// If the name is not provided, fetch it from the sources
131*9bb1b549SSpandan Das		if fp.Name == "" {
132*9bb1b549SSpandan Das			fp.Name = f.Name.Name
133*9bb1b549SSpandan Das		}
134*9bb1b549SSpandan Das
135*9bb1b549SSpandan Das		for _, rawImport := range f.Imports {
136*9bb1b549SSpandan Das			imp, err := strconv.Unquote(rawImport.Path.Value)
137*9bb1b549SSpandan Das			if err != nil {
138*9bb1b549SSpandan Das				continue
139*9bb1b549SSpandan Das			}
140*9bb1b549SSpandan Das			// We don't handle CGo for now
141*9bb1b549SSpandan Das			if imp == "C" {
142*9bb1b549SSpandan Das				continue
143*9bb1b549SSpandan Das			}
144*9bb1b549SSpandan Das			if _, ok := fp.Imports[imp]; ok {
145*9bb1b549SSpandan Das				continue
146*9bb1b549SSpandan Das			}
147*9bb1b549SSpandan Das
148*9bb1b549SSpandan Das			if pkgID := resolve(imp); pkgID != "" {
149*9bb1b549SSpandan Das				fp.Imports[imp] = pkgID
150*9bb1b549SSpandan Das			}
151*9bb1b549SSpandan Das		}
152*9bb1b549SSpandan Das	}
153*9bb1b549SSpandan Das
154*9bb1b549SSpandan Das	return nil
155*9bb1b549SSpandan Das}
156*9bb1b549SSpandan Das
157*9bb1b549SSpandan Dasfunc (fp *FlatPackage) IsRoot() bool {
158*9bb1b549SSpandan Das	return strings.HasPrefix(fp.ID, "//")
159*9bb1b549SSpandan Das}
160