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