blob: 1f1a345bb562018008699dbd3d29cc5e6cf1ccf0 [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This executable tests the "layering_check" feature of our custom Bazel toolchain. It builds
// a target multiple times with different defines, which turn on a different "invalid" include
// and verifies that they fail.
package main
import (
"context"
"flag"
"fmt"
"path/filepath"
sk_exec "go.skia.org/infra/go/exec"
"go.skia.org/infra/task_driver/go/lib/bazel"
"go.skia.org/infra/task_driver/go/lib/os_steps"
"go.skia.org/infra/task_driver/go/td"
)
var (
// Required properties for this task.
cachePath = flag.String("cache_path", "/mnt/pd0/bazel_cache", "The path where the Bazel cache should live. This should be able to hold tens of GB at least.")
config = flag.String("test_config", "", "A custom configuration specified in //bazel/buildrc. This configuration potentially encapsulates many features and options.")
projectId = flag.String("project_id", "", "ID of the Google Cloud project.")
taskId = flag.String("task_id", "", "ID of this task.")
taskName = flag.String("task_name", "", "Name of the task.")
workdir = flag.String("workdir", ".", "Working directory, the root directory of a full Skia checkout")
// Optional flags.
local = flag.Bool("local", false, "True if running locally (as opposed to on the CI/CQ)")
output = flag.String("o", "", "If provided, dump a JSON blob of step data to the given file. Prints to stdout if '-' is given.")
)
func main() {
// StartRun calls flag.Parse()
ctx := td.StartRun(projectId, taskId, taskName, output, local)
defer td.EndRun(ctx)
wd, err := os_steps.Abs(ctx, *workdir)
if err != nil {
td.Fatal(ctx, err)
}
skiaDir := filepath.Join(wd, "skia")
opts := bazel.BazelOptions{
// We want the cache to be on a bigger disk than default. The root disk, where the home
// directory (and default Bazel cache) lives, is only 15 GB on our GCE VMs.
CachePath: *cachePath,
}
if err := bazel.EnsureBazelRCFile(ctx, opts); err != nil {
td.Fatal(ctx, err)
}
testLib := "//experimental/bazel_test/client:client_lib"
// This build should succeed
if err := bazelBuild(ctx, skiaDir, testLib, *config); err != nil {
td.Fatal(ctx, err)
}
// All of these should fail
definesToIncludeExtraHeaders := []string{
"HEADER_INCLUDES_TRANSITIVE_HEADER",
"HEADER_INCLUDES_PRIVATE_HEADER",
"SOURCE_INCLUDES_TRANSITIVE_HEADER",
"SOURCE_INCLUDES_PRIVATE_HEADER",
}
for _, define := range definesToIncludeExtraHeaders {
if err := expectFailure(ctx, skiaDir, testLib, *config, define); err != nil {
td.Fatal(ctx, err)
}
}
}
// bazelBuild builds the target referenced by the given absolute label passing the provided
// config to Bazel command. Instead of calling Bazel directly, we use
func bazelBuild(ctx context.Context, checkoutDir, label, config string) error {
step := fmt.Sprintf("Build %s", label)
return td.Do(ctx, td.Props(step), func(ctx context.Context) error {
runCmd := &sk_exec.Command{
Name: "bazelisk",
Args: append([]string{"build",
label,
"--config=" + config, // Should be defined in //bazel/buildrc
}),
InheritEnv: true, // Makes sure bazelisk is on PATH
Dir: checkoutDir,
LogStdout: true,
LogStderr: true,
}
_, err := sk_exec.RunCommand(ctx, runCmd)
if err != nil {
return err
}
return nil
})
}
// expectFailure builds the target with the given config and additional define. Note that this
// define affects *all* build commands, whereas setting a copt on the BUILD.bazel impacts that
// cc_library/cc_binary but not dependencies nor dependents (except headers from dependencies).
// It returns an error if the underlying build does *not* fail. We expect setting the define to
// include a file that is not allowed and our Bazel build should enforce that.
func expectFailure(ctx context.Context, checkoutDir, label, config, define string) error {
step := fmt.Sprintf("Expect building %s with %s to fail", label, define)
return td.Do(ctx, td.Props(step), func(ctx context.Context) error {
runCmd := &sk_exec.Command{
Name: "bazelisk",
Args: append([]string{"build",
label,
"--config=" + config, // Should be defined in //bazel/buildrc
"--copt=-D" + define + "=1",
}),
InheritEnv: true, // Makes sure bazelisk is on PATH
Dir: checkoutDir,
LogStdout: true,
LogStderr: true,
}
_, err := sk_exec.RunCommand(ctx, runCmd)
if err == nil {
return fmt.Errorf("Expected a failure but didn't get one.")
}
return nil
})
}