Skip to content

Commit 2f0948b

Browse files
tjgqcopybara-github
authored andcommitted
Use the execution platform instead of the host platform to decide whether to do Windows-specific things in a few places.
Note: tests based on BuildViewTestCase never set the execution platform, so after this change they effectively always act as if running on non-Windows. This should be fixed but likely has a large blast radius, so instead I've fixed the test assertions for now. PiperOrigin-RevId: 555424062 Change-Id: Ice82412832ab79452b43e2e6e49015a87460d854
1 parent 2cd583a commit 2f0948b

File tree

13 files changed

+79
-72
lines changed

13 files changed

+79
-72
lines changed

src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package com.google.devtools.build.lib.analysis;
1616

1717
import static com.google.common.collect.ImmutableList.toImmutableList;
18+
import static com.google.devtools.build.lib.analysis.constraints.ConstraintConstants.OS_TO_CONSTRAINTS;
1819
import static com.google.devtools.build.lib.analysis.test.ExecutionInfo.DEFAULT_TEST_RUNNER_EXEC_GROUP;
1920
import static com.google.devtools.build.lib.packages.ExecGroup.DEFAULT_EXEC_GROUP_NAME;
2021

@@ -599,10 +600,8 @@ public Artifact createOutputArtifact(OutputFile out) {
599600
*/
600601
public Artifact createOutputArtifactScript() {
601602
Target target = getTarget();
602-
// TODO(laszlocsomor): Use the execution platform, not the host platform.
603-
boolean isExecutedOnWindows = OS.getCurrent() == OS.WINDOWS;
604603

605-
String fileExtension = isExecutedOnWindows ? ".cmd" : ".sh";
604+
String fileExtension = isExecutedOnWindows() ? ".cmd" : ".sh";
606605

607606
PathFragment rootRelativePath =
608607
getPackageDirectory().getRelative(PathFragment.create(target.getName() + fileExtension));
@@ -1629,6 +1628,13 @@ public boolean isTestOnlyTarget() {
16291628
return attributes().has("testonly", Type.BOOLEAN) && attributes().get("testonly", Type.BOOLEAN);
16301629
}
16311630

1631+
/** Returns true if the execution platform is Windows. */
1632+
public boolean isExecutedOnWindows() {
1633+
return getExecutionPlatform()
1634+
.constraints()
1635+
.hasConstraintValue(OS_TO_CONSTRAINTS.get(OS.WINDOWS));
1636+
}
1637+
16321638
/**
16331639
* Returns true if {@code label} is visible from {@code prerequisite}.
16341640
*

src/main/java/com/google/devtools/build/lib/analysis/actions/LauncherFileWriteAction.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@
1313
// limitations under the License.
1414
package com.google.devtools.build.lib.analysis.actions;
1515

16+
import static com.google.common.base.Preconditions.checkState;
17+
1618
import com.google.common.annotations.VisibleForTesting;
1719
import com.google.common.base.Preconditions;
1820
import com.google.common.collect.ImmutableList;
1921
import com.google.common.io.ByteStreams;
2022
import com.google.devtools.build.lib.actions.ActionExecutionContext;
2123
import com.google.devtools.build.lib.actions.ActionKeyContext;
22-
import com.google.devtools.build.lib.actions.ActionOwner;
2324
import com.google.devtools.build.lib.actions.Artifact;
2425
import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
2526
import com.google.devtools.build.lib.analysis.RuleContext;
2627
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
2728
import com.google.devtools.build.lib.collect.nestedset.Order;
2829
import com.google.devtools.build.lib.util.Fingerprint;
29-
import com.google.devtools.build.lib.util.OS;
3030
import com.google.errorprone.annotations.CanIgnoreReturnValue;
3131
import java.io.IOException;
3232
import java.io.InputStream;
@@ -46,37 +46,35 @@ public final class LauncherFileWriteAction extends AbstractFileWriteAction {
4646

4747
private final LaunchInfo launchInfo;
4848
private final Artifact launcher;
49+
private final boolean isExecutedOnWindows;
4950

5051
/** Creates a new {@link LauncherFileWriteAction}, registering it with the {@code ruleContext}. */
5152
public static void createAndRegister(
5253
RuleContext ruleContext, Artifact output, LaunchInfo launchInfo) {
5354
ruleContext.registerAction(
5455
new LauncherFileWriteAction(
55-
ruleContext.getActionOwner(),
56-
output,
57-
ruleContext.getPrerequisiteArtifact("$launcher"),
58-
launchInfo));
56+
ruleContext, output, ruleContext.getPrerequisiteArtifact("$launcher"), launchInfo));
5957
}
6058

6159
/** Creates a new {@code LauncherFileWriteAction}. */
6260
private LauncherFileWriteAction(
63-
ActionOwner owner, Artifact output, Artifact launcher, LaunchInfo launchInfo) {
61+
RuleContext ruleContext, Artifact output, Artifact launcher, LaunchInfo launchInfo) {
6462
super(
65-
owner,
63+
ruleContext.getActionOwner(),
6664
NestedSetBuilder.create(Order.STABLE_ORDER, Preconditions.checkNotNull(launcher)),
6765
output,
68-
/*makeExecutable=*/ true);
66+
/* makeExecutable= */ true);
6967
this.launcher = launcher; // already null-checked in the superclass c'tor
7068
this.launchInfo = Preconditions.checkNotNull(launchInfo);
69+
this.isExecutedOnWindows = ruleContext.isExecutedOnWindows();
7170
}
7271

7372
@Override
7473
public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) {
75-
// TODO(laszlocsomor): make this code check for the execution platform, not the host platform,
76-
// once Bazel supports distinguishing between the two.
77-
// OS.getCurrent() returns the host platform, not the execution platform, which is fine in a
78-
// single-machine execution environment, but problematic with remote execution.
79-
Preconditions.checkState(OS.getCurrent() == OS.WINDOWS);
74+
// TODO(tjgq): Move this check into createAndRegister.
75+
// This requires fixing many unit tests that don't appropriately set the execution platform
76+
// when running on Windows.
77+
checkState(isExecutedOnWindows);
8078
return out -> {
8179
try (InputStream in = ctx.getInputPath(this.launcher).getInputStream()) {
8280
ByteStreams.copy(in, out);

src/main/java/com/google/devtools/build/lib/analysis/test/AnalysisTestActionBuilder.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.google.common.base.Splitter;
1919
import com.google.devtools.build.lib.analysis.RuleContext;
2020
import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
21-
import com.google.devtools.build.lib.util.OS;
2221

2322
/**
2423
* Helper for writing test actions for analysis test rules. Analysis test rules are restricted to
@@ -37,25 +36,23 @@ private AnalysisTestActionBuilder() {}
3736
*/
3837
public static void writeAnalysisTestAction(
3938
RuleContext ruleContext, AnalysisTestResultInfo testResultInfo) {
40-
// TODO(laszlocsomor): Use the execution platform, not the host platform.
41-
boolean isExecutedOnWindows = OS.getCurrent() == OS.WINDOWS;
4239
String escapedMessage =
43-
isExecutedOnWindows
40+
ruleContext.isExecutedOnWindows()
4441
? testResultInfo.getMessage().replace("%", "%%")
4542
// Prefix each character with \ (double-escaped; once in the string, once in the
4643
// replacement sequence, which allows backslash-escaping literal "$"). "." is put in
4744
// parentheses because ErrorProne is overly vigorous about objecting to "." as an
4845
// always-matching regex (b/201772278).
4946
: testResultInfo.getMessage().replaceAll("(.)", "\\\\$1");
5047
StringBuilder sb = new StringBuilder();
51-
if (isExecutedOnWindows) {
48+
if (ruleContext.isExecutedOnWindows()) {
5249
sb.append("@echo off\n");
5350
}
5451
for (String line : Splitter.on("\n").split(escapedMessage)) {
5552
sb.append("echo ").append(line).append("\n");
5653
}
5754
sb.append("exit ");
58-
if (isExecutedOnWindows) {
55+
if (ruleContext.isExecutedOnWindows()) {
5956
sb.append("/b ");
6057
}
6158
sb.append(testResultInfo.getSuccess() ? "0" : "1");

src/main/java/com/google/devtools/build/lib/analysis/test/TestActionBuilder.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
import com.google.devtools.build.lib.packages.TestTimeout;
5050
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
5151
import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant;
52-
import com.google.devtools.build.lib.util.OS;
5352
import com.google.devtools.build.lib.util.Pair;
5453
import com.google.devtools.build.lib.vfs.PathFragment;
5554
import com.google.errorprone.annotations.CanIgnoreReturnValue;
@@ -224,11 +223,7 @@ private TestParams createTestAction(int shards)
224223
AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
225224
ArtifactRoot root = ruleContext.getTestLogsDirectory();
226225

227-
// TODO(laszlocsomor), TODO(ulfjack): `isExecutedOnWindows` should use the execution platform,
228-
// not the host platform. Once Bazel can tell apart these platforms, fix the right side of this
229-
// initialization.
230-
final boolean isExecutedOnWindows = OS.getCurrent() == OS.WINDOWS;
231-
final boolean isUsingTestWrapperInsteadOfTestSetupScript = isExecutedOnWindows;
226+
final boolean isUsingTestWrapperInsteadOfTestSetupScript = ruleContext.isExecutedOnWindows();
232227

233228
NestedSetBuilder<Artifact> inputsBuilder = NestedSetBuilder.stableOrder();
234229
inputsBuilder.addTransitive(
@@ -468,7 +463,7 @@ private TestParams createTestAction(int shards)
468463
config,
469464
ruleContext.getWorkspaceName(),
470465
(!isUsingTestWrapperInsteadOfTestSetupScript
471-
|| executionSettings.needsShell(isExecutedOnWindows))
466+
|| executionSettings.needsShell(ruleContext.isExecutedOnWindows()))
472467
? ShToolchain.getPathForPlatform(
473468
ruleContext.getConfiguration(), ruleContext.getExecutionPlatform())
474469
: null,
@@ -481,7 +476,8 @@ private TestParams createTestAction(int shards)
481476
MoreObjects.firstNonNull(
482477
Allowlist.fetchPackageSpecificationProviderOrNull(
483478
ruleContext, "external_network"),
484-
EMPTY_PACKAGES_PROVIDER));
479+
EMPTY_PACKAGES_PROVIDER),
480+
ruleContext.isExecutedOnWindows());
485481

486482
testOutputs.addAll(testRunnerAction.getSpawnOutputs());
487483
testOutputs.addAll(testRunnerAction.getOutputs());

src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ public class TestRunnerAction extends AbstractAction
144144
private final int runNumber;
145145
private final String workspaceName;
146146

147+
private final boolean isExecutedOnWindows;
148+
147149
/**
148150
* Cached test result status used to minimize disk accesses. This field is set when test status is
149151
* retrieved from disk or saved to disk. This field is null if it has not been set yet. This field
@@ -211,7 +213,8 @@ private static ImmutableSet<Artifact> nonNullAsSet(Artifact... artifacts) {
211213
boolean splitCoveragePostProcessing,
212214
NestedSetBuilder<Artifact> lcovMergerFilesToRun,
213215
RunfilesSupplier lcovMergerRunfilesSupplier,
214-
PackageSpecificationProvider networkAllowlist) {
216+
PackageSpecificationProvider networkAllowlist,
217+
boolean isExecutedOnWindows) {
215218
super(
216219
owner,
217220
inputs,
@@ -302,6 +305,12 @@ private static ImmutableSet<Artifact> nonNullAsSet(Artifact... artifacts) {
302305
getUndeclaredOutputsDir(),
303306
undeclaredOutputsAnnotationsDir,
304307
baseDir.getRelative("test_attempts"));
308+
309+
this.isExecutedOnWindows = isExecutedOnWindows;
310+
}
311+
312+
public boolean isExecutedOnWindows() {
313+
return isExecutedOnWindows;
305314
}
306315

307316
@Override

src/main/java/com/google/devtools/build/lib/analysis/test/TestStrategy.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import com.google.devtools.build.lib.server.FailureDetails.TestAction;
4444
import com.google.devtools.build.lib.server.FailureDetails.TestAction.Code;
4545
import com.google.devtools.build.lib.util.Fingerprint;
46-
import com.google.devtools.build.lib.util.OS;
4746
import com.google.devtools.build.lib.util.io.OutErr;
4847
import com.google.devtools.build.lib.vfs.Path;
4948
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -211,10 +210,6 @@ public static ImmutableList<String> getArgs(TestRunnerAction testAction)
211210
public static ImmutableList<String> expandedArgsFromAction(TestRunnerAction testAction)
212211
throws CommandLineExpansionException, InterruptedException {
213212
List<String> args = Lists.newArrayList();
214-
// TODO(ulfjack): `executedOnWindows` is incorrect for remote execution, where we need to
215-
// consider the target configuration, not the machine Bazel happens to run on. Change this to
216-
// something like: testAction.getConfiguration().getTargetOS() == OS.WINDOWS
217-
final boolean executedOnWindows = (OS.getCurrent() == OS.WINDOWS);
218213

219214
Artifact testSetup = testAction.getTestSetupScript();
220215
args.add(testSetup.getExecPath().getCallablePathString());
@@ -227,7 +222,7 @@ public static ImmutableList<String> expandedArgsFromAction(TestRunnerAction test
227222

228223
// Insert the command prefix specified by the "--run_under=<command-prefix>" option, if any.
229224
if (execSettings.getRunUnder() != null) {
230-
addRunUnderArgs(testAction, args, executedOnWindows);
225+
addRunUnderArgs(testAction, args);
231226
}
232227

233228
// Execute the test using the alias in the runfiles tree, as mandated by the Test Encyclopedia.
@@ -236,13 +231,12 @@ public static ImmutableList<String> expandedArgsFromAction(TestRunnerAction test
236231
return ImmutableList.copyOf(args);
237232
}
238233

239-
private static void addRunUnderArgs(
240-
TestRunnerAction testAction, List<String> args, boolean executedOnWindows) {
234+
private static void addRunUnderArgs(TestRunnerAction testAction, List<String> args) {
241235
TestTargetExecutionSettings execSettings = testAction.getExecutionSettings();
242236
if (execSettings.getRunUnderExecutable() != null) {
243237
args.add(execSettings.getRunUnderExecutable().getRunfilesPath().getCallablePathString());
244238
} else {
245-
if (execSettings.needsShell(executedOnWindows)) {
239+
if (execSettings.needsShell(testAction.isExecutedOnWindows())) {
246240
// TestActionBuilder constructs TestRunnerAction with a 'null' shell only when none is
247241
// required. Something clearly went wrong.
248242
Preconditions.checkNotNull(testAction.getShExecutableMaybe(), "%s", testAction);

src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
3131
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
3232
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
33-
import com.google.devtools.build.lib.util.OS;
3433
import com.google.devtools.build.lib.vfs.PathFragment;
3534
import javax.annotation.Nullable;
3635

@@ -70,7 +69,7 @@ public ConfiguredTarget create(RuleContext ruleContext)
7069
ruleContext.getConfiguration().legacyExternalRunfiles());
7170

7271
Artifact mainExecutable =
73-
(OS.getCurrent() == OS.WINDOWS) ? launcherForWindows(ruleContext, symlink, src) : symlink;
72+
ruleContext.isExecutedOnWindows() ? launcherForWindows(ruleContext, symlink, src) : symlink;
7473
if (!symlink.equals(mainExecutable)) {
7574
filesToBuildBuilder.add(mainExecutable);
7675
runfilesBuilder.addArtifact(symlink);

src/main/java/com/google/devtools/build/lib/rules/genrule/BUILD

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ java_library(
2323
"//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster",
2424
"//src/main/java/com/google/devtools/build/lib/analysis:config/execution_transition_factory",
2525
"//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
26-
"//src/main/java/com/google/devtools/build/lib/analysis:constraints/constraint_constants",
2726
"//src/main/java/com/google/devtools/build/lib/analysis:file_provider",
2827
"//src/main/java/com/google/devtools/build/lib/analysis:make_variable_supplier",
2928
"//src/main/java/com/google/devtools/build/lib/analysis:rule_definition_environment",
@@ -34,7 +33,6 @@ java_library(
3433
"//src/main/java/com/google/devtools/build/lib/packages",
3534
"//src/main/java/com/google/devtools/build/lib/util",
3635
"//src/main/java/com/google/devtools/build/lib/util:filetype",
37-
"//src/main/java/com/google/devtools/build/lib/util:os",
3836
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
3937
"//third_party:guava",
4038
"//third_party:jsr305",

src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
package com.google.devtools.build.lib.rules.genrule;
1616

1717
import static com.google.common.collect.ImmutableMap.toImmutableMap;
18-
import static com.google.devtools.build.lib.analysis.constraints.ConstraintConstants.OS_TO_CONSTRAINTS;
1918

2019
import com.google.common.collect.ImmutableList;
2120
import com.google.common.collect.ImmutableMap;
@@ -50,7 +49,6 @@
5049
import com.google.devtools.build.lib.packages.TargetUtils;
5150
import com.google.devtools.build.lib.packages.Type;
5251
import com.google.devtools.build.lib.util.FileTypeSet;
53-
import com.google.devtools.build.lib.util.OS;
5452
import com.google.devtools.build.lib.util.OnDemandString;
5553
import com.google.devtools.build.lib.util.Pair;
5654
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -95,10 +93,7 @@ enum CommandType {
9593
private static Pair<CommandType, String> determineCommandTypeAndAttribute(
9694
RuleContext ruleContext) {
9795
AttributeMap attributeMap = ruleContext.attributes();
98-
if (ruleContext
99-
.getExecutionPlatform()
100-
.constraints()
101-
.hasConstraintValue(OS_TO_CONSTRAINTS.get(OS.WINDOWS))) {
96+
if (ruleContext.isExecutedOnWindows()) {
10297
if (attributeMap.isAttributeValueExplicitlySpecified("cmd_ps")) {
10398
return Pair.of(CommandType.WINDOWS_POWERSHELL, "cmd_ps");
10499
}

src/test/java/com/google/devtools/build/lib/bazel/rules/sh/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ java_library(
1919
["*.java"],
2020
),
2121
deps = [
22+
"//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster",
2223
"//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
2324
"//src/test/java/com/google/devtools/build/lib/analysis/util",
25+
"//third_party:guava",
2426
"//third_party:junit4",
2527
"//third_party:truth",
2628
],

src/test/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestConfiguredTargetTest.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,56 @@
1515

1616
import static com.google.common.truth.Truth.assertThat;
1717

18+
import com.google.common.collect.Iterables;
1819
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
20+
import com.google.devtools.build.lib.analysis.test.TestRunnerAction;
1921
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
22+
import org.junit.Before;
2023
import org.junit.Test;
2124
import org.junit.runner.RunWith;
2225
import org.junit.runners.JUnit4;
2326

2427
/** Tests for sh_test configured target. */
2528
@RunWith(JUnit4.class)
2629
public class BazelShTestConfiguredTargetTest extends BuildViewTestCase {
30+
31+
@Before
32+
public void setUp() throws Exception {
33+
scratch.file("BUILD", "sh_test(name = 'test', srcs = ['test.sh'])");
34+
}
35+
2736
@Test
2837
public void testCoverageOutputGenerator() throws Exception {
29-
scratch.file("sh/test/BUILD", "sh_test(name = 'foo_test', srcs = ['foo_test.sh'])");
3038
reporter.removeHandler(failFastHandler);
31-
ConfiguredTarget ct = getConfiguredTarget("//sh/test:foo_test");
39+
ConfiguredTarget ct = getConfiguredTarget("//:test");
3240
assertThat(getRuleContext(ct).getPrerequisite(":lcov_merger")).isNull();
3341
}
3442

3543
@Test
3644
public void testCoverageOutputGeneratorCoverageMode() throws Exception {
3745
useConfiguration("--collect_code_coverage");
38-
scratch.file("sh/test/BUILD", "sh_test(name = 'foo_test', srcs = ['foo_test.sh'])");
3946
reporter.removeHandler(failFastHandler);
40-
ConfiguredTarget ct = getConfiguredTarget("//sh/test:foo_test");
47+
ConfiguredTarget ct = getConfiguredTarget("//:test");
4148
assertThat(getRuleContext(ct).getPrerequisite(":lcov_merger").getLabel().toString())
4249
.isEqualTo("@bazel_tools//tools/test:lcov_merger");
4350
}
51+
52+
@Test
53+
public void testNonWindowsWrapper() throws Exception {
54+
assertThat(getTestRunnerAction("//:test").getArguments().get(0)).endsWith("test-setup.sh");
55+
}
56+
57+
@Test
58+
public void testWindowsWrapper() throws Exception {
59+
scratch.file(
60+
"platforms/BUILD",
61+
"platform(name = 'windows', constraint_values = ['@platforms//os:windows'])");
62+
useConfiguration("--host_platform=//platforms:windows");
63+
64+
assertThat(getTestRunnerAction("//:test").getArguments().get(0)).endsWith("test_wrapper_bin");
65+
}
66+
67+
private TestRunnerAction getTestRunnerAction(String label) throws Exception {
68+
return (TestRunnerAction) Iterables.getOnlyElement(getActions(label, TestRunnerAction.class));
69+
}
4470
}

0 commit comments

Comments
 (0)