diff --git a/.gitignore b/.gitignore index 98c43f0..4a8b3ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ fatjar/ warped/ TODO.md +/.project +/.settings/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e7849c9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,39 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [v1.2.1] - 2025-01-17 +### Fixed +- Improved transitive dependency detection for `jdeps` call + +## [v1.2.0] - 2024-06-01 +### Added +- Additional modules that aren't fetched by jdeps can be added with `--add-modules module_1,...,module_n` + +## [v1.1.0] - 2024-05-31 +### Changed +- Improved macOS runnable execution in the tar.gz file. The executable file is now placed inside a folder named `application.app`, allowing it to be launched with a double-click. + +## [v1.0.0] - 2024-05-20 +### Changed +- Script warp4j improved to support running on aarch64 architecture +- Install script improved to run with /bin/sh +- Dockerfile changed to use install.sh script (Works on x64 and aarch64 architecture) + +### Added +- Dockerfile_x64 with old build script for tests + +## [origin warp4j] - 2019-02-28 +- See origin repository: https://github.com/guziks/warp4j + +[unreleased]: https://github.com/kirbylink/warp4j/compare/master...HEAD +[v1.2.1]: https://github.com/kirbylink/warp4j/compare/v1.2.0...v1.2.1 +[v1.2.0]: https://github.com/kirbylink/warp4j/compare/v1.1.0...v1.2.0 +[v1.1.0]: https://github.com/kirbylink/warp4j/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/kirbylink/warp4j/compare/stable...v1.0.0 +[origin warp4j]: https://github.com/guziks/warp4j \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 3927659..bad9083 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,15 +5,5 @@ RUN apt-get update && apt-get install -y \ unzip \ zip \ && rm -rf /var/lib/apt/lists/* -RUN curl -fsSL -o /tmp/warp-packer \ - https://github.com/dgiagio/warp/releases/download/v0.3.0/linux-x64.warp-packer \ - && install -D \ - --mode=755 \ - --owner=root \ - --group=root \ - /tmp/warp-packer \ - /usr/local/bin \ - && rm /tmp/warp-packer -WORKDIR /workdir -COPY warp4j /usr/local/bin/ +RUN curl -s https://github.com/kirbylink/warp4j/raw/branch/master/install.sh | /bin/sh -s ENTRYPOINT [ "/usr/local/bin/warp4j" ] diff --git a/dockerhub/Dockerfile b/Dockerfile_x64 similarity index 54% rename from dockerhub/Dockerfile rename to Dockerfile_x64 index 11a726e..345f907 100644 --- a/dockerhub/Dockerfile +++ b/Dockerfile_x64 @@ -1,12 +1,13 @@ FROM debian:stable-slim RUN apt-get update && apt-get install -y \ + binutils \ curl \ file \ unzip \ zip \ && rm -rf /var/lib/apt/lists/* RUN curl -fsSL -o /tmp/warp-packer \ - https://github.com/dgiagio/warp/releases/download/v0.3.0/linux-x64.warp-packer \ + https://github.com/kirbylink/warp/releases/download/1.0.0/linux-x64.warp-packer \ && install -D \ --mode=755 \ --owner=root \ @@ -14,14 +15,6 @@ RUN curl -fsSL -o /tmp/warp-packer \ /tmp/warp-packer \ /usr/local/bin \ && rm /tmp/warp-packer -RUN curl -fsSL -o /tmp/warp4j \ - https://raw.githubusercontent.com/guziks/warp4j/stable/warp4j \ - && install -D \ - --mode=755 \ - --owner=root \ - --group=root \ - /tmp/warp4j \ - /usr/local/bin \ - && rm /tmp/warp4j WORKDIR /workdir +COPY warp4j /usr/local/bin/ ENTRYPOINT [ "/usr/local/bin/warp4j" ] diff --git a/INSTALL.md b/INSTALL.md index 4296992..b062129 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -2,13 +2,20 @@ Here are several more ways to install `warp4j`. +## Install script +Run the [install.sh](./install.sh) script from source or use the following command: +```sh +curl -s https://github.com/kirbylink/warp4j/raw/branch/master/install.sh | /bin/sh -s +``` + + ## Manual -First install [warp-packer](https://github.com/dgiagio/warp/releases) and ensure other common tools available: `awk`, `curl`, `file`, `grep`, `sed`, `sort`, `tar`, `unzip`, optional: `zip`. Then install `warp4j` like this: +First install [warp-packer](https://github.com/kirbylink/warp/releases) and ensure other common tools available: `awk`, `curl`, `file`, `grep`, `sed`, `sort`, `tar`, `unzip`, optional: `zip`. Then install `warp4j` like this: ``` $ LOCATION=/usr/local/bin \ -LINK=https://raw.githubusercontent.com/guziks/warp4j/stable/warp4j \ +LINK=https://github.com/kirbylink/warp4j/raw/branch/master/warp4j \ TEMP_LOCATION=/tmp/warp4j \ bash -c 'curl -fsSL -o $TEMP_LOCATION $LINK && \ sudo install -D \ @@ -22,14 +29,4 @@ Previous command can be also used to upgrade to the latest version. ## Docker -See docker hub [page](https://hub.docker.com/r/guziks/warp4j). - -## Moor - -Instead of direct `docker run` command you can make a launcher with [moor](https://github.com/guziks/moor): - -``` -$ moor guziks/warp4j:stable warp4j -``` - -Then use as an ordinary command. +See [Dockerfile](./Dockerfile) \ No newline at end of file diff --git a/README.md b/README.md index 541a05a..9a5586b 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ Turn JAR (java archive) into self-contained executable in a single command. ## Features -- downloads java runtimes automatically -- makes runtimes optimized for your application -- creates self-contained binaries for Linux, macOS and Windows using [warp-packer](https://github.com/dgiagio/warp) -- works on Linux, macOS and Windows (with Windows Subsystem for Linux) -- supports cross "compilation" -- does not require neither JDK nor JRE installed +- Downloads Java runtimes automatically +- Makes runtimes optimized for your application +- Creates self-contained binaries for Linux, macOS, and Windows using [warp-packer](https://git.phoenix.ipv64.de/public/warp) +- Works on Linux, macOS, and Windows (with Windows Subsystem for Linux) +- Supports cross "compilation" +- Does not require either JDK or JRE installed ## TL;DR @@ -17,19 +17,19 @@ Just put both `warp4j` and `warp-packer` somewhere in your PATH and run `warp4j ## Install -Curl one-liner installs latest versions of both `warp4j` and `warp-packer`: +Curl one-liner installs the latest versions of both `warp4j` and `warp-packer`: ``` -$ bash -c "$(curl -fsSL https://raw.githubusercontent.com/guziks/warp4j/stable/install)" +bash -c "$(curl -fsSL https://github.com/kirbylink/warp4j/raw/refs/heads/master/install.sh)" ``` -This script will show missing dependencies (if there are any), they must be installed with your package manager. +This script will show missing dependencies (if there are any); they must be installed with your package manager. See more install methods [here](INSTALL.md). ## Usage -``` +```sh $ ls my-app.jar @@ -53,56 +53,92 @@ my-app-windows-x64.zip See help: -``` -$ wapr4j --help +```sh +$ warp4j --help Usage: warp4j [options] -Turn JAR (java archive) into self-contained executable +Turn JAR (java archive) into a self-contained executable Options: -j, --java-version - override JDK/JRE version - examples: "11", "11.0", "11.0.2", "11.0.2+9" - (default: 11) + Override JDK/JRE version + Examples: "17", "17.0", "17.0.2", "17.0.2+9" + (default: 17) + -cp, --class-path + Adds additional classpaths to the jdeps call + --auto-class-path Extract and get class-path values from jar file + Ignored when -cp, --class-path is set + --spring-boot Extract and get class-path values from + Spring-Boot application jar file + Ignored when -cp, --class-path is set -o, --output - override output directory; - this is relative to current PWD + Override output directory; + This is relative to current PWD (default: ./warped) - --list show available java releases; - takes into consideration other options: + -p, --prefix + If set, warp-packer will use the prefix + as target folder in which the + application should be extracted + --list Show available java releases; + Takes into consideration other options: "--java-version", "--no-optimize", "--jvm-impl"; - the output may be used to specify concrete + The output may be used to specify concrete "--java-version" - --no-optimize use JRE instead of optimized JDK; - by default jdeps and jlink are used to create + --add-modules A list of additional java modules that should + be added to the optimized JDK. Separate each + module with commas and no spaces + --no-optimize Use JRE instead of optimized JDK; + By default jdeps and jlink are used to create optimized JDK for the particular jar; JRE is always used for java 8 - --pull check if more recent JDK/JRE distro is available; - by default latest cached version that matches + --pull Check if more recent JDK/JRE distro is available; + By default latest cached version that matches "--java-version" is used - --linux create binary for Linux - --macos create binary for macOS - --windows create binary for Windows - if no targets are specified then binaries for + --linux Create binary for Linux + --macos Create binary for macOS + --windows Create binary for Windows + If no targets are specified then binaries for all targets are created - --jvm-impl jvm implementation: hotspot or openj9 - (default: hotspot) --jvm-options - passed to java like this: + Passed to java like this: "java -jar "; - use quotes when passing multiple options - example: '-Xms512m -Xmx1024m' - -h, --help show this message + Use quotes when passing multiple options + Example: '-Xms512m -Xmx1024m' + -s, --silent Using javaw instead of java for windows + -h, --help Show this message ``` +### Running on macOS + +For macOS, the executable is placed inside a folder with the `.app` extension within the tar.gz file. This allows the application to be launched with a double-click. + +To run the application: + +1. **From the Executable**: + - Navigate to the `warped` folder. + - Find the `my-app-macos-x64` executable. + - Note: Double-clicking on “my-app-macos-x64” does not work directly because macOS does not know which program to use to open the application. + - To run it, open the terminal and navigate to the `warped` folder: + ```sh + cd /path/to/warped + ``` + - Run the executable from the terminal: + ```sh + ./my-app-macos-x64 + ``` + +2. **From the tar.gz File**: + - Extract the `my-app-macos-x64.tar.gz` file. + - Navigate to the extracted folder: `my-app-macos-x64`. + - You will find a folder named `my-app.app`. For macOS this is now an executable file. + - Double-click on `my-app.app` to run the application. + ## Compatibility Tested on the following operating systems: -- Ubuntu 18.04 -- macOS Mojave -- Windows Subsystem for Linux with Ubuntu 14.04 +- Debian 12.5 ## Cache Location diff --git a/dockerhub/README.md b/dockerhub/README.md deleted file mode 100644 index 3d7b19c..0000000 --- a/dockerhub/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Warp4j - -Turn JAR (java archive) into self-contained executable in a single command. - -See project [page](https://github.com/guziks/warp4j) for more information. - -## Usage - -``` -$ docker run --rm -it \ - -e "WARP4J_CACHE=/cache" \ - --volume :/cache \ - --volume :/workdir \ - --user $(id -u):$(id -g) \ - guziks/warp4j:stable -``` - -Change according to your requirements, but volume with working directory is mandatory. diff --git a/install b/install deleted file mode 100755 index 6000523..0000000 --- a/install +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env bash - -# install location -LOCATION=/usr/local/bin - -# exit top level program from subshell -trap "exit 1" TERM -export TOP_PID=$$ -function fail() { - kill -s TERM $TOP_PID -} - -# platform IDs -LIN=linux -MAC=macos -WIN=windows - -# returns this platform ID -function get_this_platform() { - local this_platform="$(uname -s)" - case $this_platform in - Linux*) echo $LIN ;; - Darwin*) echo $MAC ;; - *) - echo "Error: Unsupported platform $this_platform" >&2 - fail - ;; - esac -} - -# actually sets this platform -THIS_PLATFORM=$(get_this_platform) - -# fetches latest release download link for the platform -function get_latest_warp_link() { - local this_platform=$1 - local info - info=$(curl -fsSL https://api.github.com/repos/dgiagio/warp/releases) - if [[ $? != 0 ]]; then - echo "Error: Failed to get information about releases" >&2 - fail - fi - echo "$info" \ - | grep "browser_download_url" \ - | grep "$this_platform-x64.warp-packer" \ - | head -n 1 \ - | awk '{print $2}' \ - | sed -e 's/"//g' -} - -# downloads and installs single binary -function install() { - local name=$1 - local link=$2 - local temp_location="/tmp/$name" - echo "Downloading $name..." - curl -fsSL -o "$temp_location" "$link" - if [[ $? != 0 ]]; then - echo "Error: Failed to download $name" >&2 - fail - fi - echo "Creating $LOCATION/$name..." - sudo install -D \ - --mode=755 \ - --owner=root \ - --group=root \ - "$temp_location" "$LOCATION" - if [[ $? != 0 ]]; then - echo "Error: Failed to install $name" >&2 - fail - fi -} - -# returns missing dependencies -function get_missing_deps() { - local deps=( - "awk" \ - "curl" \ - "file" \ - "grep" \ - "sed" \ - "sort" \ - "tar" \ - "unzip" \ - "zip" \ - ) - for d in ${deps[@]}; do - if ! command -v $d &> /dev/null ; then - echo -n "$d " - fi - done -} - -WARP4J_LINK="https://raw.githubusercontent.com/guziks/warp4j/stable/warp4j" - -echo "Getting information about warp-packer releases..." -WARP_LINK=$(get_latest_warp_link $THIS_PLATFORM) - -MISSING_DEPS=$(get_missing_deps) - -install "warp-packer" "$WARP_LINK" && \ -install "warp4j" "$WARP4J_LINK" - -if [[ -z $MISSING_DEPS ]]; then - echo "Successfully installed" -else - echo "Main tools successfully installed" - echo "Please install following with your package manager:" - for d in ${MISSING_DEPS[@]}; do - echo -n "$d " - done - echo - exit 1 -fi diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..a409c72 --- /dev/null +++ b/install.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash + +# install location +LOCATION=/usr/local/bin + +# exit top level program from subshell +trap "exit 1" TERM +export TOP_PID=$$ +fail() { + kill -s TERM $TOP_PID +} + +# platform IDs +LIN=linux +MAC=macos +WIN=windows + +# Urls +LIN_X64_URL=https://github.com/kirbylink/warp/releases/download/1.0.0/linux-x64.warp-packer +LIN_AARCH64_URL=https://github.com/kirbylink/warp/releases/download/1.0.0/linux-aarch64.warp-packer +MAC_URL=https://github.com/kirbylink/warp/releases/download/1.0.0/macos-x64.warp-packer + +# platform architecture +X64=x64 +AARCH64=aarch64 + +# returns this platform ID +get_this_platform() { + local this_platform="$(uname -s)" + case $this_platform in + Linux*) echo $LIN ;; + Darwin*) echo $MAC ;; + *) + echo "Error: Unsupported platform $this_platform" >&2 + fail + ;; + esac +} + +# returns this platform architecture +get_this_architecture() { + local this_machine="$(uname -m)" + case $this_machine in + x86_64) echo $X64 ;; + aarch64) echo $AARCH64 ;; + *) + echo "Error: Unsupported machine $this_machine" >&2 + fail + ;; + esac +} + +# actually sets this platform +THIS_PLATFORM=$(get_this_platform) + +# actually sets this architecture +THIS_ARCHITECTURE=$(get_this_architecture) + +# fetches latest release download link for the platform +get_warp_link() { + local this_platform=$1 + local this_architecture=$2 + + if [ "$this_platform" = "$LIN" ]; then + echo "$LIN_URL" + if [ "$this_architecture" = "$X64" ]; then + echo "$LIN_X64_URL" + else + echo "$LIN_AARCH64_URL" + fi + else + echo "$MAC_URL" + fi +} + +# downloads and installs single binary +install() { + local name=$1 + local link=$2 + local temp_location="/tmp/$name" + echo "Downloading $name..." + curl -fsSL -o $temp_location $link + if [ $? != 0 ]; then + echo "Error: Failed to download $name" >&2 + fail + fi + echo "Creating $LOCATION/$name..." + su -c "install -D \ + --mode=755 \ + --owner=root \ + --group=root \ + '$temp_location' '$LOCATION'" + if [ $? != 0 ]; then + echo "Error: Failed to install $name" >&2 + fail + fi + rm $temp_location +} + +# returns missing dependencies +get_missing_deps() { + if ! command -v awk > /dev/null 2<&1; then + echo -n "awk " + fi + if ! command -v curl > /dev/null 2<&1; then + echo -n "curl " + fi + if ! command -v file > /dev/null 2<&1; then + echo -n "file " + fi + if ! command -v grep > /dev/null 2<&1; then + echo -n "grep " + fi + if ! command -v sed > /dev/null 2<&1; then + echo -n "sed " + fi + if ! command -v sort > /dev/null 2<&1; then + echo -n "sort " + fi + if ! command -v tar > /dev/null 2<&1; then + echo -n "tar " + fi + if ! command -v unzip > /dev/null 2<&1; then + echo -n "unzip " + fi + if ! command -v zip > /dev/null 2<&1; then + echo -n "zip" + fi +} + +WARP4J_LINK="https://github.com/kirbylink/warp4j/raw/refs/heads/master/warp4j" + +echo "Getting information about warp-packer releases..." +WARP_LINK=$(get_warp_link $THIS_PLATFORM $THIS_ARCHITECTURE) + +MISSING_DEPS=$(get_missing_deps) + +install "warp-packer" "$WARP_LINK" && \ +install "warp4j" "$WARP4J_LINK" + +if [ -z "$MISSING_DEPS" ]; then + echo "Successfully installed" +else + echo "Main tools successfully installed" + echo "Please install following with your package manager:" + echo $MISSING_DEPS + exit 1 +fi diff --git a/warp4j b/warp4j index bac0480..ff280ab 100755 --- a/warp4j +++ b/warp4j @@ -4,42 +4,55 @@ function print_help { echo echo 'Usage: warp4j [options] ' echo - echo 'Turn JAR (java archive) into self-contained executable' + echo 'Turn JAR (java archive) into a self-contained executable' echo echo 'Options:' echo ' -j, --java-version ' - echo ' override JDK/JRE version' - echo ' examples: "11", "11.0", "11.0.2", "11.0.2+9"' - echo ' (default: 11)' + echo ' Override JDK/JRE version' + echo ' Examples: "17", "17.0", "17.0.2", "17.0.2+9"' + echo ' (default: 17)' + echo ' -cp, --class-path ' + echo ' Adds additional classpaths to the jdeps call' + echo ' --auto-class-path Extract and get class-path values from jar file' + echo ' Ignored when -cp, --class-path is set' + echo ' --spring-boot Extract and get class-path values from' + echo ' Spring-Boot application jar file' + echo ' Ignored when -cp, --class-path is set' echo ' -o, --output ' - echo ' override output directory;' - echo ' this is relative to current PWD' + echo ' Override output directory;' + echo ' This is relative to current PWD' echo ' (default: ./warped)' - echo ' --list show available java releases;' - echo ' takes into consideration other options:' + echo ' -p, --prefix ' + echo ' If set, warp-packer will use the prefix' + echo ' as target folder in which the' + echo ' application should be extracted' + echo ' --list Show available java releases;' + echo ' Takes into consideration other options:' echo ' "--java-version", "--no-optimize", "--jvm-impl";' - echo ' the output may be used to specify concrete' + echo ' The output may be used to specify concrete' echo ' "--java-version"' - echo ' --no-optimize use JRE instead of optimized JDK;' - echo ' by default jdeps and jlink are used to create' + echo ' --add-modules A list of additional java modules that should' + echo ' be added to the optimized JDK. Separate each' + echo ' module with commas and no spaces' + echo ' --no-optimize Use JRE instead of optimized JDK;' + echo ' By default jdeps and jlink are used to create' echo ' optimized JDK for the particular jar;' echo ' JRE is always used for java 8' - echo ' --pull check if more recent JDK/JRE distro is available;' - echo ' by default latest cached version that matches' + echo ' --pull Check if more recent JDK/JRE distro is available;' + echo ' By default latest cached version that matches' echo ' "--java-version" is used' - echo ' --linux create binary for Linux' - echo ' --macos create binary for macOS' - echo ' --windows create binary for Windows' - echo ' if no targets are specified then binaries for' + echo ' --linux Create binary for Linux' + echo ' --macos Create binary for macOS' + echo ' --windows Create binary for Windows' + echo ' If no targets are specified then binaries for' echo ' all targets are created' - echo ' --jvm-impl jvm implementation: hotspot or openj9' - echo ' (default: hotspot)' echo ' --jvm-options ' - echo ' passed to java like this:' + echo ' Passed to java like this:' echo ' "java -jar ";' - echo ' use quotes when passing multiple options' - echo " example: '-Xms512m -Xmx1024m'" - echo ' -h, --help show this message' + echo ' Use quotes when passing multiple options' + echo " Example: '-Xms512m -Xmx1024m'" + echo ' -s, --silent Using javaw instead of java for windows' + echo ' -h, --help Show this message' exit } @@ -57,7 +70,7 @@ function fail_with() { fail } -# if error code is not zero fail with a message +# if error code is not zero fail with a message function fail_if() { local error_code=$1 local message=$2 @@ -89,6 +102,22 @@ function get_this_platform() { esac } +# platform Machine +X64=x64 +AARCH64=aarch64 + +# returns this platform machine +function get_this_machine() { + local this_machine="$(uname -m)" + case $this_machine in + x86_64) echo $X64 ;; + aarch64) echo $AARCH64 ;; + *) + fail_with "Unsupported machine $this_machine" + ;; + esac +} + # show help if no arguments specified if [[ $# -eq 0 ]]; then print_help @@ -104,6 +133,18 @@ while [[ $# -gt 0 ]]; do print_help exit ;; + -cp|--class-path) + CLASS_PATH="$2" + shift 2 + ;; + --auto-class-path) + AUTO_CLASS_PATH=true + shift + ;; + --spring-boot) + SPRING_BOOT_APPLICATION=true + shift + ;; -j|--java-version) JAVA_VERSION="$2" JAVA_VERSION_OVERRIDEN=true @@ -113,10 +154,18 @@ while [[ $# -gt 0 ]]; do OUTPUT_DIR_PATH="$2" shift 2 ;; + -p|--prefix) + PREFIX="--prefix $2" + shift 2 + ;; --list) LIST_RELEASES=true shift ;; + --add-modules) + ADD_MODULES="$2" + shift 2 + ;; --no-optimize) NO_OPTIMIZE=true shift @@ -137,14 +186,14 @@ while [[ $# -gt 0 ]]; do TARGETS+=($WIN) shift ;; - --jvm-impl) - JVM_IMPL="$2" - shift 2 - ;; --jvm-options) JVM_OPTIONS="$2" shift 2 ;; + -s|--silent) + SILENT=true + shift + ;; -*|--*) # unsupported options fail_with "Unsupported option $1" ;; @@ -157,10 +206,11 @@ done set -- "${POSITIONAL[@]}" # restore positional arguments THIS_PLATFORM=$(get_this_platform) +THIS_MACHINE=$(get_this_machine) # checks if all dependencies are available function check_deps() { - local deps=( + local deps=( "awk" \ "curl" \ "file" \ @@ -213,22 +263,13 @@ if [[ $JAVA_VERSION ]] && ! java_version_is_correct $JAVA_VERSION ; then fail_with "JDK version \"$JAVA_VERSION\" is not correct" fi -JVM_IMPL_HOTSPOT=hotspot -JVM_IMPL_OPENJ9=openj9 +JVM_IMPL=hotspot -# validate jvm implementation -if [[ $JVM_IMPL ]] && - [[ $JVM_IMPL != $JVM_IMPL_HOTSPOT ]] && - [[ $JVM_IMPL != $JVM_IMPL_OPENJ9 ]]; then - fail_with "jvm implementation \"$JVM_IMPL\" is not correct" -fi - -LATEST_LTS=11 # latest LTS java branch +LATEST_LTS=17 # latest LTS java branch # default options test -z $JAVA_VERSION && JAVA_VERSION=$LATEST_LTS test -z $TARGETS && TARGETS=($LIN $MAC $WIN) -test -z $JVM_IMPL && JVM_IMPL=$JVM_IMPL_HOTSPOT # returns java branch version function get_base_version() { @@ -255,27 +296,28 @@ function choose_distro_type() { # actually choose distro type JAVA_DISTRO_TYPE=$(choose_distro_type) -# generates adoptopenjdk api url +# generates adoptium api url function api_url() { - local request=$1 # info/binary - local platform=$2 # windows/linux/macos - # adoptopenjdk uses "mac" instead of "macos" + local platform=$1 # windows/linux/macos + local architecture=$2 + # adoptium uses "mac" instead of "macos" if [[ $platform == "macos" ]]; then platform="mac" fi - echo -n "https://api.adoptopenjdk.net/v2/\ -$request/releases/openjdk$JAVA_VERSION_BASE?\ -openjdk_impl=$JVM_IMPL&\ -os=$platform&\ -arch=x64&\ -type=$JAVA_DISTRO_TYPE" + + echo -n "https://api.adoptium.net/v3/assets/feature_releases/\ +$JAVA_VERSION_BASE/ga?architecture=$architecture&heap_size=normal&image_type=jdk&\ +os=$platform&page=0&page_size=20&project=$JAVA_DISTRO_TYPE&\ +sort_method=DEFAULT&sort_order=DESC&vendor=eclipse" + } # requests info about all releases for given platform and java branch function fetch_distro_info() { local platform=$1 # platform ID - local branch=$2 # 8/9/10/11... - curl -s $(api_url info $platform) + local architecture=$2 + local branch=$3 # 8/9/10/11... + curl -s $(api_url $platform $architecture) fail_if $? "Failed to fetch java $branch info" } @@ -305,7 +347,7 @@ function list_releases() { local matched local printed local platform="linux" # just picked any - info=$(fetch_distro_info $platform $JAVA_VERSION_BASE) + info=$(fetch_distro_info $platform $X64 $JAVA_VERSION_BASE) matched=$(find_matched_versions "$info" $JAVA_VERSION) if [[ $matched ]]; then echo "Releases that match $JAVA_VERSION:" @@ -326,8 +368,8 @@ if [[ $LIST_RELEASES ]]; then exit fi -JAR_FILE_BASE_NAME=$(basename -- "$JAR") # "my-app.jAr" -JAR_EXTENSION="${JAR_FILE_BASE_NAME##*.}" # "jAr" +JAR_FILE_BASE_NAME=$(basename -- "$JAR") # "my-app.jar" +JAR_EXTENSION="${JAR_FILE_BASE_NAME##*.}" # "jar" JAR_EXTENSION_LOWERCASE=$(printf "%s" "$JAR_EXTENSION" | tr '[:upper:]' '[:lower:]') # "jar" JAR_NAME="${JAR_FILE_BASE_NAME%.*}" # "my-app" @@ -347,9 +389,10 @@ if ([[ $(file $JAR) != *"Java"* ]] && # it could be "Java archive data" or "Java fi # even if this platform is not targeted, we still need -# a JDK for this platform to optimize JDKs for other platforms +# a JDK for this platform to optimize JDKs for other platforms TARGETS_TO_CACHE=${TARGETS[@]} -if [[ $JAVA_DISTRO_TYPE == $DISTRO_TYPE_JDK ]] && # if usind JDK (not JRE) +if [[ $THIS_MACHINE == $X64 ]] && # if architecture is x86 + [[ $JAVA_DISTRO_TYPE == $DISTRO_TYPE_JDK ]] && # and if using JDK (not JRE) [[ ${TARGETS[@]} != *"$THIS_PLATFORM"* ]]; then # and this platform is not targeted TARGETS_TO_CACHE+=($THIS_PLATFORM) fi @@ -369,6 +412,11 @@ fi JAVA_DOWNLOAD_PATH=$CACHE_PATH/$JAVA_DISTRO_TYPE/$JVM_IMPL BUNDLES_PATH=$CACHE_PATH/bundle # prepare bundles here +# path for extracted jar files +EXTRACTED_JAR_PATH=$CACHE_PATH/app-jar # prepare bundles here +mkdir -p ${EXTRACTED_JAR_PATH} +trap 'rm -rf ${EXTRACTED_JAR_PATH}' EXIT + DIR="$(pwd -P)" # execution directory path # final binaries created in WARPED_TEMP_PATH and then moved to WARPED_PATH @@ -390,11 +438,11 @@ JAVA_DIST='"$BUNDLED_DISTRO_SUBDIR"' JAR='"$JAR_NAME"'.jar DIR="$(cd "$(dirname "$0")" ; pwd -P)" -JAVA=$DIR/$JAVA_DIST/bin/java +JAVA=$DIR/$JAVA_DIST/bin/'"$JAVA_EXEC"' JAR_PATH=$DIR/$JAR exec "$JAVA" '"$JVM_OPTIONS"' -jar "$JAR_PATH" "$@" -' +' } # prints a launcher for windows cmd @@ -407,12 +455,12 @@ SETLOCAL SET "JAVA_DIST='"$BUNDLED_DISTRO_SUBDIR"'" SET "JAR='"$JAR_NAME"'.jar" -SET "JAVA=%~dp0\%JAVA_DIST%\bin\java.exe" +SET "JAVA=%~dp0\%JAVA_DIST%\bin\'"$JAVA_EXEC"' SET "JAR_PATH=%~dp0\%JAR%" -CALL %JAVA% '"$JVM_OPTIONS"' -jar %JAR_PATH% %* +START %JAVA% '"$JVM_OPTIONS"' -jar %JAR_PATH% %* EXIT /B %ERRORLEVEL% -' +' } # these files are success markers @@ -422,8 +470,9 @@ MARKER_UNPACKED="unpacked" # after runtime uncompress # returns latest cached version that matches version specified by user function find_latest_cached() { local platform=$1 - local user_version=$2 - local platform_dir=$JAVA_DOWNLOAD_PATH/$platform/ + local architecture=$2 + local user_version=$3 + local platform_dir=$JAVA_DOWNLOAD_PATH/$platform/$architecture # turning something like "11.0.1+13" into regexp like "^11\.0\.1\+13" local pattern="^"$(echo $user_version \ | sed -e 's/\./\\\./g' -e 's/\+/\\\+/g') @@ -446,7 +495,7 @@ function find_latest_cached() { # finds latest concrete distro version that matches version specified by user function find_latest_version() { - local info=$1 # info fetched from AdoptOpenJDK + local info=$1 # info fetched from Adoptium local user_version=$2 # version supplied by user is a template local matched_version # latest version that matches the template local versions # all versions @@ -472,12 +521,11 @@ function find_latest_version() { # finds direct link to download concrete runtime version function find_distro_link() { - local info=$1 # info fetched from AdoptOpenJDK + local info=$1 # info fetched from Adoptium local version=$2 # concrete distro version like "11.0.2+9" local link=$(echo "$info" \ - | grep -B13 "\"heap_size\": \"normal\"" \ - | grep -B11 "\"semver\": \"$version\"" \ - | grep "binary_link" \ + | grep -B14 "\"release_name\": \"jdk-$version\"" \ + | grep "\"link\":" \ | sort --reverse \ | head -n 1 \ | awk '{print $2}' \ @@ -491,9 +539,11 @@ function find_distro_link() { # downloads runtime distro function download_distro() { local platform=$1 - local version=$2 - local link=$3 - local download_dir=$JAVA_DOWNLOAD_PATH/$platform/$version + local architecture=$2 + local version=$3 + local link=$4 + local download_dir=$JAVA_DOWNLOAD_PATH/$platform/$architecture/$version + echo "Download link: $link" echo "Downloading $JVM_IMPL-$JAVA_DISTRO_TYPE-$version-$platform..." rm -rf "$download_dir" mkdir -p "$download_dir" @@ -507,58 +557,64 @@ function download_distro() { ) } -# ensures required distro is in cache +# ensures required distro is in cache function ensure_distro_cached() { local platform=$1 + local architecture=$2 local distro_info local distro_link if [[ -z $PULL ]]; then if [[ -z $JAVA_VERSION_OVERRIDEN ]]; then - if [[ ! $(find_latest_cached $platform $LATEST_LTS) ]]; then - distro_info=$(fetch_distro_info $platform $LATEST_LTS) + if [[ ! $(find_latest_cached $platform $architecture $LATEST_LTS) ]]; then + distro_info=$(fetch_distro_info $platform $architecture $LATEST_LTS) CONCRETE_JAVA_VERSION=$(find_latest_version "$distro_info" $LATEST_LTS) distro_link=$(find_distro_link "$distro_info" $CONCRETE_JAVA_VERSION) - download_distro $platform $CONCRETE_JAVA_VERSION "$distro_link" + download_distro $platform $architecture $CONCRETE_JAVA_VERSION "$distro_link" else - CONCRETE_JAVA_VERSION=$(find_latest_cached $platform $LATEST_LTS) - fi + CONCRETE_JAVA_VERSION=$(find_latest_cached $platform $architecture $LATEST_LTS) + fi else - if [[ ! $(find_latest_cached $platform $JAVA_VERSION) ]]; then - distro_info=$(fetch_distro_info $platform $JAVA_VERSION_BASE) + if [[ ! $(find_latest_cached $platform $architecture $JAVA_VERSION) ]]; then + distro_info=$(fetch_distro_info $platform $architecture $JAVA_VERSION_BASE) CONCRETE_JAVA_VERSION=$(find_latest_version "$distro_info" $JAVA_VERSION) distro_link=$(find_distro_link "$distro_info" $CONCRETE_JAVA_VERSION) - download_distro $platform $CONCRETE_JAVA_VERSION "$distro_link" + download_distro $platform $architecture $CONCRETE_JAVA_VERSION "$distro_link" else - CONCRETE_JAVA_VERSION=$(find_latest_cached $platform $JAVA_VERSION) - fi + CONCRETE_JAVA_VERSION=$(find_latest_cached $platform $architecture $JAVA_VERSION) + fi fi else if [[ -z $JAVA_VERSION ]]; then - distro_info=$(fetch_distro_info $platform $LATEST_LTS) + distro_info=$(fetch_distro_info $platform $architecture $LATEST_LTS) CONCRETE_JAVA_VERSION=$(find_latest_version "$distro_info" $LATEST_LTS) else - distro_info=$(fetch_distro_info $platform $JAVA_VERSION_BASE) + distro_info=$(fetch_distro_info $platform $architecture $JAVA_VERSION_BASE) CONCRETE_JAVA_VERSION=$(find_latest_version "$distro_info" $JAVA_VERSION) fi - if [[ ! $(find_latest_cached $platform $CONCRETE_JAVA_VERSION) ]]; then + if [[ ! $(find_latest_cached $platform $architecture $CONCRETE_JAVA_VERSION) ]]; then distro_link=$(find_distro_link "$distro_info" $CONCRETE_JAVA_VERSION) - download_distro $platform $CONCRETE_JAVA_VERSION "$distro_link" + download_distro $platform $architecture $CONCRETE_JAVA_VERSION "$distro_link" fi fi } # actually ensure required distro is in cache for target in ${TARGETS_TO_CACHE[@]}; do - ensure_distro_cached $target + ensure_distro_cached $target $X64 done +if [[ $THIS_MACHINE == $AARCH64 ]]; then + ensure_distro_cached $THIS_PLATFORM $AARCH64 +fi + UNPACKED_SUBDIR="distro" -# ensures required distro uncompressed +# ensures required distro uncompressed function ensure_distro_unpacked() { local platform=$1 - local version=$2 - local download_dir=$JAVA_DOWNLOAD_PATH/$platform/$version + local architecture=$2 + local version=$3 + local download_dir=$JAVA_DOWNLOAD_PATH/$platform/$architecture/$version local unpacked_dir=$download_dir/$UNPACKED_SUBDIR if [[ ! -e $download_dir/$MARKER_UNPACKED ]]; then echo "Uncompressing $JVM_IMPL-$JAVA_DISTRO_TYPE-$version-$platform" @@ -607,12 +663,17 @@ function ensure_distro_unpacked() { fi } -# actually ensure required distro uncompressed +# actually ensure required distro uncompressed for target in ${TARGETS[@]}; do - ensure_distro_unpacked $target $CONCRETE_JAVA_VERSION + ensure_distro_unpacked $target $X64 $CONCRETE_JAVA_VERSION done -JDK_PATH=$JAVA_DOWNLOAD_PATH/$THIS_PLATFORM/$CONCRETE_JAVA_VERSION/$UNPACKED_SUBDIR +# actually ensure required distro for build is uncompressed when it is not x64 +if [[ $THIS_MACHINE == $AARCH64 ]]; then + ensure_distro_unpacked $THIS_PLATFORM $AARCH64 $CONCRETE_JAVA_VERSION +fi + +JDK_PATH=$JAVA_DOWNLOAD_PATH/$THIS_PLATFORM/$THIS_MACHINE/$CONCRETE_JAVA_VERSION/$UNPACKED_SUBDIR JLINK=$JDK_PATH/bin/jlink JDEPS=$JDK_PATH/bin/jdeps @@ -620,18 +681,48 @@ JDEPS=$JDK_PATH/bin/jdeps if [[ $JAVA_DISTRO_TYPE == $DISTRO_TYPE_JDK ]]; then echo "Analyzing dependencies..." # TODO check for errors - MODULES=$("$JDEPS" --print-module-deps "$JAR" | grep -v Warning) + # TODO If JAVA_VERSION is not an INT it will throw an error + if [ -n "$CLASS_PATH" ] + then + echo "Using given classpaths: $CLASS_PATH" + MODULES=$($JDEPS --class-path $CLASS_PATH --ignore-missing-deps --list-deps --multi-release $JAVA_VERSION_BASE $JAR | awk '{print $1}' | grep -Ev '^(Warning|Error:|Not\sfound|.*\.jar$|ch\.|com\.|org\.)' | sed 's|/.*||' | sort -u | paste -sd, -) + elif [ "$AUTO_CLASS_PATH" ] + then + echo "Extracting jar file to get classpath" + unzip -q "${JAR}" -d "${EXTRACTED_JAR_PATH}" + echo "Fetching modules" + MODULES=$($JDEPS --ignore-missing-deps --print-module-deps --recursive --multi-release $JAVA_VERSION_BASE -quiet --class-path=${EXTRACTED_JAR_PATH}/* --module-path=${EXTRACTED_JAR_PATH}/* $JAR | grep -v Warning) + elif [ "$SPRING_BOOT_APPLICATION" ] + then + echo "Extracting Spring Boot jar file to get classpath" + unzip -q "${JAR}" -d "${EXTRACTED_JAR_PATH}" + echo "Fetching modules" + MODULES=$($JDEPS --ignore-missing-deps --print-module-deps --recursive --multi-release $JAVA_VERSION_BASE -quiet --class-path=${EXTRACTED_JAR_PATH}/BOOT-INF/lib/* --module-path=${EXTRACTED_JAR_PATH}/BOOT-INF/lib/BOOT-INF/lib/* $JAR | grep -v Warning) + else + echo "Fetch modules with default behavior" + MODULES=$("$JDEPS" --print-module-deps --ignore-missing-deps --multi-release $JAVA_VERSION_BASE "$JAR" | grep -v Warning) + fi + if [ -n "$ADD_MODULES" ]; then + echo "Adding additional modules to optimized JDK: $ADD_MODULES" + MODULES=$ADD_MODULES,$MODULES + fi + echo "Collected modules: $MODULES" fi # creates minimized runtime for the platform function create_optimized_runtime() { local platform=$1 - local jmods=$JAVA_DOWNLOAD_PATH/$platform/$CONCRETE_JAVA_VERSION/$UNPACKED_SUBDIR/jmods + local machine=$2 + local jmods=$JAVA_DOWNLOAD_PATH/$platform/$machine/$CONCRETE_JAVA_VERSION/$UNPACKED_SUBDIR/jmods + local strip_debug=strip-debug echo "Creating minimal runtime for $platform..." + if [[ $JAVA_VERSION_BASE -ge 13 ]]; then + strip_debug=strip-java-debug-attributes + fi "$JLINK" \ --no-header-files \ --no-man-pages \ - --strip-debug \ + --$strip_debug \ --module-path "$jmods" \ --add-modules $MODULES \ --output "$BUNDLES_PATH/$platform/$BUNDLED_DISTRO_SUBDIR" @@ -641,12 +732,20 @@ function create_optimized_runtime() { # creates warp bundle for the platform function create_bundle() { local platform=$1 + local machine=$2 + + if [[ $SILENT ]] && [[ $platform == $WIN ]]; then + JAVA_EXEC=javaw + else + JAVA_EXEC=java + fi + case $JAVA_DISTRO_TYPE in $DISTRO_TYPE_JDK) - create_optimized_runtime $platform + create_optimized_runtime $platform $machine ;; $DISTRO_TYPE_JRE) - mkdir -p "$BUNDLES_PATH/$platform/$BUNDLED_DISTRO_SUBDIR" + mkdir -p "$BUNDLES_PATH/$platform/$machine/$BUNDLED_DISTRO_SUBDIR" cp -r "$JAVA_DOWNLOAD_PATH/$platform/$CONCRETE_JAVA_VERSION/$UNPACKED_SUBDIR"/* \ "$BUNDLES_PATH/$platform/$BUNDLED_DISTRO_SUBDIR" ;; @@ -664,7 +763,7 @@ function create_bundle() { rm -rf "$BUNDLES_PATH" # actually create bundles for all targets for target in ${TARGETS[@]}; do - create_bundle $target + create_bundle $target $X64 done # creates binaries and archives for all targets @@ -675,8 +774,11 @@ function warp_targets() { echo "Warping for $LIN..." mkdir -p "$WARPED_TEMP_PATH/$LIN" warp-packer \ + pack \ + --unique-id \ + $PREFIX \ --arch linux-x64 \ - --input_dir "$BUNDLES_PATH/$LIN" \ + --input-dir "$BUNDLES_PATH/$LIN" \ --exec "$LAUNCHER_NAME.sh" \ --output "$WARPED_TEMP_PATH/$LIN/$APP_NAME" \ &> /dev/null @@ -693,17 +795,25 @@ function warp_targets() { echo "Warping for $MAC..." mkdir -p "$WARPED_TEMP_PATH/$MAC" warp-packer \ + pack \ + --unique-id \ + $PREFIX \ --arch macos-x64 \ - --input_dir "$BUNDLES_PATH/$MAC" \ + --input-dir "$BUNDLES_PATH/$MAC" \ --exec "$LAUNCHER_NAME.sh" \ --output "$WARPED_TEMP_PATH/$MAC/$APP_NAME" \ &> /dev/null fail_if $? "Failed to warp for $MAC" + echo "Creating runnable $MAC application bundle" + mkdir "$WARPED_TEMP_PATH/$MAC/$APP_NAME.app" + cp "$WARPED_TEMP_PATH/$MAC/$APP_NAME" "$WARPED_TEMP_PATH/$MAC/$APP_NAME.app" echo "Archiving for $MAC..." - tar -C "$WARPED_TEMP_PATH/$MAC" -czf "$WARPED_TEMP_PATH/$APP_NAME-$MAC-x64.tar.gz" "$APP_NAME" + tar -C "$WARPED_TEMP_PATH/$MAC" -czf "$WARPED_TEMP_PATH/$APP_NAME-$MAC-x64.tar.gz" "$APP_NAME.app" fail_if $? "Failed to make archive for $MAC" + mv "$WARPED_TEMP_PATH/$APP_NAME-$MAC-x64.tar.gz" "$WARPED_PATH/" mv "$WARPED_TEMP_PATH/$MAC/$APP_NAME" "$WARPED_PATH/$APP_NAME-$MAC-x64" - mv "$WARPED_TEMP_PATH/$APP_NAME-$MAC-x64.tar.gz" "$WARPED_PATH" + rm "$WARPED_TEMP_PATH/$MAC/$APP_NAME.app/$APP_NAME" + rmdir "$WARPED_TEMP_PATH/$MAC/$APP_NAME.app" rmdir "$WARPED_TEMP_PATH/$MAC" fi @@ -711,8 +821,11 @@ function warp_targets() { echo "Warping for $WIN..." mkdir -p "$WARPED_TEMP_PATH/$WIN" warp-packer \ + pack \ + --unique-id \ + $PREFIX \ --arch windows-x64 \ - --input_dir "$BUNDLES_PATH/$WIN" \ + --input-dir "$BUNDLES_PATH/$WIN" \ --exec "$LAUNCHER_NAME.cmd" \ --output "$WARPED_TEMP_PATH/$WIN/$APP_NAME.exe" \ &> /dev/null @@ -729,7 +842,7 @@ function warp_targets() { mv "$WARPED_TEMP_PATH/$WIN/$APP_NAME.exe" "$WARPED_PATH/$APP_NAME-windows-x64.exe" rmdir "$WARPED_TEMP_PATH/$WIN" fi - + rmdir "$WARPED_TEMP_PATH" }