Add support for packaging JDK files into deploy jars
PiperOrigin-RevId: 447514841
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 c2869ac..432a5dc 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
@@ -568,7 +568,10 @@
OneVersionEnforcementLevel oneVersionEnforcementLevel,
Artifact oneVersionAllowlistArtifact,
Artifact sharedArchive,
- boolean multiReleaseDeployJars) {
+ boolean multiReleaseDeployJars,
+ PathFragment javaHome,
+ Artifact libModules,
+ NestedSet<Artifact> hermeticInputs) {
return DeployArchiveBuilder.defaultSingleJarCommandLineWithoutOneVersion(
output,
mainClass,
@@ -579,7 +582,10 @@
includeBuildData,
compression,
launcher,
- /* multiReleaseDeployJars= */ multiReleaseDeployJars)
+ /* multiReleaseDeployJars= */ multiReleaseDeployJars,
+ javaHome,
+ libModules,
+ hermeticInputs)
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java
index 5d4eb9b..b3519fe 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.rules.java;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static java.util.Objects.requireNonNull;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
@@ -30,10 +31,12 @@
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
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.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.rules.cpp.CppHelper;
import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel;
+import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nullable;
@@ -70,6 +73,9 @@
@Nullable private Artifact oneVersionAllowlistArtifact;
@Nullable private Artifact sharedArchive;
private boolean multiReleaseDeployJars;
+ @Nullable private PathFragment javaHome;
+ @Nullable private Artifact libModules;
+ private NestedSet<Artifact> hermeticInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
/** Type of compression to apply to output archive. */
public enum Compression {
@@ -180,6 +186,21 @@
return this;
}
+ public DeployArchiveBuilder setJavaHome(PathFragment javaHome) {
+ this.javaHome = requireNonNull(javaHome);
+ return this;
+ }
+
+ public DeployArchiveBuilder setLibModules(@Nullable Artifact libModules) {
+ this.libModules = libModules;
+ return this;
+ }
+
+ public DeployArchiveBuilder setHermeticInputs(NestedSet<Artifact> hermeticInputs) {
+ this.hermeticInputs = requireNonNull(hermeticInputs);
+ return this;
+ }
+
public static CustomCommandLine.Builder defaultSingleJarCommandLineWithoutOneVersion(
Artifact outputJar,
String javaMainClass,
@@ -190,7 +211,10 @@
boolean includeBuildData,
Compression compress,
Artifact launcher,
- boolean multiReleaseDeployJars) {
+ boolean multiReleaseDeployJars,
+ PathFragment javaHome,
+ Artifact libModules,
+ NestedSet<Artifact> hermeticInputs) {
return defaultSingleJarCommandLine(
outputJar,
javaMainClass,
@@ -203,7 +227,10 @@
launcher,
OneVersionEnforcementLevel.OFF,
null,
- /* multiReleaseDeployJars= */ multiReleaseDeployJars);
+ /* multiReleaseDeployJars= */ multiReleaseDeployJars,
+ javaHome,
+ libModules,
+ hermeticInputs);
}
public static CustomCommandLine.Builder defaultSingleJarCommandLine(
@@ -218,7 +245,10 @@
Artifact launcher,
OneVersionEnforcementLevel oneVersionEnforcementLevel,
@Nullable Artifact oneVersionAllowlistArtifact,
- boolean multiReleaseDeployJars) {
+ boolean multiReleaseDeployJars,
+ PathFragment javaHome,
+ Artifact libModules,
+ NestedSet<Artifact> hermeticInputs) {
CustomCommandLine.Builder args = CustomCommandLine.builder();
args.addExecPath("--output", outputJar);
@@ -265,6 +295,9 @@
if (multiReleaseDeployJars) {
args.add("--multi_release");
}
+ args.addPath("--hermetic_java_home", javaHome);
+ args.addExecPath("--jdk_lib_modules", libModules);
+ args.addExecPaths("--resources", hermeticInputs);
return args;
}
@@ -347,6 +380,10 @@
if (sharedArchive != null) {
inputs.add(sharedArchive);
}
+ inputs.addTransitive(hermeticInputs);
+ if (libModules != null) {
+ inputs.add(libModules);
+ }
Artifact singlejar = JavaToolchainProvider.from(ruleContext).getSingleJar();
@@ -374,7 +411,10 @@
oneVersionEnforcementLevel,
oneVersionAllowlistArtifact,
sharedArchive,
- /* multiReleaseDeployJars= */ multiReleaseDeployJars);
+ /* multiReleaseDeployJars= */ multiReleaseDeployJars,
+ javaHome,
+ libModules,
+ hermeticInputs);
if (checkDesugarDeps) {
commandLine = CommandLine.concat(commandLine, ImmutableList.of("--check_desugar_deps"));
}
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 836ba59..707cb09 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
@@ -15,6 +15,7 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.devtools.build.lib.collect.nestedset.Order.STABLE_ORDER;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
import static com.google.devtools.build.lib.rules.cpp.CppRuleClasses.JAVA_LAUNCHER_LINK;
import static com.google.devtools.build.lib.rules.cpp.CppRuleClasses.STATIC_LINKING_MODE;
import static com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression.COMPRESSED;
@@ -386,6 +387,22 @@
Artifact jsa = createSharedArchive(ruleContext, javaArtifacts, attributes);
+ if (ruleContext.isAttrDefined("hermetic", BOOLEAN)
+ && ruleContext.attributes().get("hermetic", BOOLEAN)) {
+ if (!createExecutable) {
+ ruleContext.ruleError("hermetic specified but create_executable is false");
+ }
+ JavaRuntimeInfo javaRuntime = JavaRuntimeInfo.from(ruleContext);
+ if (javaRuntime.libModules() == null) {
+ ruleContext.attributeError(
+ "hermetic", "hermetic specified but java_runtime.lib_modules is absent");
+ }
+ deployArchiveBuilder
+ .setJavaHome(javaRuntime.javaHomePathFragment())
+ .setLibModules(javaRuntime.libModules())
+ .setHermeticInputs(javaRuntime.hermeticInputs());
+ }
+
deployArchiveBuilder
.setOutputJar(deployJar)
.setJavaStartClass(mainClass)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java
index cd09c46..f25dedf 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java
@@ -86,6 +86,12 @@
PathFragment javaHomeRunfilesPath =
javaBinaryRunfilesPath.getParentDirectory().getParentDirectory();
+ NestedSet<Artifact> hermeticInputs =
+ PrerequisiteArtifacts.nestedSet(ruleContext, "hermetic_srcs");
+ filesBuilder.addTransitive(hermeticInputs);
+
+ Artifact libModules = ruleContext.getPrerequisiteArtifact("lib_modules");
+
NestedSet<Artifact> filesToBuild = filesBuilder.build();
// TODO(cushon): clean up uses of java_runtime in data deps and remove this
@@ -100,7 +106,9 @@
javaHome,
javaBinaryExecPath,
javaHomeRunfilesPath,
- javaBinaryRunfilesPath);
+ javaBinaryRunfilesPath,
+ hermeticInputs,
+ libModules);
TemplateVariableInfo templateVariableInfo =
new TemplateVariableInfo(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java
index 27be255..b911ed6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java
@@ -43,13 +43,17 @@
PathFragment javaHome,
PathFragment javaBinaryExecPath,
PathFragment javaHomeRunfilesPath,
- PathFragment javaBinaryRunfilesPath) {
+ PathFragment javaBinaryRunfilesPath,
+ NestedSet<Artifact> hermeticInputs,
+ @Nullable Artifact libModules) {
return new JavaRuntimeInfo(
javaBaseInputs,
javaHome,
javaBinaryExecPath,
javaHomeRunfilesPath,
- javaBinaryRunfilesPath);
+ javaBinaryRunfilesPath,
+ hermeticInputs,
+ libModules);
}
@Override
@@ -98,18 +102,24 @@
private final PathFragment javaBinaryExecPath;
private final PathFragment javaHomeRunfilesPath;
private final PathFragment javaBinaryRunfilesPath;
+ private final NestedSet<Artifact> hermeticInputs;
+ @Nullable private final Artifact libModules;
private JavaRuntimeInfo(
NestedSet<Artifact> javaBaseInputs,
PathFragment javaHome,
PathFragment javaBinaryExecPath,
PathFragment javaHomeRunfilesPath,
- PathFragment javaBinaryRunfilesPath) {
+ PathFragment javaBinaryRunfilesPath,
+ NestedSet<Artifact> hermeticInputs,
+ @Nullable Artifact libModules) {
this.javaBaseInputs = javaBaseInputs;
this.javaHome = javaHome;
this.javaBinaryExecPath = javaBinaryExecPath;
this.javaHomeRunfilesPath = javaHomeRunfilesPath;
this.javaBinaryRunfilesPath = javaBinaryRunfilesPath;
+ this.hermeticInputs = hermeticInputs;
+ this.libModules = libModules;
}
/** All input artifacts in the javabase. */
@@ -153,6 +163,22 @@
return javaBinaryRunfilesPath;
}
+ /** Input artifacts required for hermetic deployments. */
+ public NestedSet<Artifact> hermeticInputs() {
+ return hermeticInputs;
+ }
+
+ @Override
+ public Depset starlarkHermeticInputs() {
+ return Depset.of(Artifact.TYPE, hermeticInputs());
+ }
+
+ @Override
+ @Nullable
+ public Artifact libModules() {
+ return libModules;
+ }
+
@Override
public Depset starlarkJavaBaseInputs() {
return Depset.of(Artifact.TYPE, javaBaseInputs());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java
index ddefe4a..f9be8a2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java
@@ -42,6 +42,18 @@
All files in the runtime.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
.add(attr("srcs", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE))
+ /* <!-- #BLAZE_RULE(java_runtime).ATTRIBUTE(hermetic_srcs) -->
+ Files in the runtime needed for hermetic deployments.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("hermetic_srcs", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE))
+ /* <!-- #BLAZE_RULE(java_runtime).ATTRIBUTE(lib_modules) -->
+ The lib/modules file needed for hermetic deployments.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(
+ attr("lib_modules", LABEL)
+ .singleArtifact()
+ .allowedFileTypes(FileTypeSet.ANY_FILE)
+ .exec())
/* <!-- #BLAZE_RULE(java_runtime).ATTRIBUTE(java) -->
The path to the java executable.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
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 2598032..02ec7a0 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
@@ -280,7 +280,10 @@
OneVersionEnforcementLevel oneVersionEnforcementLevel,
Artifact oneVersionAllowlistArtifact,
Artifact sharedArchive,
- boolean multiReleaseDeployJars);
+ boolean multiReleaseDeployJars,
+ PathFragment javaHome,
+ Artifact libModules,
+ NestedSet<Artifact> hermeticInputs);
/**
* Creates the action that writes the Java executable stub script.
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaRuntimeInfoApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaRuntimeInfoApi.java
index e9f8a28..9a35939 100644
--- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaRuntimeInfoApi.java
+++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaRuntimeInfoApi.java
@@ -16,7 +16,9 @@
import com.google.devtools.build.docgen.annot.DocCategory;
import com.google.devtools.build.lib.collect.nestedset.Depset;
+import com.google.devtools.build.lib.starlarkbuildapi.FileApi;
import com.google.devtools.build.lib.starlarkbuildapi.core.StructApi;
+import javax.annotation.Nullable;
import net.starlark.java.annot.StarlarkBuiltin;
import net.starlark.java.annot.StarlarkMethod;
@@ -68,4 +70,20 @@
doc = "Returns the files in the Java runtime.",
structField = true)
Depset starlarkJavaBaseInputs();
+
+ /** The files in the Java runtime needed for hermetic deployments. */
+ @StarlarkMethod(
+ name = "hermetic_files",
+ doc = "Returns the files in the Java runtime needed for hermetic deployments.",
+ structField = true)
+ Depset starlarkHermeticInputs();
+
+ /** The lib/modules file. */
+ @StarlarkMethod(
+ name = "lib_modules",
+ doc = "Returns the lib/modules file.",
+ structField = true,
+ allowReturnNones = true)
+ @Nullable
+ FileApi libModules();
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfoTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfoTest.java
index 27bc0d3..d6fd39d 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfoTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfoTest.java
@@ -33,14 +33,18 @@
PathFragment.create(""),
PathFragment.create(""),
PathFragment.create(""),
- PathFragment.create(""));
+ PathFragment.create(""),
+ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
+ null);
JavaRuntimeInfo b =
JavaRuntimeInfo.create(
NestedSetBuilder.emptySet(Order.STABLE_ORDER),
PathFragment.create(""),
PathFragment.create(""),
PathFragment.create(""),
- PathFragment.create(""));
+ PathFragment.create(""),
+ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
+ null);
new EqualsTester().addEqualityGroup(a).addEqualityGroup(b).testEquals();
}
diff --git a/src/test/java/com/google/devtools/build/lib/view/java/BUILD b/src/test/java/com/google/devtools/build/lib/view/java/BUILD
index 222f0ad..f23c3b9 100644
--- a/src/test/java/com/google/devtools/build/lib/view/java/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/view/java/BUILD
@@ -113,6 +113,7 @@
deps = [
"//src/main/java/com/google/devtools/build/lib/actions",
"//src/main/java/com/google/devtools/build/lib/actions:artifacts",
+ "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
"//src/main/java/com/google/devtools/build/lib/rules/java:java-compilation",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
diff --git a/src/test/java/com/google/devtools/build/lib/view/java/SingleJarCommandLineTest.java b/src/test/java/com/google/devtools/build/lib/view/java/SingleJarCommandLineTest.java
index a60dfcc..0481318 100644
--- a/src/test/java/com/google/devtools/build/lib/view/java/SingleJarCommandLineTest.java
+++ b/src/test/java/com/google/devtools/build/lib/view/java/SingleJarCommandLineTest.java
@@ -25,6 +25,8 @@
import com.google.devtools.build.lib.actions.ArtifactRoot;
import com.google.devtools.build.lib.actions.CommandLine;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel;
import com.google.devtools.build.lib.testutil.FoundationTestCase;
import com.google.devtools.build.lib.testutil.MoreAsserts;
@@ -55,7 +57,10 @@
null,
OneVersionEnforcementLevel.OFF,
null,
- /* multiReleaseDeployJars= */ false)
+ /* multiReleaseDeployJars= */ false,
+ /* javaHome= */ null,
+ /* libModules= */ null,
+ /* hermeticInputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER))
.build();
assertThat(command.arguments()).doesNotContain("--exclude_build_data");
@@ -79,7 +84,10 @@
null,
OneVersionEnforcementLevel.OFF,
null,
- /* multiReleaseDeployJars= */ false)
+ /* multiReleaseDeployJars= */ false,
+ /* javaHome= */ null,
+ /* libModules= */ null,
+ /* hermeticInputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER))
.build();
assertThat(command.arguments()).contains("--exclude_build_data");
@@ -103,7 +111,10 @@
dummy,
OneVersionEnforcementLevel.OFF,
null,
- /* multiReleaseDeployJars= */ false)
+ /* multiReleaseDeployJars= */ false,
+ /* javaHome= */ null,
+ /* libModules= */ null,
+ /* hermeticInputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER))
.build();
assertThat(command.arguments()).contains("--java_launcher");
}
@@ -126,7 +137,10 @@
dummy,
OneVersionEnforcementLevel.OFF,
null,
- /* multiReleaseDeployJars= */ false)
+ /* multiReleaseDeployJars= */ false,
+ /* javaHome= */ null,
+ /* libModules= */ null,
+ /* hermeticInputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER))
.build();
assertThat(command.arguments()).contains("--compression");
}
@@ -149,7 +163,10 @@
dummy,
OneVersionEnforcementLevel.OFF,
null,
- /* multiReleaseDeployJars= */ false)
+ /* multiReleaseDeployJars= */ false,
+ /* javaHome= */ null,
+ /* libModules= */ null,
+ /* hermeticInputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER))
.build();
assertThat(command.arguments()).doesNotContain("--compression");
}
@@ -176,7 +193,10 @@
dummy,
OneVersionEnforcementLevel.WARNING,
dummyOneVersion,
- /* multiReleaseDeployJars= */ false)
+ /* multiReleaseDeployJars= */ false,
+ /* javaHome= */ null,
+ /* libModules= */ null,
+ /* hermeticInputs= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER))
.build();
assertThat(command.arguments())
.containsAtLeast("--enforce_one_version", "--succeed_on_found_violations");