| // 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 program generates file //bazel/devicesrc. |
| |
| //go:generate bazelisk run //bazel/device_specific_configs/generate -- --output-file ${PWD}/../../devicesrc |
| |
| package main |
| |
| import ( |
| "flag" |
| "fmt" |
| "os" |
| "sort" |
| "strings" |
| |
| "go.skia.org/skia/bazel/device_specific_configs" |
| ) |
| |
| const header = "# GENERATED FILE - Please do not edit.\n\n" |
| |
| func writeFlag(sb *strings.Builder, configName, flagName, flagValue string) { |
| _, _ = sb.WriteString(fmt.Sprintf("test:%s %s=%s\n", configName, flagName, flagValue)) |
| } |
| |
| func writeTestArgFlag(sb *strings.Builder, configName, testArgFlag string) { |
| _, _ = sb.WriteString(fmt.Sprintf("test:%s --test_arg=%s\n", configName, testArgFlag)) |
| } |
| |
| func writeDeviceFlagsFile(outputFile string) error { |
| // Sort for determinism. |
| var configNames []string |
| for configName := range device_specific_configs.Configs { |
| configNames = append(configNames, configName) |
| } |
| sort.Strings(configNames) |
| |
| var sb strings.Builder |
| _, _ = sb.WriteString(header) |
| |
| for i, configName := range configNames { |
| if i > 0 { |
| sb.WriteString("\n") |
| } |
| |
| // Force device-specific tests to run locally (as opposed to on RBE). For such tests, we assume |
| // Bazel is running on the device under test, or on a machine that controls the device under |
| // test (e.g. an Android device attached via USB). Compilation still happens on RBE. |
| // |
| // We force local execution via the --strategy flag[1]. In order to understand the --strategy |
| // flag, we must first understand the --spawn_strategy flag[2], which controls where and how |
| // commands are executed. For example: |
| // |
| // - Flag --spawn_strategy=sandboxed executes commands inside a sandbox on the local system. |
| // This is the default Bazel behavior on systems that support sandboxing. |
| // |
| // - Flag --spawn_strategy=local executes commands as regular, local subprocesses without any |
| // sandboxing. |
| // |
| // - Flag --spawn_strategy=remote executes commands remotely, provided a remote executor has |
| // been configured. We use this strategy when running Bazel with --config=remote. See the |
| // //.bazelrc file[3]. |
| // |
| // The --strategy flag allows us to override --spawn_strategy on a per-mnemonic basis. In our |
| // case, we set --strategy=TestRunner=local to force test actions to run as a local subprocess. |
| // In combination with --config=remote (or any configuration that implies it, such as |
| // --config=linux_rbe) this has the effect of running test actions locally, while build actions |
| // (and any other actions) run on RBE. |
| // |
| // The "TestRunner" mnemonic for test actions is determined here[4]. |
| // |
| // [1] https://bazel.build/docs/user-manual#strategy |
| // [2] https://bazel.build/docs/user-manual#spawn-strategy |
| // [3] https://skia.googlesource.com/skia/+/e5c37860c792de6bba0c9465c3f5280cb13dbbb9/.bazelrc#128 |
| // [4] https://github.com/bazelbuild/bazel/blob/f79ca0275e14d7c8fb478bd910ad7fb127440fd8/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java#L107 |
| writeFlag(&sb, configName, "--strategy", "TestRunner=local") |
| |
| config := device_specific_configs.Configs[configName] |
| for _, arg := range config.TestRunnerArgs() { |
| writeTestArgFlag(&sb, configName, arg) |
| } |
| } |
| |
| return os.WriteFile(outputFile, []byte(sb.String()), 0644) |
| } |
| |
| func main() { |
| outputFileFlag := flag.String("output-file", "", "Path to the output file.") |
| flag.Parse() |
| |
| if *outputFileFlag == "" { |
| fmt.Println("Flag --output-file is required.") |
| os.Exit(1) |
| } |
| |
| if err := writeDeviceFlagsFile(*outputFileFlag); err != nil { |
| fmt.Printf("error: %s\n", err) |
| os.Exit(1) |
| } |
| } |