xref: /aosp_15_r20/external/bazelbuild-rules_go/go/tools/gopackagesdriver/main.go (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1// Copyright 2021 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package main
16
17import (
18	"context"
19	"encoding/json"
20	"fmt"
21	"go/types"
22	"os"
23	"strings"
24)
25
26type driverResponse struct {
27	// NotHandled is returned if the request can't be handled by the current
28	// driver. If an external driver returns a response with NotHandled, the
29	// rest of the driverResponse is ignored, and go/packages will fallback
30	// to the next driver. If go/packages is extended in the future to support
31	// lists of multiple drivers, go/packages will fall back to the next driver.
32	NotHandled bool
33
34	// Sizes, if not nil, is the types.Sizes to use when type checking.
35	Sizes *types.StdSizes
36
37	// Roots is the set of package IDs that make up the root packages.
38	// We have to encode this separately because when we encode a single package
39	// we cannot know if it is one of the roots as that requires knowledge of the
40	// graph it is part of.
41	Roots []string `json:",omitempty"`
42
43	// Packages is the full set of packages in the graph.
44	// The packages are not connected into a graph.
45	// The Imports if populated will be stubs that only have their ID set.
46	// Imports will be connected and then type and syntax information added in a
47	// later pass (see refine).
48	Packages []*FlatPackage
49}
50
51var (
52	// Injected via x_defs.
53
54	rulesGoRepositoryName string
55	goDefaultAspect       = rulesGoRepositoryName + "//go/tools/gopackagesdriver:aspect.bzl%go_pkg_info_aspect"
56	bazelBin              = getenvDefault("GOPACKAGESDRIVER_BAZEL", "bazel")
57	bazelStartupFlags     = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_FLAGS"))
58	bazelQueryFlags       = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_QUERY_FLAGS"))
59	bazelQueryScope       = getenvDefault("GOPACKAGESDRIVER_BAZEL_QUERY_SCOPE", "")
60	bazelBuildFlags       = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_BUILD_FLAGS"))
61	workspaceRoot         = os.Getenv("BUILD_WORKSPACE_DIRECTORY")
62	additionalAspects     = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_ADDTL_ASPECTS"))
63	additionalKinds       = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_KINDS"))
64	emptyResponse         = &driverResponse{
65		NotHandled: true,
66		Sizes:      types.SizesFor("gc", "amd64").(*types.StdSizes),
67		Roots:      []string{},
68		Packages:   []*FlatPackage{},
69	}
70)
71
72func run() (*driverResponse, error) {
73	ctx, cancel := signalContext(context.Background(), os.Interrupt)
74	defer cancel()
75
76	queries := os.Args[1:]
77
78	request, err := ReadDriverRequest(os.Stdin)
79	if err != nil {
80		return emptyResponse, fmt.Errorf("unable to read request: %w", err)
81	}
82
83	bazel, err := NewBazel(ctx, bazelBin, workspaceRoot, bazelStartupFlags)
84	if err != nil {
85		return emptyResponse, fmt.Errorf("unable to create bazel instance: %w", err)
86	}
87
88	bazelJsonBuilder, err := NewBazelJSONBuilder(bazel, request.Tests)
89	if err != nil {
90		return emptyResponse, fmt.Errorf("unable to build JSON files: %w", err)
91	}
92
93	labels, err := bazelJsonBuilder.Labels(ctx, queries)
94	if err != nil {
95		return emptyResponse, fmt.Errorf("unable to lookup package: %w", err)
96	}
97
98	jsonFiles, err := bazelJsonBuilder.Build(ctx, labels, request.Mode)
99	if err != nil {
100		return emptyResponse, fmt.Errorf("unable to build JSON files: %w", err)
101	}
102
103	driver, err := NewJSONPackagesDriver(jsonFiles, bazelJsonBuilder.PathResolver())
104	if err != nil {
105		return emptyResponse, fmt.Errorf("unable to load JSON files: %w", err)
106	}
107
108	// Note: we are returning all files required to build a specific package.
109	// For file queries (`file=`), this means that the CompiledGoFiles will
110	// include more than the only file being specified.
111	return driver.GetResponse(labels), nil
112}
113
114func main() {
115	response, err := run()
116	if err := json.NewEncoder(os.Stdout).Encode(response); err != nil {
117		fmt.Fprintf(os.Stderr, "unable to encode response: %v", err)
118	}
119	if err != nil {
120		fmt.Fprintf(os.Stderr, "error: %v", err)
121		// gopls will check the packages driver exit code, and if there is an
122		// error, it will fall back to go list. Obviously we don't want that,
123		// so force a 0 exit code.
124		os.Exit(0)
125	}
126}
127