diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index 77ba7e78f..6c36c152d 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -1,8 +1,7 @@ name: main-build -## Intent is to run the ci-build workflow and download the artifacts -## and perform as much of jreleaser flow as possible and publish -## as an ever moving earlyaccess release. +## Runs full CI on every push to main and publishes an earlyaccess +## pre-release with the latest artifacts (including native bundles). on: push: @@ -17,33 +16,51 @@ concurrency: jobs: ci-build: uses: ./.github/workflows/step-ci-build.yml - with: - skip_tests: true # temporary until we have jreleaser parts working - - jreleaser: + + earlyaccess: needs: ci-build runs-on: ubuntu-latest + env: + JRELEASER_VERSION: early-access steps: - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: fetch-depth: 0 - id: shared-build uses: ./.github/actions/shared-build-setup - with: - java-version: 11 - - name: Download jbang distribution + - name: Download build artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: - name: ${{ steps.shared-build.outputs.github-short-sha }}-shared-build-jbang - path: build/install/jbang - - - name: Download native image' + name: ${{ steps.shared-build.outputs.github-short-sha }}-shared-build + path: build + - name: Download native bundles uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: - pattern: ${{ steps.shared-build.outputs.github-short-sha }}-jbang.bin-* - path: build/native-image - - - name: Show workspace tree + pattern: ${{ steps.shared-build.outputs.github-short-sha }}-jbang-native-bundles-* + path: build/distributions + merge-multiple: true + if-no-files-found: warn + - name: version extract + id: version run: | - echo "Workspace: $GITHUB_WORKSPACE" - tree -a build + RELEASE_VERSION=`cat build/tmp/version.txt` + echo "RELEASE_VERSION=$RELEASE_VERSION" >> "$GITHUB_OUTPUT" + echo "Release version: $RELEASE_VERSION" + ls -la build/distributions + - name: Run JReleaser (earlyaccess) + uses: jreleaser/release-action@97b5e2f0e845de2fe1dbbdf451ac6a21233fafff # v2 + env: + JRELEASER_PROJECT_VERSION: ${{ steps.version.outputs.RELEASE_VERSION }} + JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + version: ${{ env.JRELEASER_VERSION }} + arguments: full-release + setup-java: false + - name: JReleaser output + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: jreleaser-earlyaccess + path: | + out/jreleaser/trace.log + out/jreleaser/output.properties diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml index 99a05a2f4..44cdc9a8a 100644 --- a/.github/workflows/publish-packages.yml +++ b/.github/workflows/publish-packages.yml @@ -25,7 +25,7 @@ jobs: JRELEASER_MAVENCENTRAL_JBANG_USERNAME: ${{ secrets.OSSRH_USERNAME }} JRELEASER_MAVENCENTRAL_JBANG_PASSWORD: ${{ secrets.OSSRH_TOKEN }} JRELEASER_DOCKER_DEFAULT_PASSWORD: notusedbutrequiredbyjreleaser - JRELEASER_VERSION: 1.19.0 + JRELEASER_VERSION: early-access steps: - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: diff --git a/.github/workflows/step-ci-build.yml b/.github/workflows/step-ci-build.yml index d1ddb2a65..86bc397ad 100644 --- a/.github/workflows/step-ci-build.yml +++ b/.github/workflows/step-ci-build.yml @@ -17,6 +17,11 @@ on: required: false type: boolean default: false + skip_jreleaser_dry_run: + description: 'Skip JReleaser dry-run (e.g. when called from release workflow)' + required: false + type: boolean + default: false workflow_call: inputs: *inputs @@ -92,11 +97,24 @@ jobs: name: ${{ steps.shared-build.outputs.github-short-sha }}-jbang.bin-${{ matrix.os }} path: build/native-image/* if-no-files-found: error + + - name: build-native-bundles + run: | + ./gradlew --no-daemon nativeDistZip nativeDistTar latestNativeDistZip latestNativeDistTar + + - name: upload-native-bundles + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: ${{ steps.shared-build.outputs.github-short-sha }}-jbang-native-bundles-${{ matrix.os }} + path: | + build/distributions/*-${{ runner.os == 'macOS' && 'mac' || runner.os == 'Windows' && 'windows' || 'linux' }}-*.zip + build/distributions/*-${{ runner.os == 'macOS' && 'mac' || runner.os == 'Windows' && 'windows' || 'linux' }}-*.tar + if-no-files-found: error - - name: create install with jbang.bin + - name: create install with native binary if: ${{ !inputs.skip_tests }} run: | - ./gradlew --no-daemon installDist + ./gradlew --no-daemon cleanInstallDist installDist - name: integration-test-native-image if: ${{ !inputs.skip_tests }} env: @@ -284,6 +302,52 @@ jobs: chmod +x ./test_suite.sh ./test_suite.sh + jreleaser-dry-run: + needs: [build-shared, build-test-native-image] + if: always() && needs.build-shared.result == 'success' && !inputs.skip_jreleaser_dry_run + runs-on: ubuntu-latest + env: + JRELEASER_VERSION: early-access + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + fetch-depth: 0 + - id: shared-build + uses: ./.github/actions/shared-build-setup + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: ${{ steps.shared-build.outputs.github-short-sha }}-shared-build + path: build + - name: Download native bundles + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + pattern: ${{ steps.shared-build.outputs.github-short-sha }}-jbang-native-bundles-* + path: build/distributions + merge-multiple: true + if-no-files-found: warn + - name: version extract + id: version + run: | + RELEASE_VERSION=`cat build/tmp/version.txt` + echo "RELEASE_VERSION=$RELEASE_VERSION" >> "$GITHUB_OUTPUT" + echo "Release version: $RELEASE_VERSION" + ls -la build/distributions + - name: Run JReleaser (dry-run) + uses: jreleaser/release-action@97b5e2f0e845de2fe1dbbdf451ac6a21233fafff # v2 + env: + JRELEASER_PROJECT_VERSION: ${{ steps.version.outputs.RELEASE_VERSION }} + JRELEASER_GITHUB_TOKEN: unused-dry-run + with: + version: ${{ env.JRELEASER_VERSION }} + arguments: release --dry-run --yolo + setup-java: false + - name: Upload release artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + if: always() + with: + name: ${{ steps.shared-build.outputs.github-short-sha }}-jreleaser-release-artifacts + path: out/jreleaser/ + merge-test-reports: if: always() && !inputs.skip_tests needs: [unit-test-jvm, integration-test-jvm, build-test-native-image] diff --git a/.github/workflows/tag-and-release.yml b/.github/workflows/tag-and-release.yml index f2cd9f686..5b61d3f16 100644 --- a/.github/workflows/tag-and-release.yml +++ b/.github/workflows/tag-and-release.yml @@ -22,10 +22,111 @@ jobs: echo "debug_enabled=false" >> $GITHUB_OUTPUT fi - build: - needs: check-debug + validate-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + fetch-depth: 0 + - name: Verify commit is on main + run: | + if ! git merge-base --is-ancestor ${{ github.sha }} origin/main; then + echo "::error::Tagged commit is not on the main branch. Aborting release." + exit 1 + fi + - name: Verify CI passed for this commit + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + STATUS=$(gh api repos/${{ github.repository }}/commits/${{ github.sha }}/status --jq '.state') + echo "Commit CI status: $STATUS" + if [ "$STATUS" != "success" ]; then + echo "::error::CI has not passed for this commit (status: $STATUS). Aborting release." + exit 1 + fi + + build-shared: + needs: validate-release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + fetch-depth: 0 + - id: shared-build + uses: ./.github/actions/shared-build-setup + - name: build + run: ./gradlew --no-daemon clean build installDist publish -x spotlessCheck -x test -x integrationTest --build-cache --scan -s + - name: Upload build results + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: ${{ steps.shared-build.outputs.github-short-sha }}-shared-build + path: build + + build-native-image: + needs: build-shared + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + fetch-depth: 0 + - id: shared-build + uses: ./.github/actions/shared-build-setup + - name: setup-graalvm + uses: graalvm/setup-graalvm@bef4b0e916c7dd079bf60fb95d49139f67e32c5f # v1 + with: + java-version: '25' + distribution: 'graalvm-community' + github-token: ${{ secrets.GITHUB_TOKEN }} + set-java-home: false + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: ${{ steps.shared-build.outputs.github-short-sha }}-shared-build + path: build + - name: build-native-image + run: ./gradlew --no-daemon nativeImage + - name: ensure native image is executable + run: chmod -v +x build/native-image/jbang.bin* + - name: build-native-bundles + run: ./gradlew --no-daemon nativeDistZip nativeDistTar latestNativeDistZip latestNativeDistTar + - name: upload-native-bundles + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: ${{ steps.shared-build.outputs.github-short-sha }}-jbang-native-bundles-${{ matrix.os }} + path: | + build/distributions/*-${{ runner.os == 'macOS' && 'mac' || runner.os == 'Windows' && 'windows' || 'linux' }}-*.zip + build/distributions/*-${{ runner.os == 'macOS' && 'mac' || runner.os == 'Windows' && 'windows' || 'linux' }}-*.tar + if-no-files-found: error + + smoke-test: + needs: build-shared runs-on: ubuntu-latest - name: build-and-testing + env: + _JBANG_: ./build/install/jbang/bin/jbang + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + fetch-depth: 0 + - id: shared-build + uses: ./.github/actions/shared-build-setup + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: ${{ steps.shared-build.outputs.github-short-sha }}-shared-build + path: build + - name: smoke-test + run: | + chmod +x $_JBANG_ + $_JBANG_ init --template=cli helloworld.java + $_JBANG_ --verbose helloworld.java + rm helloworld.java + + release: + needs: [check-debug, build-shared, build-native-image, smoke-test] + runs-on: ubuntu-latest + name: release env: JRELEASER_SDKMAN_CONSUMER_KEY: ${{ secrets.SDKMAN_CONSUMER_KEY }} JRELEASER_SDKMAN_CONSUMER_TOKEN: ${{ secrets.SDKMAN_CONSUMER_TOKEN }} @@ -40,7 +141,7 @@ jobs: JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }} JRELEASER_MAVENCENTRAL_JBANG_USERNAME: ${{ secrets.OSSRH_USERNAME }} JRELEASER_MAVENCENTRAL_JBANG_PASSWORD: ${{ secrets.OSSRH_TOKEN }} - JRELEASER_VERSION: 1.19.0 + JRELEASER_VERSION: early-access steps: - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: @@ -49,35 +150,29 @@ jobs: uses: ./.github/actions/shared-build-setup with: java-version: 11 - - name: build-gradle - run: ./gradlew --no-daemon clean build installDist publish --build-cache --scan -s - - name: integration-test - env: - _JBANG_TEST_JAVA_VERSION: 11 - run: | - ./gradlew integrationTest - - name: Arcive test results - uses: ./.github/actions/shared-test-archiving - if: always() + - name: Download build artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: - prefix: ${{ steps.shared-build.outputs.github-short-sha }}-integration-test- - suffix: -jvm - - name: integration-test-bash - run: | - export PATH=`pwd`/build/install/jbang/bin:$PATH - pastdir=`pwd` - cd itests - ./test_suite.sh - cd $pastdir + name: ${{ steps.shared-build.outputs.github-short-sha }}-shared-build + path: build + - name: Download native bundles + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + pattern: ${{ steps.shared-build.outputs.github-short-sha }}-jbang-native-bundles-* + path: build/distributions + merge-multiple: true + if-no-files-found: error - name: version extract id: version run: | RELEASE_VERSION=`cat build/tmp/version.txt` - echo "::set-output name=RELEASE_VERSION::$RELEASE_VERSION" + echo "RELEASE_VERSION=$RELEASE_VERSION" >> "$GITHUB_OUTPUT" + echo "Release version: $RELEASE_VERSION" + ls -la build/distributions - name: Run JReleaser uses: jreleaser/release-action@97b5e2f0e845de2fe1dbbdf451ac6a21233fafff # v2 - env: - JRELEASER_PROJECT_VERSION: ${{steps.version.outputs.RELEASE_VERSION}} + env: + JRELEASER_PROJECT_VERSION: ${{ steps.version.outputs.RELEASE_VERSION }} with: version: ${{ env.JRELEASER_VERSION }} arguments: release @@ -90,7 +185,7 @@ jobs: path: | out/jreleaser/trace.log out/jreleaser/output.properties - + - name: Start tmate session if: always() && needs.check-debug.outputs.debug_enabled == 'true' uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3 diff --git a/build.gradle b/build.gradle index f2df72165..bcb6d66e0 100644 --- a/build.gradle +++ b/build.gradle @@ -248,7 +248,7 @@ nisseConfig { jgit { countingVersion = true countingStartPatch = 1 - appendSnapshot = false + appendSnapshot = true countingPattern = '%M.%m.%p(.%c)' } os { @@ -298,13 +298,14 @@ def commonSpec = project.copySpec { include 'jbang.ps1' into 'bin' } - // Conditionally include native image binary if it exists + // Include native image binary renamed to platform-specific name (e.g. jbang-linux-x64.bin) + // Scripts look for the platform-named binary first, then fall back to jbang.bin def nativeExecName = getNativeExecutableName() - if (project.file("${project.buildDir}/native-image/${nativeExecName}").exists()) { - from(project.buildDir.toPath().resolve('native-image')) { - include nativeExecName - into 'bin' - } + def platformNativeExecName = getPlatformNativeExecutableName() + from(project.buildDir.toPath().resolve('native-image')) { + include nativeExecName + rename nativeExecName, platformNativeExecName + into 'bin' } } @@ -325,11 +326,36 @@ latestDistZip { archiveFileName = "${project.name}.zip" } - latestDistTar { archiveFileName = "${project.name}.tar" } +tasks.register('nativeDistZip', Zip) { + dependsOn('nativeImage') + with commonSpec + archiveFileName.set(provider { "${getNativeBundleBaseName()}.zip" }) +} + +tasks.register('nativeDistTar', Tar) { + dependsOn('nativeImage') + with commonSpec + compression = Compression.NONE + archiveFileName.set(provider { "${getNativeBundleBaseName()}.tar" }) +} + +tasks.register('latestNativeDistZip', Zip) { + dependsOn('nativeImage') + with commonSpec + archiveFileName.set(provider { "${getLatestNativeBundleBaseName()}.zip" }) +} + +tasks.register('latestNativeDistTar', Tar) { + dependsOn('nativeImage') + with commonSpec + compression = Compression.NONE + archiveFileName.set(provider { "${getLatestNativeBundleBaseName()}.tar" }) +} + jar { manifest { attributes( @@ -664,8 +690,9 @@ def generateParentSuite(boolean isIntegrationTest = false, org.gradle.jvm.toolch return parts.join('-') } -// Function to get the correct native executable name based on OS -def getNativeExecutableName() { +// Functions to derive native bundle metadata based on the current platform +// Base native executable name as produced by the nativeImage task +String getNativeExecutableName() { def osName = System.getProperty('os.name').toLowerCase() if (osName.contains('windows')) { return 'jbang.bin.exe' @@ -674,6 +701,47 @@ def getNativeExecutableName() { } } +// Platform-specific native binary name for distribution bundles +String getPlatformNativeExecutableName() { + def os = getNativeBundleOs() + def arch = getNativeBundleArch() + if (os == 'windows') { + return "jbang-${os}-${arch}.bin.exe" + } else { + return "jbang-${os}-${arch}.bin" + } +} + +String getNativeBundleOs() { + def osName = System.getProperty('os.name').toLowerCase() + if (osName.contains('mac') || osName.contains('darwin')) { + return 'mac' + } else if (osName.contains('windows')) { + return 'windows' + } else { + return 'linux' + } +} + +String getNativeBundleArch() { + def arch = System.getProperty('os.arch').toLowerCase() + if (arch == 'x86_64' || arch == 'amd64') { + return 'x64' + } else if (arch == 'aarch64' || arch == 'arm64') { + return 'aarch64' + } else { + return arch.replaceAll('[^a-z0-9_]+', '-') + } +} + +String getNativeBundleBaseName() { + return "${project.name}-${project.version}-${getNativeBundleOs()}-${getNativeBundleArch()}" +} + +String getLatestNativeBundleBaseName() { + return "${project.name}-${getNativeBundleOs()}-${getNativeBundleArch()}" +} + // Configure resource processing for test and integrationTest processTestResources { filesMatching('allure.properties') { diff --git a/jreleaser.yml b/jreleaser.yml index 3808ea664..93585ee91 100644 --- a/jreleaser.yml +++ b/jreleaser.yml @@ -92,6 +92,9 @@ files: - path: build/tmp/version.txt - path: build/distributions/jbang.zip - path: build/distributions/jbang.tar + globs: + - pattern: build/distributions/jbang-*-*.zip + - pattern: build/distributions/jbang-*-*.tar distributions: jbang: diff --git a/src/it/java/dev/jbang/it/VersionIT.java b/src/it/java/dev/jbang/it/VersionIT.java index 8620ba776..4dd91dee3 100644 --- a/src/it/java/dev/jbang/it/VersionIT.java +++ b/src/it/java/dev/jbang/it/VersionIT.java @@ -20,7 +20,7 @@ public class VersionIT extends BaseIT { public void shouldVersion() { assertThat(shell("jbang version")).succeeded() .outMatches(Pattern.compile( - "(?s)\\d+\\.\\d+\\.\\d+(\\.\\d+)?" + lineSeparator())) + "(?s)\\d+\\.\\d+\\.\\d+(\\.\\d+)?(-SNAPSHOT)?" + lineSeparator())) .errEquals(""); } @@ -33,7 +33,7 @@ public void shouldVersion() { public void shouldVerboseVersion() { assertThat(shell("jbang --verbose version")).succeeded() .outMatches(Pattern.compile( - "(?s)\\d+\\.\\d+\\.\\d+(\\.\\d+)?" + lineSeparator())) + "(?s)\\d+\\.\\d+\\.\\d+(\\.\\d+)?(-SNAPSHOT)?" + lineSeparator())) .errContains("Repository"); } diff --git a/src/main/java/dev/jbang/cli/App.java b/src/main/java/dev/jbang/cli/App.java index 2ae9fdcfc..fffabd044 100644 --- a/src/main/java/dev/jbang/cli/App.java +++ b/src/main/java/dev/jbang/cli/App.java @@ -237,7 +237,8 @@ public static boolean installJBang(boolean force) throws IOException { } else { Path jar = Util.getJarLocation(); // TODO: this is duplicated in Wrapper.java - should be more shared. - if (!jar.toString().endsWith(".jar") && !jar.toString().endsWith("jbang.bin")) { + if (!jar.toString().endsWith(".jar") && !jar.toString().endsWith(".bin") + && !jar.toString().endsWith(".bin.exe")) { throw new ExitException(EXIT_GENERIC_ERROR, "Could not determine jbang location from " + jar); } Path fromDir = jar.getParent(); diff --git a/src/main/java/dev/jbang/cli/Wrapper.java b/src/main/java/dev/jbang/cli/Wrapper.java index fab782836..3a5acfe6e 100644 --- a/src/main/java/dev/jbang/cli/Wrapper.java +++ b/src/main/java/dev/jbang/cli/Wrapper.java @@ -38,11 +38,8 @@ public Integer install( } try { Path jar = Util.getJarLocation(); - String exeName = "jbang.bin"; - if (Util.isWindows()) { - exeName = "jbang.bin.exe"; - } - if (!jar.toString().endsWith(".jar") && !jar.toString().endsWith(exeName)) { + String binSuffix = Util.isWindows() ? ".bin.exe" : ".bin"; + if (!jar.toString().endsWith(".jar") && !jar.toString().endsWith(binSuffix)) { throw new ExitException(EXIT_GENERIC_ERROR, "Couldn't find JBang install location via " + jar); } Path parent = jar.getParent(); diff --git a/src/main/java/dev/jbang/spi/IntegrationManager.java b/src/main/java/dev/jbang/spi/IntegrationManager.java index 22f965ca5..e3cb9f97b 100644 --- a/src/main/java/dev/jbang/spi/IntegrationManager.java +++ b/src/main/java/dev/jbang/spi/IntegrationManager.java @@ -245,12 +245,11 @@ protected IntegrationResult runIntegrationExternal(IntegrationInput input, Path jbangJar = Util.getJarLocation(); args.add("-cp"); - String suffix = Util.isWindows() ? ".bin.exe" : ".bin"; if (JavaUtil.inNativeImage() - && (jbangJar.toString().endsWith(suffix))) { - // quick'n dirty way to get the native image to work - // TODO: check if the jar is present and if not, throw descriptive error - args.add(jbangJar.toString().replace(suffix, ".jar")); + && !jbangJar.toString().endsWith(".jar")) { + // When running as native image, find the jar in the same directory + Path jarPath = jbangJar.getParent().resolve("jbang.jar"); + args.add(jarPath.toString()); } else { if (jbangJar.toString().endsWith(".jar")) { args.add(jbangJar.toString()); diff --git a/src/main/scripts/jbang b/src/main/scripts/jbang index 12d66433f..a80321a36 100755 --- a/src/main/scripts/jbang +++ b/src/main/scripts/jbang @@ -207,7 +207,7 @@ case "$(uname -m)" in arch=x32;; x86_64|amd64) arch=x64;; - aarch64) + aarch64|arm64) arch=aarch64;; armv7l) arch=arm;; @@ -215,8 +215,6 @@ case "$(uname -m)" in arch=ppc64le;; s390x) arch=s390x;; - arm64) - arch=arm64;; riscv64) arch=riscv64 ;; @@ -249,22 +247,27 @@ if [[ -z "$JBANG_DIR" ]]; then JBDIR="$HOME/.jbang"; else JBDIR="$JBANG_DIR"; fi if [[ -z "$JBANG_CACHE_DIR" ]]; then TDIR="$JBDIR/cache"; else TDIR="$JBANG_CACHE_DIR"; fi if [[ -z "$JBANG_USE_NATIVE" ]]; then JBANG_USE_NATIVE="false"; fi -## resolve jbang.bin binary or jar path from script location +## resolve native binary or jar path from script location binaryPath="" jarPath="" if [[ "$JBANG_USE_NATIVE" == "true" ]]; then - # Look for native binary first if enabled + # Look for platform-specific native binary first (e.g. jbang-linux-x64.bin), + # then fall back to generic jbang.bin for manually placed binaries if [[ "$os" == "windows" ]]; then - if [ -f "$abs_jbang_dir/jbang.bin.exe" ] && [ -x "$abs_jbang_dir/jbang.bin.exe" ]; then + if [ -f "$abs_jbang_dir/jbang-${os}-${arch}.bin.exe" ] && [ -x "$abs_jbang_dir/jbang-${os}-${arch}.bin.exe" ]; then + binaryPath="$abs_jbang_dir/jbang-${os}-${arch}.bin.exe" + elif [ -f "$abs_jbang_dir/jbang.bin.exe" ] && [ -x "$abs_jbang_dir/jbang.bin.exe" ]; then binaryPath="$abs_jbang_dir/jbang.bin.exe" else - echo "WARNING: JBang native binary (jbang.bin.exe) not found in $abs_jbang_dir" 1>&2 + echo "WARNING: JBang native binary (jbang-${os}-${arch}.bin.exe or jbang.bin.exe) not found in $abs_jbang_dir" 1>&2 fi else - if [ -f "$abs_jbang_dir/jbang.bin" ] && [ -x "$abs_jbang_dir/jbang.bin" ]; then + if [ -f "$abs_jbang_dir/jbang-${os}-${arch}.bin" ] && [ -x "$abs_jbang_dir/jbang-${os}-${arch}.bin" ]; then + binaryPath="$abs_jbang_dir/jbang-${os}-${arch}.bin" + elif [ -f "$abs_jbang_dir/jbang.bin" ] && [ -x "$abs_jbang_dir/jbang.bin" ]; then binaryPath="$abs_jbang_dir/jbang.bin" else - echo "WARNING: JBang native binary (jbang.bin) not found or not executable in $abs_jbang_dir" 1>&2 + echo "WARNING: JBang native binary (jbang-${os}-${arch}.bin or jbang.bin) not found or not executable in $abs_jbang_dir" 1>&2 fi fi fi diff --git a/src/main/scripts/jbang.cmd b/src/main/scripts/jbang.cmd index c54764c8c..d5ff4bd55 100644 --- a/src/main/scripts/jbang.cmd +++ b/src/main/scripts/jbang.cmd @@ -8,15 +8,21 @@ if "%JBANG_DIR%"=="" (set JBDIR=%userprofile%\.jbang) else (set JBDIR=%JBANG_DIR if "%JBANG_CACHE_DIR%"=="" (set TDIR=%JBDIR%\cache) else (set TDIR=%JBANG_CACHE_DIR%) if "%JBANG_USE_NATIVE%"=="" (set JBANG_USE_NATIVE=false) -rem resolve jbang.bin binary or jar path from script location +rem detect architecture for platform-specific binary lookup +set "jbang_arch=x64" +if "%PROCESSOR_ARCHITECTURE%"=="ARM64" set "jbang_arch=aarch64" + +rem resolve native binary or jar path from script location set binaryPath= set jarPath= if "%JBANG_USE_NATIVE%"=="true" ( - rem Look for native binary first if enabled - if exist "%~dp0jbang.bin.exe" ( + rem Look for platform-specific native binary first, then fall back to jbang.bin.exe + if exist "%~dp0jbang-windows-%jbang_arch%.bin.exe" ( + set binaryPath=%~dp0jbang-windows-%jbang_arch%.bin.exe + ) else if exist "%~dp0jbang.bin.exe" ( set binaryPath=%~dp0jbang.bin.exe ) else ( - echo WARNING: JBang native binary (jbang.bin.exe^) not found in %~dp0 1>&2 + echo WARNING: JBang native binary (jbang-windows-%jbang_arch%.bin.exe or jbang.bin.exe^) not found in %~dp0 1>&2 ) ) if "!binaryPath!"=="" ( diff --git a/src/main/scripts/jbang.ps1 b/src/main/scripts/jbang.ps1 index d613ef9a6..8be978cfe 100644 --- a/src/main/scripts/jbang.ps1 +++ b/src/main/scripts/jbang.ps1 @@ -125,15 +125,20 @@ function Invoke-JBang { $env:JAVA_HOME, $env:JBANG_RUNTIME_SHELL, $env:JBANG_STDIN_NOTTY, $env:JBANG_LAUNCH_CMD=$oldJavaHome, $oldShell, $oldNotty, $oldCmd } -# resolve jbang.bin binary or jar path from script location +# detect architecture for platform-specific binary lookup +$jbang_arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) { "aarch64" } else { "x64" } + +# resolve native binary or jar path from script location $binaryPath="" $jarPath="" if ($env:JBANG_USE_NATIVE -eq "true") { - # Look for native binary first if enabled - if (Test-Path "$PSScriptRoot\jbang.bin.exe") { + # Look for platform-specific native binary first, then fall back to jbang.bin.exe + if (Test-Path "$PSScriptRoot\jbang-windows-${jbang_arch}.bin.exe") { + $binaryPath="$PSScriptRoot\jbang-windows-${jbang_arch}.bin.exe" + } elseif (Test-Path "$PSScriptRoot\jbang.bin.exe") { $binaryPath="$PSScriptRoot\jbang.bin.exe" } else { - [Console]::Error.WriteLine("WARNING: JBang native binary (jbang.bin.exe) not found in $PSScriptRoot") + [Console]::Error.WriteLine("WARNING: JBang native binary (jbang-windows-${jbang_arch}.bin.exe or jbang.bin.exe) not found in $PSScriptRoot") } } if (-not $binaryPath) {