Skip to content

Commit 8ba48ad

Browse files
ulfjackcopybara-github
authored andcommitted
Java coverage: fix handling of external files
When java_test rules are run with coverage, then Bazel writes a file containing the runtime classpath using root-relative paths. The collect_coverage.sh script then processes that file to generate another file containing absolute paths by prefixing each of the paths with the runfiles directory and the workspace name. It then runs the singlejar tool on this list of jar files to merge them into a single file. This happens to work for all jar files in the main repository because the runfiles path is the runfiles directory plus the workspace name plus the root-relative path. However, it is broken if some of the jar files come from an external repository. It appears that singlejar errors out on the first such jar file, generating a partial output jar file without a central directory. The error is swallowed by the `collect_coverage.sh` script. Presence of coverage results may thus depend on the order of classpath entries. In order to fix this, we change the runtime classpath file to contain runfiles-relative paths, and the coverage script to prefix them with the runfiles directory. Note that we reuse SourceManifestAction here, i.e., the identical code that is also responsible for generating the runfiles directory in the first place. This is the only reliable way to get the correct paths into the test action. There are more places that use `LazyWritePathsFileAction` and I suspect that all of them are broken: - persistent test runner support in BazelJavaSemantics (AFAIK, this doesn't work in Bazel anyway) - coverage w/ metadata jars in BazelJavaSemantics (not used by JavaBinary) - coverage source list file ('-paths-for-coverage.txt'); this probably results in non-functioning coverage for *source files* in external repositories Fixes #13376. Change-Id: Ie9bcc92344f06e190efcb192a3b6ef9905aea352 Closes #13377. Change-Id: Ie9bcc92344f06e190efcb192a3b6ef9905aea352 PiperOrigin-RevId: 369687409
1 parent 2f5c575 commit 8ba48ad

File tree

2 files changed

+14
-7
lines changed

2 files changed

+14
-7
lines changed

src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@
3333
import com.google.devtools.build.lib.analysis.Runfiles;
3434
import com.google.devtools.build.lib.analysis.RunfilesProvider;
3535
import com.google.devtools.build.lib.analysis.RunfilesSupport;
36+
import com.google.devtools.build.lib.analysis.SourceManifestAction;
37+
import com.google.devtools.build.lib.analysis.SourceManifestAction.ManifestType;
3638
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
3739
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
3840
import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
39-
import com.google.devtools.build.lib.analysis.actions.LazyWritePathsFileAction;
4041
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
4142
import com.google.devtools.build.lib.analysis.config.CompilationMode;
4243
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -423,19 +424,25 @@ public ConfiguredTarget create(RuleContext ruleContext)
423424
NestedSetBuilder<Artifact> coverageSupportFiles = NestedSetBuilder.stableOrder();
424425
if (ruleContext.getConfiguration().isCodeCoverageEnabled()) {
425426

426-
// Create an artifact that contains the root relative paths of the jars on the runtime
427-
// classpath.
427+
// Create an artifact that contains the runfiles relative paths of the jars on the runtime
428+
// classpath. Using SourceManifestAction is the only reliable way to match the runfiles
429+
// creation code.
428430
Artifact runtimeClasspathArtifact =
429431
ruleContext.getUniqueDirectoryArtifact(
430432
"runtime_classpath_for_coverage",
431433
"runtime_classpath.txt",
432434
ruleContext.getBinOrGenfilesDirectory());
433435
ruleContext.registerAction(
434-
new LazyWritePathsFileAction(
436+
new SourceManifestAction(
437+
ManifestType.SOURCES_ONLY,
435438
ruleContext.getActionOwner(),
436439
runtimeClasspathArtifact,
437-
common.getRuntimeClasspath(),
438-
/* filesToIgnore= */ ImmutableSet.of(),
440+
new Runfiles.Builder(
441+
ruleContext.getWorkspaceName(),
442+
ruleContext.getConfiguration().legacyExternalRunfiles())
443+
// This matches the code below in collectDefaultRunfiles.
444+
.addTransitiveArtifactsWrappedInStableOrder(common.getRuntimeClasspath())
445+
.build(),
439446
true));
440447
filesBuilder.add(runtimeClasspathArtifact);
441448

tools/test/collect_coverage.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ if [[ ! -z "${JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE}" ]]; then
140140
# Append the runfiles prefix to all the relative paths found in
141141
# JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE, to invoke SingleJar with the
142142
# absolute paths.
143-
RUNFILES_PREFIX="$TEST_SRCDIR/$TEST_WORKSPACE/"
143+
RUNFILES_PREFIX="$TEST_SRCDIR/"
144144
cat "$JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE" | sed "s@^@$RUNFILES_PREFIX@" >> "$single_jar_params_file"
145145

146146
# Invoke SingleJar. This will create JACOCO_METADATA_JAR.

0 commit comments

Comments
 (0)