1// Copyright 2022 Google LLC 2// 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5 6// This program generates file //bazel/devicesrc. 7 8//go:generate bazelisk run //bazel/device_specific_configs/generate -- --output-file ${PWD}/../../devicesrc 9 10package main 11 12import ( 13 "flag" 14 "fmt" 15 "os" 16 "sort" 17 "strings" 18 19 "go.skia.org/skia/bazel/device_specific_configs" 20) 21 22const header = "# GENERATED FILE - Please do not edit.\n\n" 23 24func writeFlag(sb *strings.Builder, configName, flagName, flagValue string) { 25 _, _ = sb.WriteString(fmt.Sprintf("test:%s %s=%s\n", configName, flagName, flagValue)) 26} 27 28func writeTestArgFlag(sb *strings.Builder, configName, testArgFlag string) { 29 _, _ = sb.WriteString(fmt.Sprintf("test:%s --test_arg=%s\n", configName, testArgFlag)) 30} 31 32func writeDeviceFlagsFile(outputFile string) error { 33 // Sort for determinism. 34 var configNames []string 35 for configName := range device_specific_configs.Configs { 36 configNames = append(configNames, configName) 37 } 38 sort.Strings(configNames) 39 40 var sb strings.Builder 41 _, _ = sb.WriteString(header) 42 43 for i, configName := range configNames { 44 if i > 0 { 45 sb.WriteString("\n") 46 } 47 48 // Force device-specific tests to run locally (as opposed to on RBE). For such tests, we assume 49 // Bazel is running on the device under test, or on a machine that controls the device under 50 // test (e.g. an Android device attached via USB). Compilation still happens on RBE. 51 // 52 // We force local execution via the --strategy flag[1]. In order to understand the --strategy 53 // flag, we must first understand the --spawn_strategy flag[2], which controls where and how 54 // commands are executed. For example: 55 // 56 // - Flag --spawn_strategy=sandboxed executes commands inside a sandbox on the local system. 57 // This is the default Bazel behavior on systems that support sandboxing. 58 // 59 // - Flag --spawn_strategy=local executes commands as regular, local subprocesses without any 60 // sandboxing. 61 // 62 // - Flag --spawn_strategy=remote executes commands remotely, provided a remote executor has 63 // been configured. We use this strategy when running Bazel with --config=remote. See the 64 // //.bazelrc file[3]. 65 // 66 // The --strategy flag allows us to override --spawn_strategy on a per-mnemonic basis. In our 67 // case, we set --strategy=TestRunner=local to force test actions to run as a local subprocess. 68 // In combination with --config=remote (or any configuration that implies it, such as 69 // --config=linux_rbe) this has the effect of running test actions locally, while build actions 70 // (and any other actions) run on RBE. 71 // 72 // The "TestRunner" mnemonic for test actions is determined here[4]. 73 // 74 // [1] https://bazel.build/docs/user-manual#strategy 75 // [2] https://bazel.build/docs/user-manual#spawn-strategy 76 // [3] https://skia.googlesource.com/skia/+/e5c37860c792de6bba0c9465c3f5280cb13dbbb9/.bazelrc#128 77 // [4] https://github.com/bazelbuild/bazel/blob/f79ca0275e14d7c8fb478bd910ad7fb127440fd8/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java#L107 78 writeFlag(&sb, configName, "--strategy", "TestRunner=local") 79 80 config := device_specific_configs.Configs[configName] 81 for _, arg := range config.TestRunnerArgs() { 82 writeTestArgFlag(&sb, configName, arg) 83 } 84 } 85 86 return os.WriteFile(outputFile, []byte(sb.String()), 0644) 87} 88 89func main() { 90 outputFileFlag := flag.String("output-file", "", "Path to the output file.") 91 flag.Parse() 92 93 if *outputFileFlag == "" { 94 fmt.Println("Flag --output-file is required.") 95 os.Exit(1) 96 } 97 98 if err := writeDeviceFlagsFile(*outputFileFlag); err != nil { 99 fmt.Printf("error: %s\n", err) 100 os.Exit(1) 101 } 102} 103