aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamy Timmermans <jamy@uber.com>2023-11-09 08:57:25 -0800
committerGitHub <noreply@github.com>2023-11-09 16:57:25 +0000
commitd8bf98b2289d8ab431b5be242c16f4b01019a6a9 (patch)
treee38680b1d81f75f121ebfdc329eab1b27bd4038f
parent5f6203e13d81edd08b0392ab4b67be1d172ed2ff (diff)
downloadbazelbuild-rules_go-d8bf98b2289d8ab431b5be242c16f4b01019a6a9.tar.gz
feat(gopackagesdriver): add base test case for go packages driver (#3743)
* feat(tests): add base test case for go packages driver * fixup! debug log * fixup! build.bazel * tmp debug * typos and returns * testing * fixup! windows fix * fix canonical labels * fixup! rulesgoname * feat(gpd): use bazel version to enable prefixing of packages (backwards compat) * fixup! makecompatible with pre-bazel 6 * fixup! use bowi
-rw-r--r--go/tools/BUILD.bazel1
-rw-r--r--go/tools/bazel_testing/bazel_testing.go12
-rw-r--r--go/tools/gopackagesdriver/BUILD.bazel12
-rw-r--r--go/tools/gopackagesdriver/bazel.go6
-rw-r--r--go/tools/gopackagesdriver/bazel_json_builder.go12
-rw-r--r--go/tools/gopackagesdriver/json_packages_driver.go4
-rw-r--r--go/tools/gopackagesdriver/main.go2
-rw-r--r--go/tools/gopackagesdriver/packageregistry.go26
-rw-r--r--tests/integration/gopackagesdriver/BUILD.bazel13
-rw-r--r--tests/integration/gopackagesdriver/README.rst8
-rw-r--r--tests/integration/gopackagesdriver/gopackagesdriver_test.go126
11 files changed, 214 insertions, 8 deletions
diff --git a/go/tools/BUILD.bazel b/go/tools/BUILD.bazel
index 50b87d74..503171d4 100644
--- a/go/tools/BUILD.bazel
+++ b/go/tools/BUILD.bazel
@@ -8,6 +8,7 @@ filegroup(
"//go/tools/bzltestutil:all_files",
"//go/tools/coverdata:all_files",
"//go/tools/go_bin_runner:all_files",
+ "//go/tools/gopackagesdriver:all_files",
],
visibility = ["//visibility:public"],
)
diff --git a/go/tools/bazel_testing/bazel_testing.go b/go/tools/bazel_testing/bazel_testing.go
index 45431405..36ba1f6c 100644
--- a/go/tools/bazel_testing/bazel_testing.go
+++ b/go/tools/bazel_testing/bazel_testing.go
@@ -206,11 +206,23 @@ func RunBazel(args ...string) error {
// If the command starts but exits with a non-zero status, a *StderrExitError
// will be returned which wraps the original *exec.ExitError.
func BazelOutput(args ...string) ([]byte, error) {
+ return BazelOutputWithInput(nil, args...)
+}
+
+// BazelOutputWithInput invokes a bazel command with a list of arguments and
+// an input stream and returns the content of stdout.
+//
+// If the command starts but exits with a non-zero status, a *StderrExitError
+// will be returned which wraps the original *exec.ExitError.
+func BazelOutputWithInput(stdin io.Reader, args ...string) ([]byte, error) {
cmd := BazelCmd(args...)
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
cmd.Stdout = stdout
cmd.Stderr = stderr
+ if stdin != nil {
+ cmd.Stdin = stdin
+ }
err := cmd.Run()
if eErr, ok := err.(*exec.ExitError); ok {
eErr.Stderr = stderr.Bytes()
diff --git a/go/tools/gopackagesdriver/BUILD.bazel b/go/tools/gopackagesdriver/BUILD.bazel
index 6b6e36c1..86ad484d 100644
--- a/go/tools/gopackagesdriver/BUILD.bazel
+++ b/go/tools/gopackagesdriver/BUILD.bazel
@@ -1,5 +1,4 @@
load("//go:def.bzl", "go_binary", "go_library")
-load(":aspect.bzl", "bazel_supports_canonical_label_literals")
load("//go/private:common.bzl", "RULES_GO_REPO_NAME")
go_library(
@@ -16,7 +15,9 @@ go_library(
"utils.go",
],
importpath = "github.com/bazelbuild/rules_go/go/tools/gopackagesdriver",
- visibility = ["//visibility:private"],
+ visibility = [
+ "//tests/integration/gopackagesdriver:__pkg__",
+ ],
)
go_binary(
@@ -29,3 +30,10 @@ go_binary(
"rulesGoRepositoryName": RULES_GO_REPO_NAME,
},
)
+
+filegroup(
+ name = "all_files",
+ testonly = True,
+ srcs = glob(["**"]),
+ visibility = ["//visibility:public"],
+)
diff --git a/go/tools/gopackagesdriver/bazel.go b/go/tools/gopackagesdriver/bazel.go
index 08da745d..979faa6d 100644
--- a/go/tools/gopackagesdriver/bazel.go
+++ b/go/tools/gopackagesdriver/bazel.go
@@ -38,6 +38,7 @@ type Bazel struct {
workspaceRoot string
bazelStartupFlags []string
info map[string]string
+ version string
}
// Minimal BEP structs to access the build outputs
@@ -55,6 +56,7 @@ func NewBazel(ctx context.Context, bazelBin, workspaceRoot string, bazelStartupF
bazelBin: bazelBin,
workspaceRoot: workspaceRoot,
bazelStartupFlags: bazelStartupFlags,
+ version: "6",
}
if err := b.fillInfo(ctx); err != nil {
return nil, fmt.Errorf("unable to query bazel info: %w", err)
@@ -73,6 +75,10 @@ func (b *Bazel) fillInfo(ctx context.Context) error {
parts := strings.SplitN(strings.TrimSpace(scanner.Text()), ":", 2)
b.info[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
}
+ release := strings.Split(b.info["release"], " ")
+ if len(release) == 2 {
+ b.version = release[1]
+ }
return nil
}
diff --git a/go/tools/gopackagesdriver/bazel_json_builder.go b/go/tools/gopackagesdriver/bazel_json_builder.go
index 32924749..a100fefc 100644
--- a/go/tools/gopackagesdriver/bazel_json_builder.go
+++ b/go/tools/gopackagesdriver/bazel_json_builder.go
@@ -24,6 +24,7 @@ import (
"path"
"path/filepath"
"regexp"
+ "runtime"
"strings"
)
@@ -238,7 +239,7 @@ func (b *BazelJSONBuilder) Build(ctx context.Context, labels []string, mode Load
ret := []string{}
for _, f := range files {
if strings.HasSuffix(f, ".pkg.json") {
- ret = append(ret, f)
+ ret = append(ret, cleanPath(f))
}
}
@@ -253,3 +254,12 @@ func (b *BazelJSONBuilder) PathResolver() PathResolverFunc {
return p
}
}
+
+func cleanPath(p string) string {
+ // On Windows the paths may contain a starting `\`, this would make them not resolve
+ if runtime.GOOS == "windows" && p[0] == '\\' {
+ return p[1:]
+ }
+
+ return p
+}
diff --git a/go/tools/gopackagesdriver/json_packages_driver.go b/go/tools/gopackagesdriver/json_packages_driver.go
index d91f2ed1..00b55b3c 100644
--- a/go/tools/gopackagesdriver/json_packages_driver.go
+++ b/go/tools/gopackagesdriver/json_packages_driver.go
@@ -23,9 +23,9 @@ type JSONPackagesDriver struct {
registry *PackageRegistry
}
-func NewJSONPackagesDriver(jsonFiles []string, prf PathResolverFunc) (*JSONPackagesDriver, error) {
+func NewJSONPackagesDriver(jsonFiles []string, prf PathResolverFunc, bazelVersion string) (*JSONPackagesDriver, error) {
jpd := &JSONPackagesDriver{
- registry: NewPackageRegistry(),
+ registry: NewPackageRegistry(bazelVersion),
}
for _, f := range jsonFiles {
diff --git a/go/tools/gopackagesdriver/main.go b/go/tools/gopackagesdriver/main.go
index 8cc904d3..0213f6f8 100644
--- a/go/tools/gopackagesdriver/main.go
+++ b/go/tools/gopackagesdriver/main.go
@@ -103,7 +103,7 @@ func run() (*driverResponse, error) {
return emptyResponse, fmt.Errorf("unable to build JSON files: %w", err)
}
- driver, err := NewJSONPackagesDriver(jsonFiles, bazelJsonBuilder.PathResolver())
+ driver, err := NewJSONPackagesDriver(jsonFiles, bazelJsonBuilder.PathResolver(), bazel.version)
if err != nil {
return emptyResponse, fmt.Errorf("unable to load JSON files: %w", err)
}
diff --git a/go/tools/gopackagesdriver/packageregistry.go b/go/tools/gopackagesdriver/packageregistry.go
index 92f9eac7..1afad7ce 100644
--- a/go/tools/gopackagesdriver/packageregistry.go
+++ b/go/tools/gopackagesdriver/packageregistry.go
@@ -16,18 +16,21 @@ package main
import (
"fmt"
+ "strconv"
"strings"
)
type PackageRegistry struct {
packagesByID map[string]*FlatPackage
stdlib map[string]string
+ bazelVersion []int
}
-func NewPackageRegistry(pkgs ...*FlatPackage) *PackageRegistry {
+func NewPackageRegistry(bazelVersion string, pkgs ...*FlatPackage) *PackageRegistry {
pr := &PackageRegistry{
packagesByID: map[string]*FlatPackage{},
stdlib: map[string]string{},
+ bazelVersion: parseVersion(bazelVersion),
}
pr.Add(pkgs...)
return pr
@@ -88,7 +91,10 @@ func (pr *PackageRegistry) Match(labels []string) ([]string, []*FlatPackage) {
roots := map[string]struct{}{}
for _, label := range labels {
- if !strings.HasPrefix(label, "@") {
+ // When packagesdriver is ran from rules go, rulesGoRepositoryName will just be @
+ if pr.bazelVersion[0] >= 6 &&
+ !strings.HasPrefix(label, "@") {
+ // Canonical labels is only since Bazel 6.0.0
label = fmt.Sprintf("@%s", label)
}
@@ -119,3 +125,19 @@ func (pr *PackageRegistry) Match(labels []string) ([]string, []*FlatPackage) {
return retRoots, retPkgs
}
+
+func parseVersion(v string) []int {
+ parts := strings.Split(v, ".")
+ version := make([]int, len(parts))
+
+ var err error
+ for i, p := range parts {
+ version[i], err = strconv.Atoi(p)
+ if err != nil {
+ // Failsafe default
+ return []int{6, 0, 0}
+ }
+ }
+
+ return version
+}
diff --git a/tests/integration/gopackagesdriver/BUILD.bazel b/tests/integration/gopackagesdriver/BUILD.bazel
new file mode 100644
index 00000000..088663ed
--- /dev/null
+++ b/tests/integration/gopackagesdriver/BUILD.bazel
@@ -0,0 +1,13 @@
+load("//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "gopackagesdriver_test",
+ size = "enormous",
+ srcs = ["gopackagesdriver_test.go"],
+ rule_files = [
+ "//:all_files",
+ ],
+ deps = [
+ "@io_bazel_rules_go//go/tools/gopackagesdriver:gopackagesdriver_lib",
+ ]
+)
diff --git a/tests/integration/gopackagesdriver/README.rst b/tests/integration/gopackagesdriver/README.rst
new file mode 100644
index 00000000..89d2d9ce
--- /dev/null
+++ b/tests/integration/gopackagesdriver/README.rst
@@ -0,0 +1,8 @@
+Go Packages Driver
+
+gopackagesdriver_test
+--------------------
+Verifies that the output of the go packages driver includes the correct output.
+
+Go x/tools is very sensitive to inaccuracies in the package output, so we should
+validate each added feature against what is expected by x/tools.
diff --git a/tests/integration/gopackagesdriver/gopackagesdriver_test.go b/tests/integration/gopackagesdriver/gopackagesdriver_test.go
new file mode 100644
index 00000000..1d2e0d4a
--- /dev/null
+++ b/tests/integration/gopackagesdriver/gopackagesdriver_test.go
@@ -0,0 +1,126 @@
+package gopackagesdriver_test
+
+import (
+ "encoding/json"
+ "path"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+ gpd "github.com/bazelbuild/rules_go/go/tools/gopackagesdriver"
+)
+
+type response struct {
+ Roots []string `json:",omitempty"`
+ Packages []*gpd.FlatPackage
+}
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "hello",
+ srcs = ["hello.go"],
+ importpath = "example.com/hello",
+ visibility = ["//visibility:public"],
+)
+
+-- hello.go --
+package hello
+
+import "os"
+
+func main() {
+ fmt.Fprintln(os.Stderr, "Hello World!")
+}
+ `,
+ })
+}
+
+const (
+ osPkgID = "@io_bazel_rules_go//stdlib:os"
+)
+
+func TestBaseFileLookup(t *testing.T) {
+ reader := strings.NewReader("{}")
+ out, err := bazel_testing.BazelOutputWithInput(reader, "run", "@io_bazel_rules_go//go/tools/gopackagesdriver", "--", "file=hello.go")
+ if err != nil {
+ t.Errorf("Unexpected error: %w", err.Error())
+ return
+ }
+ var resp response
+ err = json.Unmarshal(out, &resp)
+ if err != nil {
+ t.Errorf("Failed to unmarshal packages driver response: %w\n%w", err.Error(), out)
+ return
+ }
+
+ t.Run("roots", func(t *testing.T) {
+ if len(resp.Roots) != 1 {
+ t.Errorf("Expected 1 package root: %+v", resp.Roots)
+ return
+ }
+
+ if !strings.HasSuffix(resp.Roots[0], "//:hello") {
+ t.Errorf("Unexpected package id: %q", resp.Roots[0])
+ return
+ }
+ })
+
+ t.Run("package", func(t *testing.T) {
+ var pkg *gpd.FlatPackage
+ for _, p := range resp.Packages {
+ if p.ID == resp.Roots[0] {
+ pkg = p
+ }
+ }
+
+ if pkg == nil {
+ t.Errorf("Expected to find %q in resp.Packages", resp.Roots[0])
+ return
+ }
+
+ if len(pkg.CompiledGoFiles) != 1 || len(pkg.GoFiles) != 1 ||
+ path.Base(pkg.GoFiles[0]) != "hello.go" || path.Base(pkg.CompiledGoFiles[0]) != "hello.go" {
+ t.Errorf("Expected to find 1 file (hello.go) in (Compiled)GoFiles:\n%+v", pkg)
+ return
+ }
+
+ if pkg.Standard {
+ t.Errorf("Expected package to not be Standard:\n%+v", pkg)
+ return
+ }
+
+ if len(pkg.Imports) != 1 {
+ t.Errorf("Expected one import:\n%+v", pkg)
+ return
+ }
+
+ if pkg.Imports["os"] != osPkgID {
+ t.Errorf("Expected os import to map to %q:\n%+v", osPkgID, pkg)
+ return
+ }
+ })
+
+ t.Run("dependency", func(t *testing.T) {
+ var osPkg *gpd.FlatPackage
+ for _, p := range resp.Packages {
+ if p.ID == osPkgID {
+ osPkg = p
+ }
+ }
+
+ if osPkg == nil {
+ t.Errorf("Expected os package to be included:\n%+v", osPkg)
+ return
+ }
+
+ if !osPkg.Standard {
+ t.Errorf("Expected os import to be standard:\n%+v", osPkg)
+ return
+ }
+ })
+}