diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 6147061..ad1d1f9 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -96,8 +96,10 @@ jobs: run: | set -euo pipefail ver="$(awk -F'"' '/^DEFAULT_VERSION = /{print $2}' elide/private/versions.bzl)" - echo "Elide version: $ver" - base="https://github.com/elide-dev/elide/releases/download/$ver" + tag="$(awk -F'"' -v v="$ver" '$2 == v && $4 != "" {print $4}' elide/private/versions.bzl)" + tag="${tag:-$ver}" + echo "Elide version: $ver (tag $tag)" + base="https://github.com/elide-dev/elide/releases/download/$tag" curl -fsSL -o elide.tgz "$base/elide.linux-amd64.tgz" curl -fsSL -o elide.tgz.sha256 "$base/elide.linux-amd64.tgz.sha256" echo "$(awk '{print $1}' elide.tgz.sha256) elide.tgz" | sha256sum -c - diff --git a/docs/extensions.md b/docs/extensions.md index a56f52d..98eb4d3 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -26,7 +26,7 @@ elide.use(channel, channel | Release channel: nightly, preview, or release. | String | optional | `"nightly"` | | repo_prefix | Prefix used to name per-platform download repos. | String | optional | `"elide"` | | url_template | Override release URL template. Tokens: {channel}, {version}, {os}, {cpu}, {ext}. | String | optional | `""` | -| version | Elide release version tag, e.g. `1.2.0+20260602`. Must match an entry in elide/private/versions.bzl. Defaults to the most-recently verified release. | String | optional | `"1.3.6+20260628"` | +| version | Elide release version, e.g. `1.6.0-rc.2` or `1.3.6+20260628`. Must match an entry in elide/private/versions.bzl. Defaults to the most-recently verified release. | String | optional | `"1.6.0-rc.2"` | diff --git a/elide/extensions.bzl b/elide/extensions.bzl index cdfdc22..b0e67d0 100644 --- a/elide/extensions.bzl +++ b/elide/extensions.bzl @@ -60,7 +60,7 @@ _install = tag_class( ), "version": attr.string( default = DEFAULT_VERSION, - doc = "Elide release version tag, e.g. `1.2.0+20260602`. " + + doc = "Elide release version, e.g. `1.6.0-rc.2` or `1.3.6+20260628`. " + "Must match an entry in elide/private/versions.bzl. " + "Defaults to the most-recently verified release.", ), diff --git a/elide/kotlin/builder/Fallback.kt b/elide/kotlin/builder/Fallback.kt index 43626ba..03a1e5a 100644 --- a/elide/kotlin/builder/Fallback.kt +++ b/elide/kotlin/builder/Fallback.kt @@ -12,18 +12,27 @@ object Fallback { // launch flag (no env var, no `Picked up …` notice). See WHIPLASH#1131. // // The option only exists on JDK 23+; passing it to an older `java` launcher is - // a fatal "Unrecognized option", so gate on the running feature version (the - // shim and the fallback builder share the toolchain JDK). + // a fatal "Unrecognized option", so gate on the JDK the fallback builder runs + // on: the launcher's JAVA_HOME. The shim itself runs on `elide java`, whose + // version says nothing about that JDK. private const val UNSAFE_SILENCER = "--wrapper_script_flag=--jvm_flag=--sun-misc-unsafe-memory-access=allow" internal fun unsafeSilencer(jdkFeature: Int): List = if (jdkFeature >= 23) listOf(UNSAFE_SILENCER) else emptyList() + /** Feature version of the JDK at [javaHome], from its `release` file; 0 when unknown. */ + fun jdkFeature(javaHome: String?): Int { + if (javaHome.isNullOrEmpty()) return 0 + val release = File(javaHome, "release").takeIf { it.isFile } ?: return 0 + val line = release.readLines().firstOrNull { it.startsWith("JAVA_VERSION=") } ?: return 0 + return line.substringAfter('=').trim('"').takeWhile { it.isDigit() }.toIntOrNull() ?: 0 + } + fun command( stockBuilder: String, flagfile: String, - jdkFeature: Int = Runtime.version().feature(), + jdkFeature: Int = jdkFeature(System.getenv("JAVA_HOME")), ): List = listOf(stockBuilder) + unsafeSilencer(jdkFeature) + "--flagfile=$flagfile" diff --git a/elide/private/download.bzl b/elide/private/download.bzl index 09aac4a..7446a18 100644 --- a/elide/private/download.bzl +++ b/elide/private/download.bzl @@ -2,7 +2,7 @@ """Repository rule that downloads one elide release artifact for one platform.""" -load(":versions.bzl", "DEFAULT_CHANNEL", "DEFAULT_URL_TEMPLATE", "archive_ext", "binary_ext") +load(":versions.bzl", "DEFAULT_CHANNEL", "DEFAULT_URL_TEMPLATE", "archive_ext", "binary_ext", "release_tag") visibility(["//elide/...", "//tests/..."]) @@ -60,7 +60,7 @@ def _elide_download_impl(ctx): cpu = ctx.attr.cpu url = (ctx.attr.url_template or DEFAULT_URL_TEMPLATE).format( channel = ctx.attr.channel or DEFAULT_CHANNEL, - version = ctx.attr.version, + version = release_tag(ctx.attr.version), os = os, cpu = cpu, ext = archive_ext(os), @@ -94,6 +94,10 @@ def _elide_download_impl(ctx): ctx.execute(["chmod", "+x", "bin/" + name]) for name in ["native-image", "native-image-configure"]: ctx.execute(["chmod", "+x", "lib/svm/bin/" + name]) + + # The JDK's process launcher helper also lacks it; without it every + # subprocess started from `elide java` fails with posix_spawn EACCES. + ctx.execute(["chmod", "+x", "lib/jspawnhelper"]) bin_ext = binary_ext(os) binary_path = ctx.attr.binary_path or ("bin/elide" + bin_ext) ctx.file("BUILD.bazel", _BUILD_TEMPLATE.format( diff --git a/elide/private/versions.bzl b/elide/private/versions.bzl index 7623a61..61c2d18 100644 --- a/elide/private/versions.bzl +++ b/elide/private/versions.bzl @@ -51,6 +51,7 @@ DEFAULT_CHANNEL = "nightly" # Hashes verified 2026-06-22 against GitHub release tag 1.3.4+20260622. # Hashes verified 2026-06-23 against GitHub release tag 1.3.4+20260623. # Hashes verified 2026-06-28 against GitHub release tag 1.3.6+20260628. +# Hashes verified 2026-10-12 against GitHub release tag v1.6.0-rc.2. ELIDE_VERSIONS = { "1.2.0+20260602": { ("linux", "amd64"): "sha256-yIQZwU4nM0SN19Zj2rdikdWBpj9d+fVlJK0d10p3DRA=", @@ -106,11 +107,35 @@ ELIDE_VERSIONS = { ("macos", "arm64"): "sha256-IPUIc9kYzc1mxpva0PX88yGA7UsWS+dneXTfhJxUxRA=", ("windows", "amd64"): "sha256-mKvMV80P8OFl0Qw1fTjH33qRw239sIPqJ0m18VAhlt8=", }, + "1.6.0-rc.2": { + ("linux", "amd64"): "sha256-hlwps26EHnSj+mZtqTGylHzACQAKcUrZIPWW3Q8OV5c=", + ("linux", "arm64"): "sha256-rVHHv97BWesWwT2s9eMW/BNYYtjivxps8xiZOeKJSSw=", + ("macos", "arm64"): "sha256-eWiPIObRBd6ZxAtCpSR1gtAb2S9IRufTP7KxddFrOug=", + ("windows", "amd64"): "sha256-KGilECOjaOLFVMy1jhiHx2dcWUbXVW9n9Hp1kOF06uw=", + }, +} + +# Versions whose GitHub release tag differs from the version string. Nightly tags +# (`1.3.6+20260628`) are the version itself; release candidates and releases are +# tagged with a leading `v`. +RELEASE_TAGS = { + "1.6.0-rc.2": "v1.6.0-rc.2", } +def release_tag(version): + """Returns the GitHub release tag that publishes `version`. + + Args: + version: str. An Elide version, e.g. `1.6.0-rc.2` or `1.3.6+20260628`. + + Returns: + str. The release tag, which the `{version}` URL token expands to. + """ + return RELEASE_TAGS.get(version, version) + # Default version used when consumers call elide.install() without a version. # Points at the most-recently verified entry in ELIDE_VERSIONS above. -DEFAULT_VERSION = "1.3.6+20260628" +DEFAULT_VERSION = "1.6.0-rc.2" # GitHub releases serve each tag as an immutable artifact. The {channel} token # is accepted but unused here; it remains available for consumers who override diff --git a/tests/kotlin_builder/FallbackTest.kt b/tests/kotlin_builder/FallbackTest.kt index f56a13e..5e9436e 100644 --- a/tests/kotlin_builder/FallbackTest.kt +++ b/tests/kotlin_builder/FallbackTest.kt @@ -1,5 +1,6 @@ package elide.kotlin.builder +import java.nio.file.Files import kotlin.test.Test import kotlin.test.assertEquals @@ -24,4 +25,18 @@ class FallbackTest { Fallback.command(stockBuilder = "/bin/stock", flagfile = "/tmp/f", jdkFeature = 23), ) } + + @Test fun readsFeatureVersionFromJavaHome() { + val home = Files.createTempDirectory("jdk").toFile() + try { + assertEquals(0, Fallback.jdkFeature(home.path)) + home.resolve("release").writeText("IMPLEMENTOR=\"x\"\nJAVA_VERSION=\"21.0.5\"\n") + assertEquals(21, Fallback.jdkFeature(home.path)) + home.resolve("release").writeText("JAVA_VERSION=\"25\"\n") + assertEquals(25, Fallback.jdkFeature(home.path)) + assertEquals(0, Fallback.jdkFeature(null)) + } finally { + home.deleteRecursively() + } + } } diff --git a/tests/versions_test.bzl b/tests/versions_test.bzl index 5198413..8cf90e2 100644 --- a/tests/versions_test.bzl +++ b/tests/versions_test.bzl @@ -5,7 +5,7 @@ load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") # buildifier: disable=bzl-visibility -load("//elide/private:versions.bzl", "PLATFORMS", "archive_ext", "binary_ext") +load("//elide/private:versions.bzl", "DEFAULT_VERSION", "ELIDE_VERSIONS", "PLATFORMS", "archive_ext", "binary_ext", "release_tag") def _archive_ext_test_impl(ctx): env = unittest.begin(ctx) @@ -36,6 +36,15 @@ def _platforms_complete_test_impl(ctx): _platforms_complete_test = unittest.make(_platforms_complete_test_impl) +def _release_tag_test_impl(ctx): + env = unittest.begin(ctx) + asserts.equals(env, "1.3.6+20260628", release_tag("1.3.6+20260628")) + asserts.equals(env, "v1.6.0-rc.2", release_tag("1.6.0-rc.2")) + asserts.true(env, DEFAULT_VERSION in ELIDE_VERSIONS, "DEFAULT_VERSION has no integrity row") + return unittest.end(env) + +_release_tag_test = unittest.make(_release_tag_test_impl) + def versions_test_suite(name): """Wires unit tests for versions.bzl helpers. @@ -45,11 +54,13 @@ def versions_test_suite(name): _archive_ext_test(name = "archive_ext_test") _binary_ext_test(name = "binary_ext_test") _platforms_complete_test(name = "platforms_complete_test") + _release_tag_test(name = "release_tag_test") native.test_suite( name = name, tests = [ ":archive_ext_test", ":binary_ext_test", ":platforms_complete_test", + ":release_tag_test", ], )