diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java index d073b337e25030..c399e4e6435cef 100644 --- a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java +++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java @@ -1142,7 +1142,10 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re || // In case the action failed, download all outputs. It might be helpful for debugging // and there is no point in injecting output metadata of a failed action. - result.getExitCode() != 0; + result.getExitCode() != 0 + || + // Symlinks in actions output are not yet supported with BwoB. + !metadata.symlinks().isEmpty(); // Download into temporary paths, then move everything at the end. // This avoids holding the output lock while downloading, which would prevent the local branch @@ -1162,12 +1165,8 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re checkState( result.getExitCode() == 0, "injecting remote metadata is only supported for successful actions (exit code 0)."); - - if (!metadata.symlinks().isEmpty()) { - throw new IOException( - "Symlinks in action outputs are not yet supported by " - + "--experimental_remote_download_outputs=minimal"); - } + checkState(metadata.symlinks.isEmpty(), "Symlinks in action outputs are not yet supported by" + + " --experimental_remote_download_outputs=minimal"); } FileOutErr tmpOutErr = outErr.childOutErr(); diff --git a/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java index 1922c99c9a674d..d35ad7da61872c 100644 --- a/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java +++ b/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java @@ -32,6 +32,7 @@ import com.google.devtools.build.lib.util.OS; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.Symlinks; import java.io.IOException; import org.junit.After; import org.junit.Test; @@ -433,6 +434,36 @@ public void symlinkToNestedDirectory() throws Exception { buildTarget("//a:one_local", "//a:two_local", "//a:one_remote", "//a:two_remote"); } + @Test + public void outputSymlinkHandledGracefully() throws Exception { + write( + "a/defs.bzl", + "def _impl(ctx):", + " out = ctx.actions.declare_symlink(ctx.label.name)", + " ctx.actions.run_shell(", + " inputs = [],", + " outputs = [out],", + " command = 'ln -s hello $1',", + " arguments = [out.path],", + " )", + " return DefaultInfo(files = depset([out]))", + "", + "my_rule = rule(", + " implementation = _impl,", + ")"); + + write( + "a/BUILD", + "load(':defs.bzl', 'my_rule')", + "", + "my_rule(name = 'hello')"); + + buildTarget("//a:hello"); + + Path outputPath = getOutputPath("a/hello"); + assertThat(outputPath.stat(Symlinks.NOFOLLOW).isSymbolicLink()).isTrue(); + } + @Test public void replaceOutputDirectoryWithFile() throws Exception { write(