Sorting the Action output files. PiperOrigin-RevId: 161925075
diff --git a/src/main/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunner.java index 95a3404..8b0376a 100644 --- a/src/main/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunner.java +++ b/src/main/java/com/google/devtools/build/lib/remote/CachedLocalSpawnRunner.java
@@ -40,6 +40,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.SortedMap; import java.util.TreeSet; @@ -138,11 +139,13 @@ Action.Builder action = Action.newBuilder(); action.setCommandDigest(command); action.setInputRootDigest(inputRoot); - // Somewhat ugly: we rely on the stable order of outputs here for remote action caching. + ArrayList<String> outputPaths = new ArrayList<>(); for (ActionInput output : outputs) { - // TODO: output directories should be handled here, when they are supported. - action.addOutputFiles(output.getExecPathString()); + outputPaths.add(output.getExecPathString()); } + Collections.sort(outputPaths); + // TODO: output directories should be handled here, when they are supported. + action.addAllOutputFiles(outputPaths); if (platform != null) { action.setPlatform(platform); }
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java index 7ba5e5e..7a50e1c 100644 --- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java +++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
@@ -39,6 +39,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.SortedMap; import java.util.TreeSet; @@ -159,11 +160,13 @@ Action.Builder action = Action.newBuilder(); action.setCommandDigest(command); action.setInputRootDigest(inputRoot); - // Somewhat ugly: we rely on the stable order of outputs here for remote action caching. + ArrayList<String> outputPaths = new ArrayList<>(); for (ActionInput output : outputs) { - // TODO: output directories should be handled here, when they are supported. - action.addOutputFiles(output.getExecPathString()); + outputPaths.add(output.getExecPathString()); } + Collections.sort(outputPaths); + // TODO: output directories should be handled here, when they are supported. + action.addAllOutputFiles(outputPaths); if (platform != null) { action.setPlatform(platform); }
diff --git a/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java b/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java index 8732235..2a39ba9 100644 --- a/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java +++ b/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteExecutionClientTest.java
@@ -167,7 +167,29 @@ ImmutableMap.of("VARIABLE", "value"), /*executionInfo=*/ ImmutableMap.<String, String>of(), /*inputs=*/ ImmutableList.of(ActionInputHelper.fromPath("input")), - /*outputs=*/ ImmutableList.<ActionInput>of(), + /*outputs=*/ ImmutableList.<ActionInput>of( + new ActionInput() { + @Override + public String getExecPathString() { + return "foo"; + } + + @Override + public PathFragment getExecPath() { + return null; // unused here. + } + }, + new ActionInput() { + @Override + public String getExecPathString() { + return "bar"; + } + + @Override + public PathFragment getExecPath() { + return null; // unused here. + } + }), ResourceSet.ZERO); Path stdout = fs.getPath("/tmp/stdout"); @@ -335,6 +357,10 @@ new ExecutionImplBase() { @Override public void execute(ExecuteRequest request, StreamObserver<Operation> responseObserver) { + // Check that the output files are sorted. + assertThat(request.getAction().getOutputFilesList()) + .containsExactly("bar", "foo") + .inOrder(); responseObserver.onNext( Operation.newBuilder() .setDone(true)