Allow `BootClassPathInfo.system` to be a sequence of files
PiperOrigin-RevId: 388718540
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/BootClassPathInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/BootClassPathInfo.java
index cfe3e2a..2507ce0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/BootClassPathInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/BootClassPathInfo.java
@@ -13,6 +13,9 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.java;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+import com.google.common.collect.ImmutableList;
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;
@@ -24,7 +27,8 @@
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
import com.google.devtools.build.lib.starlarkbuildapi.FileApi;
import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi;
-import javax.annotation.Nullable;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.Optional;
import net.starlark.java.annot.Param;
import net.starlark.java.annot.ParamType;
import net.starlark.java.annot.StarlarkBuiltin;
@@ -66,8 +70,13 @@
allowedTypes = {
@ParamType(type = FileApi.class),
@ParamType(type = NoneType.class),
+ @ParamType(type = Sequence.class),
},
- defaultValue = "None"),
+ defaultValue = "None",
+ doc =
+ "The inputs to javac's --system flag, either a directory or a listing of files,"
+ + " which must contain at least 'release', 'lib/modules', and"
+ + " 'lib/jrt-fs.jar'"),
},
selfCall = true,
useStarlarkThread = true)
@@ -77,10 +86,13 @@
Object systemOrNone,
StarlarkThread thread)
throws EvalException {
+ NestedSet<Artifact> systemInputs = getSystemInputs(systemOrNone);
+ Optional<PathFragment> systemPath = getSystemPath(systemInputs);
return new BootClassPathInfo(
getBootClassPath(bootClassPathList),
getAuxiliary(auxiliaryList),
- getSystem(systemOrNone),
+ systemInputs,
+ systemPath,
thread.getCallerLocation());
}
@@ -96,32 +108,65 @@
Order.STABLE_ORDER, Sequence.cast(auxiliaryList, Artifact.class, "auxiliary"));
}
- private static Artifact getSystem(Object systemOrNone) throws EvalException {
+ private static NestedSet<Artifact> getSystemInputs(Object systemOrNone) throws EvalException {
if (systemOrNone == Starlark.NONE) {
- return null;
+ return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
}
if (systemOrNone instanceof Artifact) {
- return (Artifact) systemOrNone;
+ return NestedSetBuilder.create(Order.STABLE_ORDER, (Artifact) systemOrNone);
}
- throw Starlark.errorf("for system, got %s, want File or None", Starlark.type(systemOrNone));
+ if (systemOrNone instanceof Sequence<?>) {
+ return NestedSetBuilder.wrap(
+ Order.STABLE_ORDER, Sequence.cast(systemOrNone, Artifact.class, "system"));
+ }
+ throw Starlark.errorf(
+ "for system, got %s, want File, sequence, or None", Starlark.type(systemOrNone));
+ }
+
+ private static Optional<PathFragment> getSystemPath(NestedSet<Artifact> systemInputs)
+ throws EvalException {
+ ImmutableList<Artifact> inputs = systemInputs.toList();
+ if (inputs.isEmpty()) {
+ return Optional.empty();
+ }
+ if (inputs.size() == 1) {
+ Artifact input = getOnlyElement(inputs);
+ if (!input.isTreeArtifact()) {
+ throw Starlark.errorf("for system, %s is not a directory", input.getExecPathString());
+ }
+ return Optional.of(input.getExecPath());
+ }
+ Optional<PathFragment> input =
+ inputs.stream()
+ .map(Artifact::getExecPath)
+ .filter(p -> p.getBaseName().equals("release"))
+ .map(PathFragment::getParentDirectory)
+ .findAny();
+ if (!input.isPresent()) {
+ throw Starlark.errorf("for system, expected inputs to contain 'release'");
+ }
+ return input;
}
}
private final NestedSet<Artifact> bootclasspath;
private final NestedSet<Artifact> auxiliary;
- @Nullable private final Artifact system;
+ private final NestedSet<Artifact> systemInputs;
+ private final Optional<PathFragment> systemPath;
@VisibleForSerialization
@AutoCodec.Instantiator
public BootClassPathInfo(
NestedSet<Artifact> bootclasspath,
NestedSet<Artifact> auxiliary,
- Artifact system,
+ NestedSet<Artifact> systemInputs,
+ Optional<PathFragment> systemPath,
Location creationLocation) {
super(creationLocation);
this.bootclasspath = bootclasspath;
this.auxiliary = auxiliary;
- this.system = system;
+ this.systemInputs = systemInputs;
+ this.systemPath = systemPath;
}
@Override
@@ -131,14 +176,19 @@
public static BootClassPathInfo create(NestedSet<Artifact> bootclasspath) {
return new BootClassPathInfo(
- bootclasspath, NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), null, null);
+ bootclasspath,
+ NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER),
+ NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER),
+ Optional.empty(),
+ null);
}
public static BootClassPathInfo empty() {
return new BootClassPathInfo(
NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER),
NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER),
- null,
+ NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER),
+ Optional.empty(),
null);
}
@@ -156,9 +206,13 @@
}
/** An argument to the javac >= 9 {@code --system} flag. */
- @Nullable
- public Artifact system() {
- return system;
+ public Optional<PathFragment> systemPath() {
+ return systemPath;
+ }
+
+ /** Contents of the directory that is passed to the javac >= 9 {@code --system} flag. */
+ public NestedSet<Artifact> systemInputs() {
+ return systemInputs;
}
public boolean isEmpty() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileActionBuilder.java
index 11de681..cc34c32 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileActionBuilder.java
@@ -45,7 +45,9 @@
import com.google.devtools.build.lib.rules.java.JavaPluginInfo.JavaPluginData;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.util.StringCanonicalizer;
+import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.Collections;
+import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nullable;
@@ -80,7 +82,7 @@
private final NestedSet<Artifact> bootclasspathEntries;
/** An argument to the javac >= 9 {@code --system} flag. */
- @Nullable private final Artifact system;
+ @Nullable private final Optional<PathFragment> system;
/** The list of classpath entries to search for annotation processors. */
private final NestedSet<Artifact> processorPath;
@@ -101,7 +103,7 @@
Artifact outputJar,
NestedSet<Artifact> classpathEntries,
NestedSet<Artifact> bootclasspathEntries,
- @Nullable Artifact system,
+ Optional<PathFragment> system,
NestedSet<Artifact> processorPath,
NestedSet<String> processorNames,
ImmutableList<Artifact> sourceJars,
@@ -130,8 +132,8 @@
.addAllProcessor(processorNames.toList())
.addAllProcessorpath(Artifact.toExecPaths(processorPath.toList()))
.setOutputjar(outputJar.getExecPathString());
- if (system != null) {
- info.setSystem(system.getExecPathString());
+ if (system.isPresent()) {
+ info.setSystem(system.get().toString());
}
info.addAllArgument(arguments);
builder.setExtension(JavaCompileInfo.javaCompileInfo, info.build());
@@ -215,17 +217,18 @@
.addTransitive(toolchain.getJavaRuntime().javaBaseInputs())
.addTransitive(bootClassPath.bootclasspath())
.addAll(sourcePathEntries)
- .addAll(additionalInputs);
- Stream.of(coverageArtifact, bootClassPath.system())
- .filter(x -> x != null)
- .forEachOrdered(mandatoryInputs::add);
+ .addAll(additionalInputs)
+ .addTransitive(bootClassPath.systemInputs());
+ if (coverageArtifact != null) {
+ mandatoryInputs.add(coverageArtifact);
+ }
JavaCompileExtraActionInfoSupplier extraActionInfoSupplier =
new JavaCompileExtraActionInfoSupplier(
outputs.output(),
classpathEntries,
bootClassPath.bootclasspath(),
- bootClassPath.system(),
+ bootClassPath.systemPath(),
plugins.processorClasspath(),
plugins.processorClasses(),
sourceJars,
@@ -303,7 +306,9 @@
}
result.addExecPath("--output_deps_proto", outputs.depsProto());
result.addExecPaths("--bootclasspath", bootClassPath.bootclasspath());
- result.addExecPath("--system", bootClassPath.system());
+ if (bootClassPath.systemPath().isPresent()) {
+ result.addPath("--system", bootClassPath.systemPath().get());
+ }
result.addExecPaths("--sourcepath", sourcePathEntries);
result.addExecPaths("--processorpath", plugins.processorClasspath());
result.addAll("--processors", plugins.processorClasses());