diff options
Diffstat (limited to 'src/main/java')
18 files changed, 283 insertions, 224 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/LazyWritePathsFileAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/LazyWritePathsFileAction.java deleted file mode 100644 index d349c6c02e..0000000000 --- a/src/main/java/com/google/devtools/build/lib/analysis/actions/LazyWritePathsFileAction.java +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.devtools.build.lib.analysis.actions; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.collect.ImmutableSet; -import com.google.devtools.build.lib.actions.ActionExecutionContext; -import com.google.devtools.build.lib.actions.ActionOwner; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.util.Fingerprint; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Lazily writes the exec path of the given files separated by newline into a specified output file. - */ -public final class LazyWritePathsFileAction extends AbstractFileWriteAction { - private static final String GUID = "6be94d90-96f3-4bec-8104-1fb08abc2546"; - - private final NestedSet<Artifact> files; - private final boolean includeOnlyIfSource; - - public LazyWritePathsFileAction( - ActionOwner owner, Artifact output, NestedSet<Artifact> files, boolean includeOnlyIfSource) { - super(owner, Artifact.NO_ARTIFACTS, output, false); - this.files = NestedSetBuilder.fromNestedSet(files).build(); - this.includeOnlyIfSource = includeOnlyIfSource; - } - - public LazyWritePathsFileAction( - ActionOwner owner, Artifact output, - ImmutableSet<Artifact> files, - boolean includeOnlyIfSource) { - super(owner, Artifact.NO_ARTIFACTS, output, false); - this.files = NestedSetBuilder.<Artifact>stableOrder().addAll(files).build(); - this.includeOnlyIfSource = includeOnlyIfSource; - } - - @Override - public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) { - return new DeterministicWriter() { - @Override - public void writeOutputFile(OutputStream out) throws IOException { - out.write(getContents().toString().getBytes(UTF_8)); - } - }; - } - - /** - * Computes the Action key for this action by computing the fingerprint for the file contents. - */ - @Override - protected String computeKey() { - Fingerprint f = new Fingerprint(); - f.addString(GUID); - f.addBoolean(includeOnlyIfSource); - f.addString(getContents()); - return f.hexDigestAndReset(); - } - - private String getContents() { - StringBuilder stringBuilder = new StringBuilder(); - for (Artifact file : files) { - if (includeOnlyIfSource) { - if (file.isSourceArtifact()) { - stringBuilder.append(file.getRootRelativePathString()); - stringBuilder.append("\n"); - } - } else { - stringBuilder.append(file.getRootRelativePathString()); - stringBuilder.append("\n"); - } - } - return stringBuilder.toString(); - } -}
\ No newline at end of file diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java b/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java index 8b42e96721..f7d2fc184e 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java @@ -461,8 +461,8 @@ public class TestRunnerAction extends AbstractAction implements NotifyOnActionCa env.put("COVERAGE_MANIFEST", getCoverageManifest().getExecPathString()); env.put("COVERAGE_DIR", getCoverageDirectory().getPathString()); env.put("COVERAGE_OUTPUT_FILE", getCoverageData().getExecPathString()); - // TODO(elenairina): Remove this after it reaches a blaze release. - env.put("NEW_JAVA_COVERAGE_IMPL", "released"); + // TODO(elenairina): Remove this after the next blaze release (after 2017.07.30). + env.put("NEW_JAVA_COVERAGE_IMPL", "True"); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java index ccfe515141..65956414df 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java @@ -29,7 +29,6 @@ import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.LazyWritePathsFileAction; import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction; import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.ComputedSubstitution; import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution; @@ -262,8 +261,6 @@ public class BazelJavaSemantics implements JavaSemantics { List<String> jvmFlags, Artifact executable, String javaStartClass, - String coverageStartClass, - NestedSetBuilder<Artifact> filesBuilder, String javaExecutable) { Preconditions.checkState(ruleContext.getConfiguration().hasFragment(Jvm.class)); @@ -317,35 +314,22 @@ public class BazelJavaSemantics implements JavaSemantics { } arguments.add(new ComputedClasspathSubstitution(classpath, workspacePrefix, isRunfilesEnabled)); - if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { - Artifact runtimeClassPathArtifact = ruleContext.getUniqueDirectoryArtifact( - "coverage_runtime_classpath", - "runtime-classpath.txt", - ruleContext.getBinOrGenfilesDirectory()); - ruleContext.registerAction(new LazyWritePathsFileAction( - ruleContext.getActionOwner(), - runtimeClassPathArtifact, - javaCommon.getRuntimeClasspath(), - false)); - filesBuilder.add(runtimeClassPathArtifact); - arguments.add(Substitution.of( - JACOCO_METADATA_PLACEHOLDER, - "export JACOCO_METADATA_JAR=${JAVA_RUNFILES}/" + workspacePrefix + "/" - + runtimeClassPathArtifact.getRootRelativePathString() - )); - arguments.add(Substitution.of( - JACOCO_MAIN_CLASS_PLACEHOLDER, "export JACOCO_MAIN_CLASS=" + coverageStartClass)); - arguments.add(Substitution.of( - JACOCO_JAVA_RUNFILES_ROOT_PLACEHOLDER, - "export JACOCO_JAVA_RUNFILES_ROOT=${JAVA_RUNFILES}/" + workspacePrefix) - ); - } else { - arguments.add(Substitution.of(JavaSemantics.JACOCO_METADATA_PLACEHOLDER, "")); - arguments.add(Substitution.of(JavaSemantics.JACOCO_MAIN_CLASS_PLACEHOLDER, "")); - arguments.add(Substitution.of(JavaSemantics.JACOCO_JAVA_RUNFILES_ROOT_PLACEHOLDER, "")); - } + JavaCompilationArtifacts javaArtifacts = javaCommon.getJavaCompilationArtifacts(); + String path = + javaArtifacts.getInstrumentedJar() != null + ? "${JAVA_RUNFILES}/" + + workspacePrefix + + javaArtifacts.getInstrumentedJar().getRootRelativePath().getPathString() + : ""; + arguments.add( + Substitution.of( + "%set_jacoco_metadata%", + ruleContext.getConfiguration().isCodeCoverageEnabled() + ? "export JACOCO_METADATA_JAR=" + path + : "")); - arguments.add(Substitution.of("%java_start_class%", ShellEscaper.escapeString(javaStartClass))); + arguments.add(Substitution.of("%java_start_class%", + ShellEscaper.escapeString(javaStartClass))); ImmutableList<String> jvmFlagsList = ImmutableList.copyOf(jvmFlags); arguments.add(Substitution.ofSpaceSeparatedList("%jvm_flags%", jvmFlagsList)); @@ -674,11 +658,49 @@ public class BazelJavaSemantics implements JavaSemantics { return jvmFlags.build(); } + /** + * Returns whether coverage has instrumented artifacts. + */ + public static boolean hasInstrumentationMetadata(JavaTargetAttributes.Builder attributes) { + return !attributes.getInstrumentationMetadata().isEmpty(); + } + + // TODO(yueg): refactor this (only mainClass different for now) @Override - public String addCoverageSupport(JavaCompilationHelper helper, Artifact executable) + public String addCoverageSupport( + JavaCompilationHelper helper, + JavaTargetAttributes.Builder attributes, + Artifact executable, + Artifact instrumentationMetadata, + JavaCompilationArtifacts.Builder javaArtifactsBuilder, + String mainClass) throws InterruptedException { // This method can be called only for *_binary/*_test targets. Preconditions.checkNotNull(executable); + // Add our own metadata artifact (if any). + if (instrumentationMetadata != null) { + attributes.addInstrumentationMetadataEntries(ImmutableList.of(instrumentationMetadata)); + } + + if (!hasInstrumentationMetadata(attributes)) { + return mainClass; + } + + Artifact instrumentedJar = + helper + .getRuleContext() + .getBinArtifact(helper.getRuleContext().getLabel().getName() + "_instrumented.jar"); + + // Create an instrumented Jar. This will be referenced on the runtime classpath prior + // to all other Jars. + JavaCommon.createInstrumentedJarAction( + helper.getRuleContext(), + this, + attributes.getInstrumentationMetadata(), + instrumentedJar, + mainClass); + javaArtifactsBuilder.setInstrumentedJar(instrumentedJar); + // Add the coverage runner to the list of dependencies when compiling in coverage mode. TransitiveInfoCollection runnerTarget = helper.getRuleContext().getPrerequisite("$jacocorunner", Mode.TARGET); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt index f1c5c84ba2..d5495c00b6 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt @@ -245,8 +245,6 @@ export CLASSLOADER_PREFIX_PATH="${RUNPATH}" # We need to make the metadata jar with uninstrumented classes available for generating # the lcov-compatible coverage report, and we don't want it on the classpath. %set_jacoco_metadata% -%set_jacoco_main_class% -%set_jacoco_java_runfiles_root% if [[ -n "$JVM_DEBUG_PORT" ]]; then JVM_DEBUG_SUSPEND=${DEFAULT_JVM_DEBUG_SUSPEND:-"y"} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java index 84a9b1abab..1198ee341a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java @@ -646,6 +646,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ApkProvider.create( zipAlignedApk, unsignedApk, + androidCommon.getInstrumentedJar(), applicationManifest.getManifest(), debugKeystore)) .addProvider(AndroidPreDexJarProvider.class, AndroidPreDexJarProvider.create(jarToDex)) diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java index 1c5d7a00e5..843e96319f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java @@ -448,11 +448,12 @@ public class AndroidCommon { } else { Artifact outputDepsProto = javacHelper.createOutputDepsProtoArtifact(resourceClassJar, javaArtifactsBuilder); - javacHelper.createCompileAction( + javacHelper.createCompileActionWithInstrumentation( resourceClassJar, null /* manifestProtoOutput */, null /* genSourceJar */, - outputDepsProto); + outputDepsProto, + javaArtifactsBuilder); } } else { // Otherwise, it should have been the AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR. @@ -698,7 +699,8 @@ public class AndroidCommon { helper.createSourceJarAction(srcJar, genSourceJar); outputDepsProto = helper.createOutputDepsProtoArtifact(classJar, javaArtifactsBuilder); - helper.createCompileAction(classJar, manifestProtoOutput, genSourceJar, outputDepsProto); + helper.createCompileActionWithInstrumentation(classJar, manifestProtoOutput, genSourceJar, + outputDepsProto, javaArtifactsBuilder); if (isBinary) { generatedExtensionRegistryProvider = @@ -879,10 +881,6 @@ public class AndroidCommon { return javaCommon.getJavacOpts(); } - public Artifact getClassJar() { - return classJar; - } - public Artifact getGenClassJar() { return genClassJar; } @@ -908,6 +906,10 @@ public class AndroidCommon { return jarsProducedForRuntime; } + public Artifact getInstrumentedJar() { + return javaCommon.getJavaCompilationArtifacts().getInstrumentedJar(); + } + public NestedSet<Artifact> getTransitiveNeverLinkLibraries() { return transitiveNeverlinkLibraries; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java index 48d8bb115e..01c4e6b89b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java @@ -126,6 +126,8 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor JavaCompilationHelper helper = getJavaCompilationHelperWithDependencies(ruleContext, javaSemantics, javaCommon, attributesBuilder); + Artifact instrumentationMetadata = + helper.createInstrumentationMetadata(classJar, javaArtifactsBuilder); Artifact executable; // the artifact for the rule itself if (OS.getCurrent() == OS.WINDOWS && ruleContext.getConfiguration().enableWindowsExeLauncher()) { @@ -152,7 +154,7 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor javaSemantics, helper, executable, - null, + instrumentationMetadata, javaArtifactsBuilder, attributesBuilder); @@ -176,7 +178,11 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor helper.createOutputDepsProtoArtifact(classJar, javaArtifactsBuilder); javaRuleOutputJarsProviderBuilder.setJdeps(outputDepsProtoArtifact); helper.createCompileAction( - classJar, manifestProtoOutput, genSourceJar, outputDepsProtoArtifact); + classJar, + manifestProtoOutput, + genSourceJar, + outputDepsProtoArtifact, + instrumentationMetadata); helper.createSourceJarAction(srcJar, genSourceJar); setUpJavaCommon(javaCommon, helper, javaArtifactsBuilder.build()); @@ -196,8 +202,6 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor getJvmFlags(ruleContext, testClass), executable, mainClass, - "com.google.testing.junit.runner.GoogleTestRunner", - filesToBuildBuilder, javaExecutable); Artifact deployJar = @@ -424,6 +428,13 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor builder.addTargets(depsForRunfiles, RunfilesProvider.DEFAULT_RUNFILES); builder.addTransitiveArtifacts(transitiveAarArtifacts); + if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { + Artifact instrumentedJar = javaCommon.getJavaCompilationArtifacts().getInstrumentedJar(); + if (instrumentedJar != null) { + builder.addArtifact(instrumentedJar); + } + } + builder.addArtifacts(javaCommon.getRuntimeClasspath()); // Add the JDK files if it comes from P4 (see java_stub_template.txt). @@ -458,4 +469,3 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor return testClass; } } - diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApkProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApkProvider.java index 70676b701d..d265fd3160 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ApkProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ApkProvider.java @@ -17,6 +17,7 @@ import com.google.auto.value.AutoValue; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import javax.annotation.Nullable; /** A provider for targets that produce an apk file. */ @AutoValue @@ -26,9 +27,10 @@ public abstract class ApkProvider implements TransitiveInfoProvider { public static ApkProvider create( Artifact apk, Artifact unsignedApk, + @Nullable Artifact coverageMetdata, Artifact mergedManifest, Artifact keystore) { - return new AutoValue_ApkProvider(apk, unsignedApk, mergedManifest, keystore); + return new AutoValue_ApkProvider(apk, unsignedApk, coverageMetdata, mergedManifest, keystore); } /** Returns the APK file built in the transitive closure. */ @@ -37,6 +39,10 @@ public abstract class ApkProvider implements TransitiveInfoProvider { /** Returns the unsigned APK file built in the transitive closure. */ public abstract Artifact getUnsignedApk(); + /** Returns the coverage metadata artifacts generated in the transitive closure. */ + @Nullable + public abstract Artifact getCoverageMetadata(); + /** Returns the merged manifest. */ public abstract Artifact getMergedManifest(); diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java index c98d231f52..0672fe4942 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java @@ -79,6 +79,7 @@ public class JavaBinary implements RuleConfiguredTargetFactory { JavaTargetAttributes.Builder attributesBuilder = common.initCommon(); attributesBuilder.addClassPathResources( ruleContext.getPrerequisiteArtifacts("classpath_resources", Mode.TARGET).list()); + // Add Java8 timezone resource data addTimezoneResourceForJavaBinaries(ruleContext, attributesBuilder); @@ -147,6 +148,8 @@ public class JavaBinary implements RuleConfiguredTargetFactory { } JavaCompilationArtifacts.Builder javaArtifactsBuilder = new JavaCompilationArtifacts.Builder(); + Artifact instrumentationMetadata = + helper.createInstrumentationMetadata(classJar, javaArtifactsBuilder); NestedSetBuilder<Artifact> filesBuilder = NestedSetBuilder.stableOrder(); Artifact executableForRunfiles = null; @@ -163,7 +166,14 @@ public class JavaBinary implements RuleConfiguredTargetFactory { filesBuilder.add(classJar).add(executableForRunfiles); if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { - mainClass = semantics.addCoverageSupport(helper, executableForRunfiles); + mainClass = + semantics.addCoverageSupport( + helper, + attributesBuilder, + executableForRunfiles, + instrumentationMetadata, + javaArtifactsBuilder, + mainClass); } } else { filesBuilder.add(classJar); @@ -214,7 +224,8 @@ public class JavaBinary implements RuleConfiguredTargetFactory { helper.createGenJarAction(classJar, manifestProtoOutput, genClassJar); } - helper.createCompileAction(classJar, manifestProtoOutput, genSourceJar, outputDepsProto); + helper.createCompileAction( + classJar, manifestProtoOutput, genSourceJar, outputDepsProto, instrumentationMetadata); helper.createSourceJarAction(srcJar, genSourceJar); common.setClassPathFragment( @@ -249,8 +260,6 @@ public class JavaBinary implements RuleConfiguredTargetFactory { jvmFlags, executableForRunfiles, mainClass, - originalMainClass, - filesBuilder, javaExecutable); if (!executableToRun.equals(executableForRunfiles)) { filesBuilder.add(executableToRun); @@ -496,6 +505,13 @@ public class JavaBinary implements RuleConfiguredTargetFactory { builder.addTargets(runtimeDeps, RunfilesProvider.DEFAULT_RUNFILES); semantics.addDependenciesForRunfiles(ruleContext, builder); + if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { + Artifact instrumentedJar = javaArtifacts.getInstrumentedJar(); + if (instrumentedJar != null) { + builder.addArtifact(instrumentedJar); + } + } + builder.addArtifacts((Iterable<Artifact>) common.getRuntimeClasspath()); // Add the JDK files if it comes from the source repository (see java_stub_template.txt). @@ -578,4 +594,3 @@ public class JavaBinary implements RuleConfiguredTargetFactory { } } } - diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java index fd3258d566..8e7fdf2395 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java @@ -173,6 +173,28 @@ public class JavaCommon { } } + /** + * Creates an action to aggregate all metadata artifacts into a single + * <target_name>_instrumented.jar file. + */ + public static void createInstrumentedJarAction( + RuleContext ruleContext, + JavaSemantics semantics, + List<Artifact> metadataArtifacts, + Artifact instrumentedJar, + String mainClass) + throws InterruptedException { + // In Jacoco's setup, metadata artifacts are real jars. + new DeployArchiveBuilder(semantics, ruleContext) + .setOutputJar(instrumentedJar) + // We need to save the original mainClass because we're going to run inside CoverageRunner + .setJavaStartClass(mainClass) + .setAttributes(new JavaTargetAttributes.Builder(semantics).build()) + .addRuntimeJars(ImmutableList.copyOf(metadataArtifacts)) + .setCompression(DeployArchiveBuilder.Compression.UNCOMPRESSED) + .build(); + } + public static ImmutableList<String> getConstraints(RuleContext ruleContext) { return ruleContext.getRule().isAttrDefined("constraints", Type.STRING_LIST) ? ImmutableList.copyOf(ruleContext.attributes().get("constraints", Type.STRING_LIST)) @@ -734,6 +756,7 @@ public class JavaCommon { .addTransitiveTargets(runtimeDepInfo, true, ClasspathType.RUNTIME_ONLY) .build(); attributes.addRuntimeClassPathEntries(args.getRuntimeJars()); + attributes.addInstrumentationMetadataEntries(args.getInstrumentationMetadata()); } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationArgs.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationArgs.java index 65896c4fd3..f30705bba4 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationArgs.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationArgs.java @@ -22,6 +22,7 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.util.FileType; +import java.util.Collection; /** A container of Java compilation artifacts. */ @AutoValue @@ -41,11 +42,14 @@ public abstract class JavaCompilationArgs { public static final JavaCompilationArgs EMPTY_ARGS = JavaCompilationArgs.create( NestedSetBuilder.<Artifact>create(Order.NAIVE_LINK_ORDER), + NestedSetBuilder.<Artifact>create(Order.NAIVE_LINK_ORDER), NestedSetBuilder.<Artifact>create(Order.NAIVE_LINK_ORDER)); private static JavaCompilationArgs create( - NestedSet<Artifact> runtimeJars, NestedSet<Artifact> compileTimeJars) { - return new AutoValue_JavaCompilationArgs(runtimeJars, compileTimeJars); + NestedSet<Artifact> runtimeJars, + NestedSet<Artifact> compileTimeJars, + NestedSet<Artifact> instrumentationMetadata) { + return new AutoValue_JavaCompilationArgs(runtimeJars, compileTimeJars, instrumentationMetadata); } /** Returns transitive runtime jars. */ @@ -54,6 +58,9 @@ public abstract class JavaCompilationArgs { /** Returns transitive compile-time jars. */ public abstract NestedSet<Artifact> getCompileTimeJars(); + /** Returns transitive instrumentation metadata jars. */ + public abstract NestedSet<Artifact> getInstrumentationMetadata(); + /** * Returns a new builder instance. */ @@ -69,6 +76,8 @@ public abstract class JavaCompilationArgs { NestedSetBuilder.naiveLinkOrder(); private final NestedSetBuilder<Artifact> compileTimeJarsBuilder = NestedSetBuilder.naiveLinkOrder(); + private final NestedSetBuilder<Artifact> instrumentationMetadataBuilder = + NestedSetBuilder.naiveLinkOrder(); /** * Use {@code TransitiveJavaCompilationArgs#builder()} to instantiate the builder. @@ -86,6 +95,7 @@ public abstract class JavaCompilationArgs { addRuntimeJars(other.getRuntimeJars()); } addCompileTimeJars(other.getCompileTimeJars()); + addInstrumentationMetadata(other.getInstrumentationMetadata()); return this; } @@ -127,6 +137,16 @@ public abstract class JavaCompilationArgs { return this; } + public Builder addInstrumentationMetadata(Artifact instrumentationMetadata) { + this.instrumentationMetadataBuilder.add(instrumentationMetadata); + return this; + } + + public Builder addInstrumentationMetadata(Collection<Artifact> instrumentationMetadata) { + this.instrumentationMetadataBuilder.addAll(instrumentationMetadata); + return this; + } + public Builder addTransitiveCompilationArgs( JavaCompilationArgsProvider dep, boolean recursive, ClasspathType type) { JavaCompilationArgs args = recursive @@ -219,6 +239,8 @@ public abstract class JavaCompilationArgs { if (!ClasspathType.COMPILE_ONLY.equals(type)) { runtimeJarsBuilder.addTransitive(args.getRuntimeJars()); } + instrumentationMetadataBuilder.addTransitive( + args.getInstrumentationMetadata()); return this; } @@ -226,7 +248,10 @@ public abstract class JavaCompilationArgs { * Builds a {@link JavaCompilationArgs} object. */ public JavaCompilationArgs build() { - return JavaCompilationArgs.create(runtimeJarsBuilder.build(), compileTimeJarsBuilder.build()); + return JavaCompilationArgs.create( + runtimeJarsBuilder.build(), + compileTimeJarsBuilder.build(), + instrumentationMetadataBuilder.build()); } } @@ -246,4 +271,3 @@ public abstract class JavaCompilationArgs { JavaCompilationArgs() {} } - diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationArtifacts.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationArtifacts.java index bd34392f35..e18ded353a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationArtifacts.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationArtifacts.java @@ -19,8 +19,10 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; + import java.util.LinkedHashSet; import java.util.Set; + import javax.annotation.Nullable; /** @@ -45,7 +47,9 @@ public abstract class JavaCompilationArtifacts { public abstract ImmutableList<Artifact> getRuntimeJars(); public abstract ImmutableList<Artifact> getCompileTimeJars(); + public abstract ImmutableList<Artifact> getInstrumentationMetadata(); @Nullable public abstract Artifact getCompileTimeDependencyArtifact(); + @Nullable public abstract Artifact getInstrumentedJar(); /** Returns a builder for a {@link JavaCompilationArtifacts}. */ public static Builder builder() { @@ -58,13 +62,17 @@ public abstract class JavaCompilationArtifacts { public static final class Builder { private final Set<Artifact> runtimeJars = new LinkedHashSet<>(); private final Set<Artifact> compileTimeJars = new LinkedHashSet<>(); + private final Set<Artifact> instrumentationMetadata = new LinkedHashSet<>(); private Artifact compileTimeDependencies; + private Artifact instrumentedJar; public JavaCompilationArtifacts build() { return new AutoValue_JavaCompilationArtifacts( ImmutableList.copyOf(runtimeJars), ImmutableList.copyOf(compileTimeJars), - compileTimeDependencies); + ImmutableList.copyOf(instrumentationMetadata), + compileTimeDependencies, + instrumentedJar); } public Builder addRuntimeJar(Artifact jar) { @@ -87,9 +95,19 @@ public abstract class JavaCompilationArtifacts { return this; } + public Builder addInstrumentationMetadata(Artifact instrumentationMetadata) { + this.instrumentationMetadata.add(instrumentationMetadata); + return this; + } + public Builder setCompileTimeDependencies(@Nullable Artifact compileTimeDependencies) { this.compileTimeDependencies = compileTimeDependencies; return this; } + + public Builder setInstrumentedJar(@Nullable Artifact instrumentedJar) { + this.instrumentedJar = instrumentedJar; + return this; + } } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java index ac07ba6832..aa2fc6a104 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java @@ -167,16 +167,18 @@ public final class JavaCompilationHelper { * * @param outputJar the class jar Artifact to create with the Action * @param manifestProtoOutput the output artifact for the manifest proto emitted from JavaBuilder - * @param gensrcOutputJar the generated sources jar Artifact to create with the Action (null if no - * sources will be generated). - * @param outputDepsProto the compiler-generated jdeps file to create with the Action (null if not - * requested) + * @param gensrcOutputJar the generated sources jar Artifact to create with the Action + * (null if no sources will be generated). + * @param outputDepsProto the compiler-generated jdeps file to create with the Action + * (null if not requested) + * @param outputMetadata metadata file (null if no instrumentation is needed). */ public void createCompileAction( Artifact outputJar, Artifact manifestProtoOutput, @Nullable Artifact gensrcOutputJar, - @Nullable Artifact outputDepsProto) { + @Nullable Artifact outputDepsProto, + @Nullable Artifact outputMetadata) { JavaTargetAttributes attributes = getAttributes(); @@ -209,7 +211,7 @@ public final class JavaCompilationHelper { builder.setGensrcOutputJar(gensrcOutputJar); builder.setOutputDepsProto(outputDepsProto); builder.setAdditionalOutputs(attributes.getAdditionalOutputs()); - builder.setFileWithPathsForCoverage(maybeCreateFileWithPathsForCoverage(outputJar)); + builder.setMetadata(outputMetadata); builder.setInstrumentationJars(jacocoInstrumentation); builder.setSourceFiles(attributes.getSourceFiles()); builder.addSourceJars(attributes.getSourceJars()); @@ -254,15 +256,65 @@ public final class JavaCompilationHelper { } } - private Artifact maybeCreateFileWithPathsForCoverage(Artifact outputJar) { - if (!shouldInstrumentJar()) { - return null; + /** + * Returns the instrumentation metadata files to be generated for a given output jar. + * + * <p>Only called if the output jar actually needs to be instrumented. + */ + @Nullable + private static Artifact createInstrumentationMetadataArtifact( + RuleContext ruleContext, Artifact outputJar) { + PathFragment packageRelativePath = outputJar.getRootRelativePath().relativeTo( + ruleContext.getPackageDirectory()); + return ruleContext.getPackageRelativeArtifact( + FileSystemUtils.replaceExtension(packageRelativePath, ".em"), outputJar.getRoot()); + } + + /** + * Creates the Action that compiles Java source files and optionally instruments them for + * coverage. + * + * @param outputJar the class jar Artifact to create with the Action + * @param manifestProtoOutput the output artifact for the manifest proto emitted from JavaBuilder + * @param gensrcJar the generated sources jar Artifact to create with the Action + * @param outputDepsProto the compiler-generated jdeps file to create with the Action + * @param javaArtifactsBuilder the build to store the instrumentation metadata in + */ + public void createCompileActionWithInstrumentation( + Artifact outputJar, + Artifact manifestProtoOutput, + @Nullable Artifact gensrcJar, + @Nullable Artifact outputDepsProto, + JavaCompilationArtifacts.Builder javaArtifactsBuilder) { + createCompileAction( + outputJar, + manifestProtoOutput, + gensrcJar, + outputDepsProto, + createInstrumentationMetadata(outputJar, javaArtifactsBuilder)); + } + + /** + * Creates the instrumentation metadata artifact if needed. + * + * @return the instrumentation metadata artifact or null if instrumentation is + * disabled + */ + @Nullable + public Artifact createInstrumentationMetadata(Artifact outputJar, + JavaCompilationArtifacts.Builder javaArtifactsBuilder) { + // If we need to instrument the jar, add additional output (the coverage metadata file) to the + // JavaCompileAction. + Artifact instrumentationMetadata = null; + if (shouldInstrumentJar()) { + instrumentationMetadata = createInstrumentationMetadataArtifact( + getRuleContext(), outputJar); + + if (instrumentationMetadata != null) { + javaArtifactsBuilder.addInstrumentationMetadata(instrumentationMetadata); + } } - PathFragment packageRelativePath = - outputJar.getRootRelativePath().relativeTo(ruleContext.getPackageDirectory()); - PathFragment path = - FileSystemUtils.replaceExtension(packageRelativePath, "-paths-for-coverage.txt"); - return ruleContext.getPackageRelativeArtifact(path, outputJar.getRoot()); + return instrumentationMetadata; } private boolean shouldInstrumentJar() { diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java index 6fe89c86fe..c0c8ae4e80 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java @@ -44,7 +44,6 @@ import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.actions.CommandLine; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.CustomMultiArgv; -import com.google.devtools.build.lib.analysis.actions.LazyWritePathsFileAction; import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; @@ -499,7 +498,7 @@ public final class JavaCompileAction extends SpawnAction { private Artifact outputDepsProto; private Collection<Artifact> additionalOutputs; private Artifact paramFile; - private Artifact fileWithPathsForCoverage; + private Artifact metadata; private ImmutableSet<Artifact> sourceFiles = ImmutableSet.of(); private final Collection<Artifact> sourceJars = new ArrayList<>(); private BuildConfiguration.StrictDepsMode strictJavaDeps = @@ -593,6 +592,7 @@ public final class JavaCompileAction extends SpawnAction { .addAll( new ArrayList<>(Collections2.filter(Arrays.asList( outputJar, + metadata, gensrcOutputJar, manifestProtoOutput, outputDepsProto), Predicates.notNull()))); @@ -615,11 +615,6 @@ public final class JavaCompileAction extends SpawnAction { semantics.getJavaBuilderMainClass(), pathSeparator); - if (fileWithPathsForCoverage != null) { - analysisEnvironment.registerAction(new LazyWritePathsFileAction( - owner, fileWithPathsForCoverage, sourceFiles, true)); - } - // The actual params-file-based command line executed for a compile action. CommandLine javaBuilderCommandLine = CustomCommandLine.builder() @@ -635,7 +630,7 @@ public final class JavaCompileAction extends SpawnAction { .addAll(instrumentationJars) .build(); - NestedSetBuilder<Artifact> inputsBuilder = + NestedSet<Artifact> inputs = NestedSetBuilder.<Artifact>stableOrder() .addTransitive(classpathEntries) .addTransitive(compileTimeDependencyArtifacts) @@ -647,12 +642,8 @@ public final class JavaCompileAction extends SpawnAction { .addAll(sourcePathEntries) .addAll(extdirInputs) .add(paramFile) - .addTransitive(tools); - if (fileWithPathsForCoverage != null) { - inputsBuilder.add(fileWithPathsForCoverage); - } - - NestedSet<Artifact> inputs = inputsBuilder.build(); + .addTransitive(tools) + .build(); return new JavaCompileAction( owner, @@ -769,9 +760,9 @@ public final class JavaCompileAction extends SpawnAction { } } } - if (fileWithPathsForCoverage != null) { + if (metadata != null) { result.add("--post_processor"); - result.addExecPath(JACOCO_INSTRUMENTATION_PROCESSOR, fileWithPathsForCoverage); + result.addExecPath(JACOCO_INSTRUMENTATION_PROCESSOR, metadata); result.addPath( configuration .getCoverageMetadataDirectory(targetLabel.getPackageIdentifier().getRepository()) @@ -881,8 +872,8 @@ public final class JavaCompileAction extends SpawnAction { return this; } - public Builder setFileWithPathsForCoverage(Artifact fileWithExecPathsForCoverage) { - this.fileWithPathsForCoverage = fileWithExecPathsForCoverage; + public Builder setMetadata(Artifact metadata) { + this.metadata = metadata; return this; } @@ -1028,7 +1019,3 @@ public final class JavaCompileAction extends SpawnAction { } } } - - - - diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java index 9326f735aa..5932b19526 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java @@ -126,7 +126,8 @@ public class JavaLibrary implements RuleConfiguredTargetFactory { Artifact outputDepsProto = helper.createOutputDepsProtoArtifact(classJar, javaArtifactsBuilder); - helper.createCompileAction(classJar, manifestProtoOutput, genSourceJar, outputDepsProto); + helper.createCompileActionWithInstrumentation(classJar, manifestProtoOutput, genSourceJar, + outputDepsProto, javaArtifactsBuilder); helper.createSourceJarAction(srcJar, genSourceJar); Artifact iJar = null; diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibraryHelper.java index 8b43e9491c..1be54d5358 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibraryHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibraryHelper.java @@ -188,7 +188,11 @@ public final class JavaLibraryHelper { jacocoInstrumental); Artifact outputDepsProto = helper.createOutputDepsProtoArtifact(output, artifactsBuilder); helper.createCompileAction( - output, null /* manifestProtoOutput */, null /* gensrcOutputJar */, outputDepsProto); + output, + null /* manifestProtoOutput */, + null /* gensrcOutputJar */, + outputDepsProto, + null /* outputMetadata */); helper.createCompileTimeJarAction(output, artifactsBuilder); artifactsBuilder.addRuntimeJar(output); @@ -240,6 +244,7 @@ public final class JavaLibraryHelper { .build(); attributes.addCompileTimeClassPathEntries(args.getCompileTimeJars()); attributes.addRuntimeClassPathEntries(args.getRuntimeJars()); + attributes.addInstrumentationMetadataEntries(args.getInstrumentationMetadata()); } private NestedSet<Artifact> getNonRecursiveCompileTimeJarsFromDeps() { diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java index 02e4149def..9e2e719532 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java @@ -21,7 +21,6 @@ import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fro import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Streams; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.LanguageDependentFragment.LibraryLanguage; import com.google.devtools.build.lib.analysis.OutputGroupProvider; @@ -32,10 +31,8 @@ import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.Runfiles.Builder; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.ComputedSubstitution; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.Attribute.LateBoundLabel; import com.google.devtools.build.lib.packages.Attribute.LateBoundLabelList; @@ -49,10 +46,8 @@ import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistry import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.util.FileType; import com.google.devtools.build.lib.vfs.PathFragment; -import java.io.File; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; import javax.annotation.Nullable; /** @@ -245,34 +240,7 @@ public interface JavaSemantics { } }; - String JACOCO_METADATA_PLACEHOLDER = "%set_jacoco_metadata%"; - String JACOCO_MAIN_CLASS_PLACEHOLDER = "%set_jacoco_main_class%"; - String JACOCO_JAVA_RUNFILES_ROOT_PLACEHOLDER = "%set_jacoco_java_runfiles_root%"; - - /** - * Substitution for exporting the jars needed for jacoco coverage. - */ - class ComputedJacocoSubstitution extends ComputedSubstitution { - private final NestedSet<Artifact> jars; - private final String pathPrefix; - - public ComputedJacocoSubstitution(NestedSet<Artifact> jars, String workspacePrefix) { - super(JACOCO_METADATA_PLACEHOLDER); - this.jars = jars; - this.pathPrefix = "${JAVA_RUNFILES}/" + workspacePrefix; - } - - /** - * Concatenating the root relative paths of the artifacts. Each relative path entry is prepended - * with "${JAVA_RUNFILES}" and the workspace prefix. - */ - @Override - public String getValue() { - return Streams.stream(jars) - .map(artifact -> pathPrefix + "/" + artifact.getRootRelativePathString()) - .collect(Collectors.joining(File.pathSeparator, "export JACOCO_METADATA_JARS=", "")); - } - } + String IJAR_LABEL = "//tools/defaults:ijar"; /** * Verifies if the rule contains any errors. @@ -343,8 +311,6 @@ public interface JavaSemantics { List<String> jvmFlags, Artifact executable, String javaStartClass, - String coverageStartClass, - NestedSetBuilder<Artifact> filesBuilder, String javaExecutable); /** @@ -390,7 +356,13 @@ public interface JavaSemantics { * * @return new main class */ - String addCoverageSupport(JavaCompilationHelper helper, Artifact executable) + String addCoverageSupport( + JavaCompilationHelper helper, + JavaTargetAttributes.Builder attributes, + Artifact executable, + Artifact instrumentationMetadata, + JavaCompilationArtifacts.Builder javaArtifactsBuilder, + String mainClass) throws InterruptedException; /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java index 5c9d2ca666..0f2ec192cd 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java @@ -82,6 +82,7 @@ public class JavaTargetAttributes { private final Map<PathFragment, Artifact> resources = new LinkedHashMap<>(); private final NestedSetBuilder<Artifact> resourceJars = NestedSetBuilder.stableOrder(); private final List<Artifact> messages = new ArrayList<>(); + private final List<Artifact> instrumentationMetadata = new ArrayList<>(); private final List<Artifact> sourceJars = new ArrayList<>(); private final List<Artifact> classPathResources = new ArrayList<>(); @@ -141,6 +142,7 @@ public class JavaTargetAttributes { Preconditions.checkArgument(!built); addCompileTimeClassPathEntries(context.getCompileTimeJars()); addRuntimeClassPathEntries(context.getRuntimeJars()); + addInstrumentationMetadataEntries(context.getInstrumentationMetadata()); return this; } @@ -254,6 +256,12 @@ public class JavaTargetAttributes { return this; } + public Builder addInstrumentationMetadataEntries(Iterable<Artifact> metadataEntries) { + Preconditions.checkArgument(!built); + Iterables.addAll(instrumentationMetadata, metadataEntries); + return this; + } + public Builder addNativeLibrary(Artifact nativeLibrary) { Preconditions.checkArgument(!built); String name = nativeLibrary.getFilename(); @@ -400,6 +408,12 @@ public class JavaTargetAttributes { return !sourceFiles.isEmpty(); } + /** @deprecated prefer {@link JavaTargetAttributes#getInstrumentationMetadata} */ + @Deprecated + public List<Artifact> getInstrumentationMetadata() { + return instrumentationMetadata; + } + /** @deprecated prefer {@link JavaTargetAttributes#hasSourceJars} */ @Deprecated public boolean hasSourceJars() { |