diff --git a/src/main/java/com/google/devtools/build/lib/remote/options/RemoteOptions.java b/src/main/java/com/google/devtools/build/lib/remote/options/RemoteOptions.java index 1f7ff97d5186d6..e62571f75cb33c 100644 --- a/src/main/java/com/google/devtools/build/lib/remote/options/RemoteOptions.java +++ b/src/main/java/com/google/devtools/build/lib/remote/options/RemoteOptions.java @@ -407,9 +407,8 @@ public RemoteBuildEventUploadModeConverter() { effectTags = {OptionEffectTag.EXECUTION}, metadataTags = {OptionMetadataTag.INCOMPATIBLE_CHANGE}, help = - "If set to true, Bazel will represent symlinks in action outputs in the remote" - + " caching/execution protocol as such. Otherwise, symlinks will be followed and" - + " represented as files or directories. See #6631 for details.") + "If set to true, Bazel will upload symlinks as such to a remote or disk cache. Otherwise," + + " non-dangling symlinks will be uploaded as the file or directory they point to.") public boolean incompatibleRemoteSymlinks; @Option( @@ -419,9 +418,7 @@ public RemoteBuildEventUploadModeConverter() { documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY, effectTags = {OptionEffectTag.EXECUTION}, metadataTags = {OptionMetadataTag.INCOMPATIBLE_CHANGE}, - help = - "If set to true and --incompatible_remote_symlinks is also true, symlinks in action" - + " outputs are allowed to dangle.") + help = "If set to true, symlinks uploaded to a remote or disk cache are allowed to dangle.") public boolean incompatibleRemoteDanglingSymlinks; @Option( diff --git a/src/test/java/com/google/devtools/build/lib/remote/UploadManifestTest.java b/src/test/java/com/google/devtools/build/lib/remote/UploadManifestTest.java index c0b93f2a4d002c..8443870e598b27 100644 --- a/src/test/java/com/google/devtools/build/lib/remote/UploadManifestTest.java +++ b/src/test/java/com/google/devtools/build/lib/remote/UploadManifestTest.java @@ -440,6 +440,53 @@ public void actionResult_noFollowSymlinks_relativeDirectorySymlinkAsSymlink() th assertThat(result.build()).isEqualTo(expectedResult.build()); } + @Test + public void actionResult_followSymlinks_absoluteDanglingSymlinkAsSymlink() throws Exception { + ActionResult.Builder result = ActionResult.newBuilder(); + Path link = execRoot.getRelative("link"); + Path target = execRoot.getRelative("target"); + link.createSymbolicLink(target); + + UploadManifest um = + new UploadManifest( + digestUtil, + remotePathResolver, + result, + /* followSymlinks= */ true, + /* allowDanglingSymlinks= */ true, + /* allowAbsoluteSymlinks= */ true); + um.addFiles(ImmutableList.of(link)); + assertThat(um.getDigestToFile()).isEmpty(); + + ActionResult.Builder expectedResult = ActionResult.newBuilder(); + expectedResult.addOutputFileSymlinksBuilder().setPath("link").setTarget("/execroot/target"); + expectedResult.addOutputSymlinksBuilder().setPath("link").setTarget("/execroot/target"); + assertThat(result.build()).isEqualTo(expectedResult.build()); + } + + @Test + public void actionResult_followSymlinks_relativeDanglingSymlinkAsSymlink() throws Exception { + ActionResult.Builder result = ActionResult.newBuilder(); + Path link = execRoot.getRelative("link"); + link.createSymbolicLink(PathFragment.create("target")); + + UploadManifest um = + new UploadManifest( + digestUtil, + remotePathResolver, + result, + /* followSymlinks= */ true, + /* allowDanglingSymlinks= */ true, + /* allowAbsoluteSymlinks= */ false); + um.addFiles(ImmutableList.of(link)); + assertThat(um.getDigestToFile()).isEmpty(); + + ActionResult.Builder expectedResult = ActionResult.newBuilder(); + expectedResult.addOutputFileSymlinksBuilder().setPath("link").setTarget("target"); + expectedResult.addOutputSymlinksBuilder().setPath("link").setTarget("target"); + assertThat(result.build()).isEqualTo(expectedResult.build()); + } + @Test public void actionResult_noFollowSymlinks_noAllowDanglingSymlinks_absoluteDanglingSymlinkError() throws Exception { @@ -903,6 +950,55 @@ public void actionResult_noFollowSymlinks_relativeDirectorySymlinkInDirectoryAsS assertThat(result.build()).isEqualTo(expectedResult.build()); } + @Test + public void + actionResult_followSymlinks_allowDanglingSymlinks_absoluteDanglingSymlinkInDirectoryError() + throws Exception { + ActionResult.Builder result = ActionResult.newBuilder(); + Path dir = execRoot.getRelative("dir"); + dir.createDirectory(); + Path link = dir.getRelative("link"); + Path target = dir.getRelative("target"); + link.createSymbolicLink(target); + + UploadManifest um = + new UploadManifest( + digestUtil, + remotePathResolver, + result, + /* followSymlinks= */ true, + /* allowDanglingSymlinks= */ true, + /* allowAbsoluteSymlinks= */ true); + IOException e = assertThrows(IOException.class, () -> um.addFiles(ImmutableList.of(dir))); + assertThat(e).hasMessageThat().contains("dangling"); + assertThat(e).hasMessageThat().contains("/execroot/dir/link"); + assertThat(e).hasMessageThat().contains("/execroot/dir/target"); + } + + @Test + public void + actionResult_followSymlinks_allowDanglingSymlinks_relativeDanglingSymlinkInDirectoryError() + throws Exception { + ActionResult.Builder result = ActionResult.newBuilder(); + Path dir = execRoot.getRelative("dir"); + dir.createDirectory(); + Path link = dir.getRelative("link"); + link.createSymbolicLink(PathFragment.create("target")); + + UploadManifest um = + new UploadManifest( + digestUtil, + remotePathResolver, + result, + /* followSymlinks= */ true, + /* allowDanglingSymlinks= */ true, + /* allowAbsoluteSymlinks= */ false); + IOException e = assertThrows(IOException.class, () -> um.addFiles(ImmutableList.of(dir))); + assertThat(e).hasMessageThat().contains("dangling"); + assertThat(e).hasMessageThat().contains("/execroot/dir/link"); + assertThat(e).hasMessageThat().contains("target"); + } + @Test public void actionResult_noFollowSymlinks_noAllowDanglingSymlinks_absoluteDanglingSymlinkInDirectory()