Skip to content

Commit

Permalink
Merge pull request #12 from herkolategan/hbl/bazel-runfiles
Browse files Browse the repository at this point in the history
Bazel runfiles
  • Loading branch information
tbg authored Feb 21, 2025
2 parents b760d1f + 2e52c4f commit 18268d9
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 26 deletions.
96 changes: 72 additions & 24 deletions bench.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"hash/fnv"
"os"
"path/filepath"
Expand All @@ -10,6 +11,13 @@ import (
"github.com/pkg/errors"
)

const bazelRunScript = `#!/bin/bash
SCRIPT_PATH="$(realpath "$0")"
BAZEL_DIR="${SCRIPT_PATH}.bazel"
RUNFILES_DIR="${BAZEL_DIR}/%[1]s.runfiles"
"${BAZEL_DIR}/%[1]s" "$@"
`

// expandPackages expands the package filter into all of the packages that it
// references using `go list`.
func expandPackages(pkgFilter []string) ([]string, error) {
Expand Down Expand Up @@ -65,40 +73,80 @@ func testBinToPkg(bin string) string {
return strings.ReplaceAll(bin, "_", "/")
}

// buildTestBin builds a test binary for the specified package and moves it to
// the destination directory if successful.
func buildTestBin(pkg, dst string, useBazel bool) (string, bool, error) {
// buildTestBinWithGo builds a test binary, using Go directly, for the specified
// package and moves it to the destination directory if successful.
func buildTestBinWithGo(pkg, dst string) (string, bool, error) {
dstFile := pkgToTestBin(pkg) // cockroachdb_cockroach_pkg_util_log
var srcFile string
if !useBazel {
srcFile = dstFile
// Capture to silence warnings from pkgs with no test files.
if _, err := capture("go", "test", "-c", "-o", dstFile, pkg); err != nil {
return "", false, errors.Wrap(err, "building test binary")
}
} else {
relPkg := strings.TrimPrefix(pkg, "github.com/cockroachdb/cockroach/")
pathList := strings.Split(relPkg, string(filepath.Separator)) // ['pkg','util','log']
last := pathList[len(pathList)-1] // 'log'
// `bazel build //pkg/util/log:log_test`.
if _, err := capture("bazel", "build", "//"+relPkg+":"+last+"_test"); err != nil {
return "", false, errors.Wrap(err, "building test binary")
}
// `_bazel/bin/pkg/util/log/log_test_/log_test`.
out := append([]string{"_bazel", "bin"}, pathList...)
out = append(out, last+"_test_", last+"_test")
srcFile = filepath.Join(out...)
// Capture to silence warnings from pkgs with no test files.
if _, err := capture("go", "test", "-c", "-o", dstFile, pkg); err != nil {
return "", false, errors.Wrap(err, "building test binary")
}

// If there were no tests in the package, no file will have been created.
if _, err := os.Stat(srcFile); err != nil {
if _, err := os.Stat(dstFile); err != nil {
if os.IsNotExist(err) {
return "", false, nil
}
return "", false, errors.Wrap(err, "looking for test binary")
}
if err := spawn("mv", srcFile, filepath.Join(dst, dstFile)); err != nil {
if err := spawn("mv", dstFile, filepath.Join(dst, dstFile)); err != nil {
return "", false, errors.Wrap(err, "moving test binary")
}
return dstFile, true, nil
}

// buildTestBinWithBazel builds a test binary, using Bazel, for the specified
// package. It creates an executable script inplace of a binary that will invoke
// the test binary with the correct runfiles, stored in a `<dst>.bazel`
// directory alongside it.
func buildTestBinWithBazel(pkg, dst string) (string, bool, error) {
dstBin := pkgToTestBin(pkg) // cockroachdb_cockroach_pkg_util_log
dstBazelDir := filepath.Join(dst, dstBin+".bazel")

relPkg := strings.TrimPrefix(pkg, "github.com/cockroachdb/cockroach/")
pathList := strings.Split(relPkg, string(filepath.Separator)) // ['pkg','util','log']
last := pathList[len(pathList)-1] // 'log'
// `bazel build //pkg/util/log:log_test`.
if _, err := capture("bazel", "build", "//"+relPkg+":"+last+"_test"); err != nil {
return "", false, errors.Wrap(err, "building test binary")
}

// `_bazel/bin/pkg/util/log/log_test_`.
outDir := append([]string{"_bazel", "bin"}, pathList...)
outDir = append(outDir, last+"_test_")

// `_bazel/bin/pkg/util/log/log_test_/log_test`.
srcBin := filepath.Join(filepath.Join(outDir...), last+"_test")
// `_bazel/bin/pkg/util/log/log_test_/log_test.runfiles`.
srcRunfilesDir := filepath.Join(filepath.Join(outDir...), filepath.Base(srcBin)+".runfiles")

// If there were no tests in the package, no test binary file will have been
// created.
if _, err := os.Stat(srcBin); err != nil {
if os.IsNotExist(err) {
return "", false, nil
}
return "", false, errors.Wrap(err, "looking for test binary")
}
if err := os.Mkdir(dstBazelDir, 0755); err != nil {
return "", false, errors.Wrap(err, "creating bazel binary directory")
}
if err := spawn("cp", "-rL", srcBin, srcRunfilesDir, dstBazelDir); err != nil {
return "", false, errors.Wrap(err, "copying binary and bazel runfiles")
}
runScript := fmt.Sprintf(bazelRunScript, filepath.Base(srcBin))
if err := writeExecutableScript(runScript, filepath.Join(dst, dstBin)); err != nil {
return "", false, errors.Wrap(err, "writing bazel binary script")
}
return dstBin, true, nil
}

func writeExecutableScript(script, path string) error {
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(script)
return err
}
11 changes: 9 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,10 @@ func (bs *benchSuite) build(pkgFilter []string, postChck string, t time.Time) (e
}
for _, f := range files {
if f.IsDir() {
return errors.Errorf("unexpected directory %q", f.Name())
if !strings.HasSuffix(f.Name(), ".bazel") {
return errors.Errorf("unexpected directory %q", f.Name())
}
continue
}
bs.testFiles[f.Name()] = struct{}{}
}
Expand Down Expand Up @@ -680,9 +683,13 @@ func (bs *benchSuite) build(pkgFilter []string, postChck string, t time.Time) (e
spinner.Start(os.Stderr, fmt.Sprintf("building benchmark binaries for %s: %.50s [bazel=%t] ", bs.ref,
bs.subject, bs.useBazel))
defer spinner.Stop()
buildTestBin := buildTestBinWithGo
if bs.useBazel {
buildTestBin = buildTestBinWithBazel
}
for i, pkg := range pkgs {
spinner.Update(ui.Fraction(i, len(pkgs)))
if testBin, ok, err := buildTestBin(pkg, bs.binDir, bs.useBazel); err != nil {
if testBin, ok, err := buildTestBin(pkg, bs.binDir); err != nil {
return err
} else if ok {
bs.testFiles[testBin] = struct{}{}
Expand Down

0 comments on commit 18268d9

Please sign in to comment.