aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java162
1 files changed, 143 insertions, 19 deletions
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 182c2130f5..f55c0d939f 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
@@ -16,11 +16,14 @@ package com.google.devtools.build.lib.bazel.rules.java;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.Runfiles;
+import com.google.devtools.build.lib.analysis.RunfilesProvider;
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;
@@ -38,6 +41,7 @@ import com.google.devtools.build.lib.rules.java.JavaCompilationHelper;
import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.rules.java.JavaHelper;
import com.google.devtools.build.lib.rules.java.JavaPrimaryClassProvider;
+import com.google.devtools.build.lib.rules.java.JavaRunfilesProvider;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
import com.google.devtools.build.lib.rules.java.JavaUtil;
@@ -51,6 +55,7 @@ import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
/**
* Semantics for Bazel Java rules
@@ -80,14 +85,29 @@ public class BazelJavaSemantics implements JavaSemantics {
}
}
- private String getMainClassInternal(RuleContext ruleContext) {
- return ruleContext.getRule().isAttrDefined("main_class", Type.STRING)
+ private String getMainClassInternal(RuleContext ruleContext, JavaCommon javaCommon) {
+ String mainClass = ruleContext.getRule().isAttrDefined("main_class", Type.STRING)
? ruleContext.attributes().get("main_class", Type.STRING) : "";
+ boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN);
+ boolean useTestrunner = ruleContext.attributes().get("use_testrunner", Type.BOOLEAN)
+ && !useLegacyJavaTest(ruleContext);
+
+ if (createExecutable) {
+ if (useTestrunner) {
+ mainClass = "com.google.testing.junit.runner.BazelTestRunner";
+ } else { /* java_binary or non-Junit java_test */
+ if (mainClass.isEmpty()) {
+ mainClass = javaCommon.determinePrimaryClass(javaCommon.getSrcsArtifacts());
+ }
+ }
+ }
+
+ return mainClass;
}
private void checkMainClass(RuleContext ruleContext, JavaCommon javaCommon) {
boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN);
- String mainClass = getMainClassInternal(ruleContext);
+ String mainClass = getMainClassInternal(ruleContext, javaCommon);
if (!createExecutable && !mainClass.isEmpty()) {
ruleContext.ruleError("main class must not be specified when executable is not created");
@@ -95,8 +115,7 @@ public class BazelJavaSemantics implements JavaSemantics {
if (createExecutable && mainClass.isEmpty()) {
if (javaCommon.getSrcsArtifacts().isEmpty()) {
- ruleContext.ruleError(
- "need at least one of 'main_class', 'use_testrunner' or Java source files");
+ ruleContext.ruleError("need at least one of 'main_class' or Java source files");
}
mainClass = javaCommon.determinePrimaryClass(javaCommon.getSrcsArtifacts());
if (mainClass == null) {
@@ -111,7 +130,7 @@ public class BazelJavaSemantics implements JavaSemantics {
@Override
public String getMainClass(RuleContext ruleContext, JavaCommon javaCommon) {
checkMainClass(ruleContext, javaCommon);
- return getMainClassInternal(ruleContext);
+ return getMainClassInternal(ruleContext, javaCommon);
}
@Override
@@ -198,9 +217,30 @@ public class BazelJavaSemantics implements JavaSemantics {
}
}
+ private TransitiveInfoCollection getTestSupport(RuleContext ruleContext) {
+ if (!isJavaBinaryOrJavaTest(ruleContext)) {
+ return null;
+ }
+ if (useLegacyJavaTest(ruleContext)) {
+ return null;
+ }
+
+ boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN);
+ if (createExecutable && ruleContext.attributes().get("use_testrunner", Type.BOOLEAN)) {
+ return Iterables.getOnlyElement(ruleContext.getPrerequisites("$testsupport", Mode.TARGET));
+ } else {
+ return null;
+ }
+ }
+
@Override
public void addRunfilesForBinary(RuleContext ruleContext, Artifact launcher,
Runfiles.Builder runfilesBuilder) {
+ TransitiveInfoCollection testSupport = getTestSupport(ruleContext);
+ if (testSupport != null) {
+ runfilesBuilder.addTarget(testSupport, JavaRunfilesProvider.TO_RUNFILES);
+ runfilesBuilder.addTarget(testSupport, RunfilesProvider.DEFAULT_RUNFILES);
+ }
}
@Override
@@ -210,6 +250,13 @@ public class BazelJavaSemantics implements JavaSemantics {
@Override
public void collectTargetsTreatedAsDeps(
RuleContext ruleContext, ImmutableList.Builder<TransitiveInfoCollection> builder) {
+ TransitiveInfoCollection testSupport = getTestSupport(ruleContext);
+ if (testSupport != null) {
+ // TODO(bazel-team): The testsupport is used as the test framework
+ // and really only needs to be on the runtime, not compile-time
+ // classpath.
+ builder.add(testSupport);
+ }
}
@Override
@@ -230,17 +277,87 @@ public class BazelJavaSemantics implements JavaSemantics {
NestedSetBuilder<Artifact> filesBuilder,
RuleConfiguredTargetBuilder ruleBuilder) {
if (isJavaBinaryOrJavaTest(ruleContext)) {
- boolean createExec = ruleContext.attributes().get("create_executable", Type.BOOLEAN);
- ruleBuilder.add(JavaPrimaryClassProvider.class,
- new JavaPrimaryClassProvider(createExec ? getMainClassInternal(ruleContext) : null));
+ ruleBuilder.add(
+ JavaPrimaryClassProvider.class,
+ new JavaPrimaryClassProvider(getPrimaryClass(ruleContext, javaCommon)));
+ }
+ }
+
+ // TODO(dmarting): simplify that logic when we remove the legacy Bazel java_test behavior.
+ private String getPrimaryClassLegacy(RuleContext ruleContext, JavaCommon javaCommon) {
+ boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN);
+ if (!createExecutable) {
+ return null;
}
+ return getMainClassInternal(ruleContext, javaCommon);
}
+ private String getPrimaryClassNew(RuleContext ruleContext, JavaCommon javaCommon) {
+ boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN);
+ Set<Artifact> sourceFiles = ImmutableSet.copyOf(javaCommon.getSrcsArtifacts());
+
+ if (!createExecutable) {
+ return null;
+ }
+
+ boolean useTestrunner = ruleContext.attributes().get("use_testrunner", Type.BOOLEAN);
+
+ String testClass = ruleContext.getRule().isAttrDefined("test_class", Type.STRING)
+ ? ruleContext.attributes().get("test_class", Type.STRING) : "";
+
+ if (useTestrunner) {
+ if (testClass.isEmpty()) {
+ testClass = javaCommon.determinePrimaryClass(sourceFiles);
+ if (testClass == null) {
+ ruleContext.ruleError("cannot determine junit.framework.Test class "
+ + "(Found no source file '" + ruleContext.getTarget().getName()
+ + ".java' and package name doesn't include 'java' or 'javatests'. "
+ + "You might want to rename the rule or add a 'test_class' "
+ + "attribute.)");
+ }
+ }
+ return testClass;
+ } else {
+ if (!testClass.isEmpty()) {
+ ruleContext.attributeError("test_class", "this attribute is only meaningful to "
+ + "BazelTestRunner, but you are not using it (use_testrunner = 0)");
+ }
+
+ return getMainClassInternal(ruleContext, javaCommon);
+ }
+ }
+
+ private String getPrimaryClass(RuleContext ruleContext, JavaCommon javaCommon) {
+ return useLegacyJavaTest(ruleContext) ? getPrimaryClassLegacy(ruleContext, javaCommon)
+ : getPrimaryClassNew(ruleContext, javaCommon);
+ }
@Override
public Iterable<String> getJvmFlags(
RuleContext ruleContext, JavaCommon javaCommon, List<String> userJvmFlags) {
- return userJvmFlags;
+ ImmutableList.Builder<String> jvmFlags = ImmutableList.builder();
+ jvmFlags.addAll(userJvmFlags);
+
+ if (!useLegacyJavaTest(ruleContext)) {
+ if (ruleContext.attributes().get("use_testrunner", Type.BOOLEAN)) {
+ String testClass = ruleContext.getRule().isAttrDefined("test_class", Type.STRING)
+ ? ruleContext.attributes().get("test_class", Type.STRING) : "";
+ if (testClass.isEmpty()) {
+ testClass = javaCommon.determinePrimaryClass(javaCommon.getSrcsArtifacts());
+ }
+
+ if (testClass == null) {
+ ruleContext.ruleError("cannot determine test class");
+ } else {
+ // Always run junit tests with -ea (enable assertion)
+ jvmFlags.add("-ea");
+ // "suite" is a misnomer.
+ jvmFlags.add("-Dbazel.test_suite=" + ShellEscaper.escapeString(testClass));
+ }
+ }
+ }
+
+ return jvmFlags.build();
}
@Override
@@ -309,22 +426,29 @@ public class BazelJavaSemantics implements JavaSemantics {
@Override
public List<String> getExtraArguments(RuleContext ruleContext, JavaCommon javaCommon) {
if (ruleContext.getRule().getRuleClass().equals("java_test")) {
- if (ruleContext.getConfiguration().getTestArguments().isEmpty()
- && !ruleContext.attributes().isAttributeValueExplicitlySpecified("args")) {
- ImmutableList.Builder<String> builder = ImmutableList.builder();
- for (Artifact artifact : javaCommon.getSrcsArtifacts()) {
- PathFragment path = artifact.getRootRelativePath();
- String className = JavaUtil.getJavaFullClassname(FileSystemUtils.removeExtension(path));
- if (className != null) {
- builder.add(className);
+ if (useLegacyJavaTest(ruleContext)) {
+ if (ruleContext.getConfiguration().getTestArguments().isEmpty()
+ && !ruleContext.attributes().isAttributeValueExplicitlySpecified("args")) {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ for (Artifact artifact : javaCommon.getSrcsArtifacts()) {
+ PathFragment path = artifact.getRootRelativePath();
+ String className = JavaUtil.getJavaFullClassname(FileSystemUtils.removeExtension(path));
+ if (className != null) {
+ builder.add(className);
+ }
}
+ return builder.build();
}
- return builder.build();
}
}
return ImmutableList.<String>of();
}
+ private boolean useLegacyJavaTest(RuleContext ruleContext) {
+ return !ruleContext.attributes().isAttributeValueExplicitlySpecified("test_class")
+ && ruleContext.getFragment(JavaConfiguration.class).useLegacyBazelJavaTest();
+ }
+
@Override
public String getJavaBuilderMainClass() {
return JAVABUILDER_CLASS_NAME;