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 "context" 19*9bb1b549SSpandan Das "encoding/json" 20*9bb1b549SSpandan Das "fmt" 21*9bb1b549SSpandan Das "go/types" 22*9bb1b549SSpandan Das "os" 23*9bb1b549SSpandan Das "strings" 24*9bb1b549SSpandan Das) 25*9bb1b549SSpandan Das 26*9bb1b549SSpandan Dastype driverResponse struct { 27*9bb1b549SSpandan Das // NotHandled is returned if the request can't be handled by the current 28*9bb1b549SSpandan Das // driver. If an external driver returns a response with NotHandled, the 29*9bb1b549SSpandan Das // rest of the driverResponse is ignored, and go/packages will fallback 30*9bb1b549SSpandan Das // to the next driver. If go/packages is extended in the future to support 31*9bb1b549SSpandan Das // lists of multiple drivers, go/packages will fall back to the next driver. 32*9bb1b549SSpandan Das NotHandled bool 33*9bb1b549SSpandan Das 34*9bb1b549SSpandan Das // Sizes, if not nil, is the types.Sizes to use when type checking. 35*9bb1b549SSpandan Das Sizes *types.StdSizes 36*9bb1b549SSpandan Das 37*9bb1b549SSpandan Das // Roots is the set of package IDs that make up the root packages. 38*9bb1b549SSpandan Das // We have to encode this separately because when we encode a single package 39*9bb1b549SSpandan Das // we cannot know if it is one of the roots as that requires knowledge of the 40*9bb1b549SSpandan Das // graph it is part of. 41*9bb1b549SSpandan Das Roots []string `json:",omitempty"` 42*9bb1b549SSpandan Das 43*9bb1b549SSpandan Das // Packages is the full set of packages in the graph. 44*9bb1b549SSpandan Das // The packages are not connected into a graph. 45*9bb1b549SSpandan Das // The Imports if populated will be stubs that only have their ID set. 46*9bb1b549SSpandan Das // Imports will be connected and then type and syntax information added in a 47*9bb1b549SSpandan Das // later pass (see refine). 48*9bb1b549SSpandan Das Packages []*FlatPackage 49*9bb1b549SSpandan Das} 50*9bb1b549SSpandan Das 51*9bb1b549SSpandan Dasvar ( 52*9bb1b549SSpandan Das // Injected via x_defs. 53*9bb1b549SSpandan Das 54*9bb1b549SSpandan Das rulesGoRepositoryName string 55*9bb1b549SSpandan Das goDefaultAspect = rulesGoRepositoryName + "//go/tools/gopackagesdriver:aspect.bzl%go_pkg_info_aspect" 56*9bb1b549SSpandan Das bazelBin = getenvDefault("GOPACKAGESDRIVER_BAZEL", "bazel") 57*9bb1b549SSpandan Das bazelStartupFlags = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_FLAGS")) 58*9bb1b549SSpandan Das bazelQueryFlags = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_QUERY_FLAGS")) 59*9bb1b549SSpandan Das bazelQueryScope = getenvDefault("GOPACKAGESDRIVER_BAZEL_QUERY_SCOPE", "") 60*9bb1b549SSpandan Das bazelBuildFlags = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_BUILD_FLAGS")) 61*9bb1b549SSpandan Das workspaceRoot = os.Getenv("BUILD_WORKSPACE_DIRECTORY") 62*9bb1b549SSpandan Das additionalAspects = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_ADDTL_ASPECTS")) 63*9bb1b549SSpandan Das additionalKinds = strings.Fields(os.Getenv("GOPACKAGESDRIVER_BAZEL_KINDS")) 64*9bb1b549SSpandan Das emptyResponse = &driverResponse{ 65*9bb1b549SSpandan Das NotHandled: true, 66*9bb1b549SSpandan Das Sizes: types.SizesFor("gc", "amd64").(*types.StdSizes), 67*9bb1b549SSpandan Das Roots: []string{}, 68*9bb1b549SSpandan Das Packages: []*FlatPackage{}, 69*9bb1b549SSpandan Das } 70*9bb1b549SSpandan Das) 71*9bb1b549SSpandan Das 72*9bb1b549SSpandan Dasfunc run() (*driverResponse, error) { 73*9bb1b549SSpandan Das ctx, cancel := signalContext(context.Background(), os.Interrupt) 74*9bb1b549SSpandan Das defer cancel() 75*9bb1b549SSpandan Das 76*9bb1b549SSpandan Das queries := os.Args[1:] 77*9bb1b549SSpandan Das 78*9bb1b549SSpandan Das request, err := ReadDriverRequest(os.Stdin) 79*9bb1b549SSpandan Das if err != nil { 80*9bb1b549SSpandan Das return emptyResponse, fmt.Errorf("unable to read request: %w", err) 81*9bb1b549SSpandan Das } 82*9bb1b549SSpandan Das 83*9bb1b549SSpandan Das bazel, err := NewBazel(ctx, bazelBin, workspaceRoot, bazelStartupFlags) 84*9bb1b549SSpandan Das if err != nil { 85*9bb1b549SSpandan Das return emptyResponse, fmt.Errorf("unable to create bazel instance: %w", err) 86*9bb1b549SSpandan Das } 87*9bb1b549SSpandan Das 88*9bb1b549SSpandan Das bazelJsonBuilder, err := NewBazelJSONBuilder(bazel, request.Tests) 89*9bb1b549SSpandan Das if err != nil { 90*9bb1b549SSpandan Das return emptyResponse, fmt.Errorf("unable to build JSON files: %w", err) 91*9bb1b549SSpandan Das } 92*9bb1b549SSpandan Das 93*9bb1b549SSpandan Das labels, err := bazelJsonBuilder.Labels(ctx, queries) 94*9bb1b549SSpandan Das if err != nil { 95*9bb1b549SSpandan Das return emptyResponse, fmt.Errorf("unable to lookup package: %w", err) 96*9bb1b549SSpandan Das } 97*9bb1b549SSpandan Das 98*9bb1b549SSpandan Das jsonFiles, err := bazelJsonBuilder.Build(ctx, labels, request.Mode) 99*9bb1b549SSpandan Das if err != nil { 100*9bb1b549SSpandan Das return emptyResponse, fmt.Errorf("unable to build JSON files: %w", err) 101*9bb1b549SSpandan Das } 102*9bb1b549SSpandan Das 103*9bb1b549SSpandan Das driver, err := NewJSONPackagesDriver(jsonFiles, bazelJsonBuilder.PathResolver()) 104*9bb1b549SSpandan Das if err != nil { 105*9bb1b549SSpandan Das return emptyResponse, fmt.Errorf("unable to load JSON files: %w", err) 106*9bb1b549SSpandan Das } 107*9bb1b549SSpandan Das 108*9bb1b549SSpandan Das // Note: we are returning all files required to build a specific package. 109*9bb1b549SSpandan Das // For file queries (`file=`), this means that the CompiledGoFiles will 110*9bb1b549SSpandan Das // include more than the only file being specified. 111*9bb1b549SSpandan Das return driver.GetResponse(labels), nil 112*9bb1b549SSpandan Das} 113*9bb1b549SSpandan Das 114*9bb1b549SSpandan Dasfunc main() { 115*9bb1b549SSpandan Das response, err := run() 116*9bb1b549SSpandan Das if err := json.NewEncoder(os.Stdout).Encode(response); err != nil { 117*9bb1b549SSpandan Das fmt.Fprintf(os.Stderr, "unable to encode response: %v", err) 118*9bb1b549SSpandan Das } 119*9bb1b549SSpandan Das if err != nil { 120*9bb1b549SSpandan Das fmt.Fprintf(os.Stderr, "error: %v", err) 121*9bb1b549SSpandan Das // gopls will check the packages driver exit code, and if there is an 122*9bb1b549SSpandan Das // error, it will fall back to go list. Obviously we don't want that, 123*9bb1b549SSpandan Das // so force a 0 exit code. 124*9bb1b549SSpandan Das os.Exit(0) 125*9bb1b549SSpandan Das } 126*9bb1b549SSpandan Das} 127