Skip to content

Commit eb45f34

Browse files
committed
Test and publish a multi-release jar
The previously published jars only worked on Java 21 because classes that need `--enable-preview` are not compatible between Java releases (even when the API is identical). We now still build the base contents of the jar on Java 21, but we add Java 22 overrides for all classes that have the preview flag set.
1 parent 867afe1 commit eb45f34

File tree

3 files changed

+92
-4
lines changed

3 files changed

+92
-4
lines changed

.github/workflows/build.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,38 @@ jobs:
5757
if: matrix.java == 23
5858
run: |
5959
sbt core/doc
60+
61+
integration:
62+
runs-on: ubuntu-latest
63+
name: Multi-Release JAR Integration Test
64+
steps:
65+
- uses: actions/checkout@v4
66+
- name: Set up Java
67+
uses: actions/setup-java@v4
68+
with:
69+
java-version: |
70+
21
71+
22
72+
distribution: 'temurin'
73+
cache: 'sbt'
74+
- name: Set up sbt
75+
uses: sbt/setup-sbt@v1
76+
- name: Run tests
77+
run: |
78+
# Build multi-release override classes on Java 22
79+
PATH=$JAVA_HOME_22_X64/bin:$PATH JAVA_HOME=$JAVA_HOME_22_X64 sbt \
80+
core/compile
81+
cp -r core/target/classes override-core-j22
82+
# Build jar on Java 21 with --enable-preview and include Java 22 overrides
83+
PATH=$JAVA_HOME_21_X64/bin:$PATH JAVA_HOME=$JAVA_HOME_21_X64 JAVA_OPTS=--enable-preview \
84+
OVERRIDE_CORE_J22=`realpath override-core-j22` sbt \
85+
core/clean \
86+
core/packageBin
87+
# Run tests with multi-release jar
88+
cp `realpath core/target/perfio-*.jar` override-test.jar
89+
PATH=$JAVA_HOME_21_X64/bin:$PATH JAVA_HOME=$JAVA_HOME_21_X64 JAVA_OPTS=--enable-preview \
90+
OVERRIDE_TEST_JAR=`realpath override-test.jar` sbt \
91+
test/test
92+
PATH=$JAVA_HOME_22_X64/bin:$PATH JAVA_HOME=$JAVA_HOME_22_X64 \
93+
OVERRIDE_TEST_JAR=`realpath override-test.jar` sbt \
94+
test/test

.github/workflows/release.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ jobs:
2323
with:
2424
java-version: |
2525
21
26+
22
2627
23
2728
distribution: 'temurin'
2829
cache: 'sbt'
@@ -42,9 +43,15 @@ jobs:
4243
SONATYPE_USER: ${{ secrets.SONATYPE_USER }}
4344
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
4445
run: |
45-
# Publish binaries with Java 21 (because we can't use --enable-preview for 21 from 23)
46-
PATH=$JAVA_HOME_21_X64/bin:$PATH JAVA_HOME=$JAVA_HOME_21_X64 JAVA_OPTS=--enable-preview sbt \
46+
# Build multi-release override classes with Java 22
47+
PATH=$JAVA_HOME_22_X64/bin:$PATH JAVA_HOME=$JAVA_HOME_22_X64 sbt \
48+
core/compile
49+
cp -r core/target/classes override-core-j22
50+
# Publish binaries with Java 21 with --enable-preview and include Java 22 overrides
51+
PATH=$JAVA_HOME_21_X64/bin:$PATH JAVA_HOME=$JAVA_HOME_21_X64 JAVA_OPTS=--enable-preview \
52+
OVERRIDE_CORE_J22=`realpath override-core-j22` sbt \
4753
"set core/Compile/packageDoc/publishArtifact := false" \
54+
core/clean \
4855
core/publishSigned
4956
ls -lR target/sonatype-staging
5057
# Publish javadoc with Java 23 (because we need Markdown support)

build.sbt

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import java.io.FileInputStream
12
import java.nio.file.{Files, Path}
2-
import scala.jdk.CollectionConverters._
3+
import scala.jdk.CollectionConverters.*
34

45
val PROTOBUF_HOME = sys.env.getOrElse("PROTOBUF_HOME", s"${sys.props("user.home")}/protobuf")
56
val protobufVersion = "4.29.0-RC2"
@@ -24,6 +25,9 @@ val compileOpts = Seq(
2425
"--enable-preview",
2526
))
2627

28+
// External jar to use instead of `core` for tests and benchmarks
29+
val overrideTestJar = sys.env.get("OVERRIDE_TEST_JAR")
30+
2731
javaOptions in Global ++= runtimeOpts
2832
javacOptions in Global ++= compileOpts
2933
scalacOptions in Global ++= Seq("-java-output-version", release.toString)
@@ -78,13 +82,47 @@ lazy val core = (project in file("core"))
7882
crossPaths := false,
7983
autoScalaLibrary := false,
8084
name := "perfio",
85+
// When building the Java 21 version, add multi-release overrides for preview API classes
86+
// by copying them from a previously built Java 22 output directory
87+
Compile / packageBin / mappings := {
88+
val orig = (Compile / packageBin / mappings).value
89+
sys.env.get("OVERRIDE_CORE_J22") match {
90+
case Some(j22classes) =>
91+
println("Building multi-release jar")
92+
val overrides = orig.collect {
93+
case (f, s) if s.endsWith(".class") && isPreview(f) =>
94+
val nf = new File(j22classes, s)
95+
assert(nf.exists())
96+
val ns = "META-INF/versions/22/" + s
97+
println(" Adding override "+ns)
98+
(nf, ns)
99+
}
100+
orig ++ overrides
101+
case None => orig
102+
}
103+
},
104+
(Compile / packageBin) / packageOptions +=
105+
Package.ManifestAttributes("Multi-Release" -> "true"),
81106
)
82107

83108
lazy val scalaApi = (project in file("scalaapi"))
84-
.dependsOn(core)
109+
.dependsOn(
110+
(overrideTestJar match {
111+
case Some(_) => Nil
112+
case None => Seq(core: ClasspathDep[ProjectReference])
113+
}): _*
114+
)
85115
.settings(
86116
name := "perfio-scala",
87117
publish / skip := true,
118+
(Compile / unmanagedJars) ++= {
119+
overrideTestJar match {
120+
case Some(j) =>
121+
println("Using override test jar "+j)
122+
Seq(file(j))
123+
case None => Nil
124+
}
125+
},
88126
)
89127

90128
lazy val benchUtil = (project in file("bench-util"))
@@ -215,3 +253,11 @@ test_ / Test / javap := {
215253
val pb = new ProcessBuilder(Seq("javap", "-cp", cp.iterator.map(_.data).mkString(sys.props.getOrElse("path.separator", ":"))) ++ args: _*).inheritIO()
216254
pb.start().waitFor()
217255
}
256+
257+
def isPreview(classFile: File): Boolean = {
258+
val in = new FileInputStream(classFile)
259+
try {
260+
val a = in.readNBytes(5)
261+
a(4) != 0
262+
} finally in.close()
263+
}

0 commit comments

Comments
 (0)