diff --git a/.github/issue_template.md b/.github/issue_template.md index af25ee3..305af0a 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -1,9 +1,24 @@ I'm submitting a… -- [x] bug report + + +- [ ] bug report - [ ] feature request - [ ] other + + + **Short description of the issue/suggestion:** @@ -14,6 +29,7 @@ I'm submitting a… 2. [Second Step] 3. [Other Steps...] + **What is the expected behavior?** @@ -33,7 +49,12 @@ I'm submitting a… **Please tell us about your environment:** - universalJavaApplicationStub version: -- Mac OS version: +- macOS version: - Java version(s): -**Other information** (e.g. related issues, suggestions how to fix, links for us to have context) + +**Other information:** + + + + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6b26b45 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,114 @@ +name: Release + +# Trigger the workflow only on tags +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + + +jobs: + + draft_release: + name: Create draft release + runs-on: ubuntu-latest + + outputs: + release_id: ${{ steps.create_draft_release.outputs.id }} + upload_url: ${{ steps.create_draft_release.outputs.upload_url }} + + steps: + - name: Get version from tag + id: tag_name + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV + + - uses: actions/checkout@v2 + + - name: Get Changelog Entry + id: changelog_reader + uses: mindsers/changelog-reader-action@v2 + with: + version: ${{ env.RELEASE_VERSION }} + path: ./CHANGELOG.md + + - name: Create draft release + id: create_draft_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GH_API_PERSONAL_ACCESS_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + draft: true + prerelease: ${{ steps.changelog_reader.outputs.status == 'prereleased' }} + body: ${{ steps.changelog_reader.outputs.changes }} + + - name: ZIP uncompiled universalJavaApplicationStub + run: | + echo "Zipping uncompiled script..." + zip --junk-paths universalJavaApplicationStub-uncompiled.zip src/universalJavaApplicationStub + + - name: Upload release assets + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GH_API_PERSONAL_ACCESS_TOKEN }} + with: + upload_url: ${{ steps.create_draft_release.outputs.upload_url }} + asset_name: universalJavaApplicationStub-v${{ env.RELEASE_VERSION }}-source.zip + asset_path: ./universalJavaApplicationStub-uncompiled.zip + asset_content_type: application/zip + + + compile: + name: Compile the stub on ${{ matrix.os }} + needs: draft_release # we need to know the upload URL + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ macos-10.15 ] # macos-11.0 + + steps: + - uses: actions/checkout@v2 + + - name: Set env + run: echo "RELEASE_TAG=${GITHUB_REF:10}" >> $GITHUB_ENV + + - name: Install shc via HomeBrew + run: | + brew install shc + shc -h + + - name: Compile universalJavaApplicationStub + run: | + echo "Running shc..." + shc -r -f src/universalJavaApplicationStub + + - name: ZIP universalJavaApplicationStub binary + run: | + echo "Zipping binary..." + mv src/universalJavaApplicationStub.x universalJavaApplicationStub + rm src/universalJavaApplicationStub.x.c + zip --junk-paths universalJavaApplicationStub-${{ matrix.os }}.zip universalJavaApplicationStub + + - name: Upload release assets + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GH_API_PERSONAL_ACCESS_TOKEN }} + with: + upload_url: ${{ needs.draft_release.outputs.upload_url }} + asset_name: universalJavaApplicationStub-${{ env.RELEASE_TAG }}-binary-${{ matrix.os }}.zip + asset_path: ./universalJavaApplicationStub-${{ matrix.os }}.zip + asset_content_type: application/zip + + + publish_release: + name: Publish drafted release + needs: [ draft_release, compile ] + runs-on: ubuntu-latest + + steps: + - uses: eregon/publish-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GH_API_PERSONAL_ACCESS_TOKEN }} + with: + release_id: ${{ needs.draft_release.outputs.release_id }} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..34e07d9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,59 @@ +name: Tests and Shellcheck + +# Trigger the workflow on push or pull request +on: [push, pull_request] + + +jobs: + + tests: + name: Run bash function tests on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ macos-10.15 ] # macos-11.0 + + steps: + - uses: actions/checkout@v2 + + # Run the 'java-version-tester' script and show&save (`tee`) the output to a + # logfile; then grep the logfile for 'FAILED' entries which would cause grep + # to exit with 0; then run 'test' command and swap the grep exit code + # to return with 0 if grep doesn't match and return with 1 if it matches. + - name: Run function tests in java-version-tester.sh + run: | + echo "Running tests..." + bash test/java-version-tester.sh | tee test/java-version-tester.log + echo "Tests done. Checking for failures..." + test/check-log.sh test/java-version-tester.log FAILED + + + shellcheck: + name: Check bash syntax with shellcheck on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ macos-10.15 ] # macos-11.0 + + steps: + - uses: actions/checkout@v2 + + - name: Install shellcheck via HomeBrew + run: | + brew install shellcheck + shellcheck -V + + # Test with shellcheck for bash syntax errors which should fail the build. + # Until https://github.com/koalaman/shellcheck/issues/524 is implemented, + # grep for errors and fail manually. + # + # Show & save the output via `tee` to a logfile; then grep the logfile for + # 'error:' entries which would cause grep to exit with 0; then run 'test' + # command and swap the grep exit code to return with 0 if grep doesn't match + # and return with 1 if it matches + - name: Run shellcheck on the launcher stub + run: | + echo "Running shellcheck..." + shellcheck -s bash -f gcc src/universalJavaApplicationStub | tee test/shellcheck.log + echo "Shellcheck done. Checking for errors..." + test/check-log.sh test/shellcheck.log "error:" diff --git a/.gitignore b/.gitignore index e43b0f9..6053715 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ .DS_Store + +# shc compiler +*.x +*.x.c \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fb0a0e0..0000000 --- a/.travis.yml +++ /dev/null @@ -1,42 +0,0 @@ -language: generic - -# run on different Mac OS X versions -# https://docs.travis-ci.com/user/reference/osx/#OS-X-Version -matrix: - include: - # OS X 10.11 - - os: osx - osx_image: xcode8 - # OS X 10.12 - - os: osx - osx_image: xcode9 - # OS X 10.13 - - os: osx - osx_image: xcode9.3 - - -# Homebrew needs ruby 2.3 and should be updated everytime to use the latest -# version of shellcheck -before_install: - - rvm install 2.3.0 - - brew update - -install: - - brew install shellcheck - -before_script: - - sw_vers - - shellcheck -V - - -# run the 'java-version-tester' script and show&save (`tee`) the output to a -# logfile; then grep the logfile for 'FAILED' entries which would cause grep -# to exit with 0; then run 'test' command and swap the grep exit code -# to return with 0 if grep doesn't match and return with 1 if it matches -script: - - bash test/java-version-tester.sh | tee test/java-version-tester.log - - cat test/java-version-tester.log | grep FAILED ; test $? -eq 1 - # test with shellcheck for bash syntax errors which should fail the build - # grep for errors until shellcheck issue / feature request - # https://github.com/koalaman/shellcheck/issues/524 is implemented - - shellcheck -s bash -f gcc src/universalJavaApplicationStub | grep "error:" ; test $? -eq 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b301ae..e07dd0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,109 +1,226 @@ -ChangeLog ---------- - -### v3.0.2 (2018-04-12) -* Bugfix: fix typo in JVMOptions expansion on java exec call (PR #63, Thanks to @michaelweiser for his contribution) -* Added a basic Travis CI build pipeline running a `shellcheck` test for errors and executing the basic testsuite - -### v3.0.1 (2018-03-10) -* Bugfix: remove build number from JVM version number when creating comparable version number or extracting major version (fixes #61) - -### v3.0.0 (2018-02-25) -* Completeley overhauled algorithm for JVM detection (JRE and JDK) - * JDK has no longer precedence over JRE - * All Java Virtual Machines on the system are taken into account - * See Readme section 'How the script works' for more details -* NEW special syntax in Plist key `JVMVersion` to specify a maximum JVM version requirement in addition to the minimum requirement. - * See issue #51 for examples -* Support `JVMVersion` also in Oracle PList style (#59) -* Implemented logging to `syslog` facility which can be viewed via `Console.app` (#49) -* Translation of messages to Chinese (PR #55, Thanks to @acely for his contribution) -* Added a table with 'Supported PList keys' to the Readme file -* Refactoring of functions, bash syntax, etc... (#46, #50, #56) -* Bugfix: pass JVM options with spaces correctly to the java exec call (#14) -* Bugfixes: better handling of MainClass arguments with spaces (#57, #58) -* Bugfixes: issues #47, #48, #52 - -### v2.1.0 (2017-07-28) -* Support for Java 9 which introduces a new version number schema (fixes #43) - -### v2.0.2 (2017-04-23) -* Bugfix: do NOT expand/evaluate the default Oracle Classpath (`App.app/Contents/Java/*`) (PR #42, Thanks to @mguessan for his contribution) - -### v2.0.1 (2016-11-27) -* Bugfix for regression in argument passthru introduced in 2.0.0 (fixes #39) - -### v2.0.0 (2016-11-20) -* Localization of messages (English, German, French) (fixes #27 / PR #30, Thanks to @ebourg for his contribution) -* Improve the version of Java reported in the error messages (fixes #28) -* Send to java.com when the version of Java installed is too old (fixes #29) -* Bugfix for parsing 3-digit java release/build numbers (e.g. for 1.8.0_101) (fixes #36) -* Better search algorithm for specific Java version (fixes #35) -* Use highest available Java version for execution if `JVMversion` is NOT specified (fixes #37) - * matches the new behaviour for when `JVMversion` IS specified (#35) -* Switch to `/bin/bash` with changes in #35 -* Add support for arrays of VMOptions in Apple style Info.plists (PR #25, Thanks to @spectre683 for his contribution) -* Pass command line arguments through to the application (PR #31, Thanks to @dbankieris for his contribution) -* Allow specifying `$JAVA_HOME` relative to `$AppPackageFolder` (fixes #7 / PR #26, Thanks to @toonetown for his contribution) - * This allows you to set a relative `$JAVA_HOME` via the `` Plist key - * Which means you can bundle a custom version of Java inside your app! - -### v1.0.1 (2015-11-02) -* Improved display error message with applescript (PR #22, Thanks to @ygesnel for his initial contribution) -* Reorder search for Java VM locations when specific JVM version is required (PR #22, Thanks to @yoe for his contribution) - -### v1.0.0 (2015-10-08) -* Support for a splash file (PR #19) - * For details see https://github.com/tofi86/universalJavaApplicationStub/pull/19 -* Also search for JRE's (not only for JDK's) when a specific JVMversion is required (fixes #15) -* Expand variables like $APP_ROOT or $JAVAROOT in Apple formatted Plist files so as to match the Oracle format (PR #17, Thanks to @cxbrooks for his contribution) -* support for `JVMClasspath` in Oracle formatted Plist files (PR #16, Thanks to @pedrofvteixeira for his contribution) -* Mark script as executable (PR #18, Thanks to @yoe for his contribution) -* bugfix: fix JVMDefaultOptions when retrieved from array -* bugfix: hide the retrieved java home path in stdout - -### v0.9.0 (2015-05-15) -* added support for `JavaX` Plist key (fixes #9) - -### v0.8.1 (2015-03-26) -* Bugfix for `JVMVersion` key present but no JVMs in `/usr/libexec/java_home` - -### v0.8.0 (2015-02-22) -* support for `JVMVersion` key (fixes #13, Thanks to @Dylan-M for his contribution) -* use `$HOME` instead of `~` to set the users home directory (fixes #11) -* WorkingDirectory: improved substitution of variables ($JAVAROOT, $APP_PACKAGE, $USER_HOME) (fixes #12) -* use different non-zero exit codes - -### v0.7.0 (2014-10-12) -* read ClassPath from ApplePlist in either Array or String style (PR #5, Thanks to Philipp Holzschneider for his contribution) -* read StartOnMainThread (issue #4, Thanks to @wrstlbrnft for his contribution) - -### v0.6.3 (2014-07-31) -* check Info.plist for Apple style Java keys. Better indicator to distinguish between Apple or Oracle parsing... - -### v0.6.2 (2014-07-28) -* minor code refactoring and bugfixes - -### v0.6.1 (2014-07-27) -* Standard Working Directory for Apple PList apparently is the AppRoot directory - -### v0.6 *(2014-07-12)* -* also catch fixed paths for Plist key `JVMWorkDir` *(thanks @dpolivaev)* - -### v0.5 *(2014-06-30)* -* bugfix for pathes / App bundles containing spaces (#2) - -### v0.4 *(2014-06-30)* -* read and set WorkingDirectory based on the key in `Info.plist` (#1) - * interpret the 3 different values $JAVAROOT, $APP_PACKAGE, $USER_HOME - * fallback to root / as standard - -### v0.3 *(2014-03-16)* -* enable drag&drop to the dock icon - -### v0.2 *(2014-03-16)* -* trim whitespace from variables and commandline -* don't show errors in output for Info.plist querying - -### v0.1 *(2014-03-09)* -* initial release of 'universalJavaApplicationStub' +# 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). + + +## [3.3.0] - 2023-02-04 + +PLEASE NOTE: This is the last official release as I'm going to sunset this project for personal reasons. + +### Added +- Support country specific locales such as Brazilian Portuguese (`pt-BR`) +- Translation of messages to Brazilian Portuguese (#115, Thanks to @israelins85 for his contribution) + +### Changed +- Changed Adopt OpenJDK link and name to Adoptium + +### Removed +- Option to fund this project + + +## [3.2.0] - 2021-02-21 +### Added +- Also expand variables `$APP_PACKAGE`, `$JAVAROOT` and `$USER_HOME` in Oracle style PList files +- Also expand variable `$APP_ROOT` in Apple style PList files +- Oracle JVMDefaultOptions key: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#99) + +### Changed +- Improved language detection by reading the user preferred languages from the macOS System Preferences instead of using the system locale (#101, thanks to @Flexperte for his valuable feedback) +- Improved logging for JAVA_HOME detection (#100) + +### Fixed +- Fixed a crash when `/usr/libexec/java_home` returns no JVMs (#93) + + +## [3.1.0] - 2021-01-07 +### Added +- Support for macOS 11.0 "Big Sur" (#91) +- Support for JDK's installed via SDKMAN! (#95) +- Apple `VMOptions` key: expand variables `$APP_PACKAGE`, `$JAVAROOT`, `$USER_HOME` (#84) +- Translation of messages to Spanish (PR #88, Thanks to @fvarrui for his contribution) +- Added a CI action for automated releases that builds and publishes binary releases with `shc` (#85, #87, PR #96) + +### Changed +- Suppress empty `-splash` option if no splash image is specified in `Info.plist` (#94) +- Replace Travis CI with GitHub Actions CI + + +## [3.0.6] - 2020-03-19 +### Fixed +- Fixed an issue related to Java 4-8 version number detection (PR #81, Thanks to @thatChadM for his contribution) + + +## [3.0.5] - 2019-12-15 +### Added +- If java is missing, offer a choice between Oracle and AdoptOpenJDK download buttons (#78) +- Support Array style `Java:Arguments` for Apple Plist style (#76) + +### Fixed +- Bugfix: do not crash if `CFBundleIconFile` is provided without ".icns" extension (#75) +- Minor French translation fix (PR #73, Thanks to @ebourg for his contribution) + + +## [3.0.4] - 2018-08-24 +### Fixed +- Bugfix: Variables `$APP_PACKAGE`, `$JAVAROOT`, `$USER_HOME` in `JVMOptions` key (Oracle) or `Java:Properties` key (Apple) were not expanded (#69) + +## [3.0.3] - 2018-07-29 +### Fixed +- Bugfix: changes for the new Java 10 `java -version` formatting (#66) + + +## [3.0.2] - 2018-04-12 +### Added +- Added a basic Travis CI build pipeline running a `shellcheck` test for errors and executing the basic testsuite + +### Fixed +- Bugfix: fix typo in JVMOptions expansion on java exec call (PR #63, Thanks to @michaelweiser for his contribution) + + +## [3.0.1] - 2018-03-10 +### Fixed +- Bugfix: remove build number from JVM version number when creating comparable version number or extracting major version (fixes #61) + + +## [3.0.0] - 2018-02-25 +### Added +- Completeley overhauled algorithm for JVM detection (JRE and JDK) + - JDK has no longer precedence over JRE + - All Java Virtual Machines on the system are taken into account + - See Readme section 'How the script works' for more details +- NEW special syntax in Plist key `JVMVersion` to specify a maximum JVM version requirement in addition to the minimum requirement. + - See issue #51 for examples +- Support `JVMVersion` also in Oracle PList style (#59) +- Implemented logging to `syslog` facility which can be viewed via `Console.app` (#49) +- Translation of messages to Chinese (PR #55, Thanks to @acely for his contribution) +- Added a table with 'Supported PList keys' to the Readme file +- Refactoring of functions, bash syntax, etc... (#46, #50, #56) + +### Fixed +- Bugfix: pass JVM options with spaces correctly to the java exec call (#14) +- Bugfixes: better handling of MainClass arguments with spaces (#57, #58) +- Bugfixes: issues #47, #48, #52 + + +## [2.1.0] - 2017-07-28 +### Added +- Support for Java 9 which introduces a new version number schema (fixes #43) + + +## [2.0.2] - 2017-04-23 +### Fixed +- Bugfix: do NOT expand/evaluate the default Oracle Classpath (`App.app/Contents/Java/*`) (PR #42, Thanks to @mguessan for his contribution) + + +## [2.0.1] - 2016-11-27 +### Fixed +- Bugfix for regression in argument passthru introduced in 2.0.0 (fixes #39) + + +## [2.0.0] - 2016-11-20 +### Added +- Localization of messages (English, German, French) (fixes #27 / PR #30, Thanks to @ebourg for his contribution) +- Improve the version of Java reported in the error messages (fixes #28) +- Send to java.com when the version of Java installed is too old (fixes #29) +- Pass command line arguments through to the application (PR #31, Thanks to @dbankieris for his contribution) +- Add support for arrays of VMOptions in Apple style Info.plists (PR #25, Thanks to @spectre683 for his contribution) +- Allow specifying `$JAVA_HOME` relative to `$AppPackageFolder` (fixes #7 / PR #26, Thanks to @toonetown for his contribution) + - This allows you to set a relative `$JAVA_HOME` via the `` Plist key + - Which means you can bundle a custom version of Java inside your app! + +### Changed +- Better search algorithm for specific Java version (fixes #35) +- Use highest available Java version for execution if `JVMversion` is NOT specified (fixes #37) + - matches the new behaviour for when `JVMversion` IS specified (#35) +- Switch to `/bin/bash` with changes in #35 + +### Fixed +- Bugfix for parsing 3-digit java release/build numbers (e.g. for 1.8.0_101) (fixes #36) + + +## [1.0.1] - 2015-11-02 +### Changed +- Improved display error message with applescript (PR #22, Thanks to @ygesnel for his initial contribution) +- Reorder search for Java VM locations when specific JVM version is required (PR #22, Thanks to @yoe for his contribution) + + +## [1.0.0] - 2015-10-08 +### Added +- Support for a splash file (PR #19) + - For details see https://github.com/tofi86/universalJavaApplicationStub/pull/19 +- Expand variables like $APP_ROOT or $JAVAROOT in Apple formatted Plist files so as to match the Oracle format (PR #17, Thanks to @cxbrooks for his contribution) +- Support for `JVMClasspath` in Oracle formatted Plist files (PR #16, Thanks to @pedrofvteixeira for his contribution) + +### Fixed +- Also search for JRE's (not only for JDK's) when a specific JVMversion is required (fixes #15) +- Mark script as executable (PR #18, Thanks to @yoe for his contribution) +- Fix JVMDefaultOptions when retrieved from array +- Hide the retrieved java home path in stdout + + +## [0.9.0] - 2015-05-15 +### Added +- Added support for `JavaX` Plist key (fixes #9) + + +## [0.8.1] - 2015-03-26 +### Fixed +- Bugfix for `JVMVersion` key present but no JVMs in `/usr/libexec/java_home` + + +## [0.8.0] - 2015-02-22 +### Added +- Support for `JVMVersion` key (fixes #13, Thanks to @Dylan-M for his contribution) + +### Changed +- Use `$HOME` instead of `~` to set the users home directory (fixes #11) +- WorkingDirectory: improved substitution of variables ($JAVAROOT, $APP_PACKAGE, $USER_HOME) (fixes #12) +- Use different non-zero exit codes + + +## [0.7.0] - 2014-10-12 +### Added +- Read ClassPath from ApplePlist in either Array or String style (PR #5, Thanks to Philipp Holzschneider for his contribution) +- Read StartOnMainThread (issue #4, Thanks to @wrstlbrnft for his contribution) + + +## [0.6.3] - 2014-07-31 +### Changed +- Check Info.plist for Apple style Java keys. Better indicator to distinguish between Apple or Oracle parsing... + +## [0.6.2] - 2014-07-28 +### Fixed +- Minor code refactoring and bugfixes + +## [0.6.1] - 2014-07-27 +### Changed +- Standard Working Directory for Apple PList apparently is the AppRoot directory + +## [0.6] - 2014-07-12 +### Fixed +- Also catch fixed paths for Plist key `JVMWorkDir` *(thanks @dpolivaev)* + +## [0.5] - 2014-06-30 +### Fixed +- Bugfix for pathes / App bundles containing spaces (#2) + +## [0.4] - 2014-06-30 +### Added +- Read and set WorkingDirectory based on the key in `Info.plist` (#1) + - interpret the 3 different values $JAVAROOT, $APP_PACKAGE, $USER_HOME + - fallback to root / as standard + +## [0.3] - 2014-03-16 +### Added +- Enable drag&drop to the dock icon + +## [0.2] - 2014-03-16 +### Fixed +- Trim whitespace from variables and commandline +- Don't show errors in output for Info.plist querying + +## [0.1] - 2014-03-09 +- Initial release of 'universalJavaApplicationStub' diff --git a/LICENSE b/LICENSE index fe1f190..378f79d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2018 Tobias Fischer +Copyright (c) 2014-2023 Tobias Fischer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3235c5f..2eb7842 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ universalJavaApplicationStub ============================ -[![Build Status](https://travis-ci.org/tofi86/universalJavaApplicationStub.svg?branch=master)](https://travis-ci.org/tofi86/universalJavaApplicationStub) [![Current release](https://img.shields.io/github/release/tofi86/universalJavaApplicationStub.svg)](https://github.com/tofi86/universalJavaApplicationStub/releases) [![Join the chat at https://gitter.im/tofi86/universalJavaApplicationStub](https://badges.gitter.im/tofi86/universalJavaApplicationStub.svg)](https://gitter.im/tofi86/universalJavaApplicationStub?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +![Tests and Shellcheck](https://github.com/tofi86/universalJavaApplicationStub/workflows/Tests%20and%20Shellcheck/badge.svg) [![Current release](https://img.shields.io/github/release/tofi86/universalJavaApplicationStub.svg)](https://github.com/tofi86/universalJavaApplicationStub/releases) -A BASH based *JavaApplicationStub* for Java Apps on Mac OS X that works with both Apple's and Oracle's plist format. It is released under the [MIT License](https://github.com/tofi86/universalJavaApplicationStub/blob/master/LICENSE). +A BASH based _launcher stub_ for Java based macOS Apps that works with both Apple's and Oracle's plist format. It is released under the [MIT License](https://github.com/tofi86/universalJavaApplicationStub/blob/master/LICENSE). -See the [CHANGELOG](https://github.com/tofi86/universalJavaApplicationStub/blob/master/CHANGELOG.md) for a Release History and feature details. +📃 🔄 See the [CHANGELOG](https://github.com/tofi86/universalJavaApplicationStub/blob/master/CHANGELOG.md) for a Release History and feature details. + +🐛 🔥 Report _Issues_ at the [GitHub Issues Page](https://github.com/tofi86/universalJavaApplicationStub/issues). + +🤔 ❓ If you have a _general question_ about how a feature works or would like to _share an idea_ or a _usecase for this project_, then please use the [GitHub Discussions Page](https://github.com/tofi86/universalJavaApplicationStub/discussions). Why @@ -104,6 +108,8 @@ Use whichever ANT task you like: * Oracle's opensource ["Appbundler"](https://java.net/projects/appbundler) *(seems to be dead)* * or [*infinitekind*'s fork](https://bitbucket.org/infinitekind/appbundler/overview) +Or build the App bundle statically from scratch... + ### JarBundler (≥ v3.3) example Download the latest JarBundler release [from its github repo](https://github.com/UltraMixer/JarBundler). @@ -149,19 +155,86 @@ You should get a fully functional Mac Application Bundle working with both Java Supported PList keys -------------------- -| Function | Apple PList key | Oracle PList key | -|---------------------------------|------------------------|-----------------------| -| **App Name** (Dock Name) | `:CFBundleName` | `:CFBundleName` | -| **App Icon** (Dock Icon) | `:CFBundleIconFile` | `:CFBundleIconFile` | -| **Working Directory** | `:Java(X):WorkingDirectory`
fallback to `name.app/`
support for variables `$APP_PACKAGE`, `$JAVAROOT`, `$USER_HOME` | *not supported*
default: `name.app/Contents/Java/` | -| **Java Min/Max[*](https://github.com/tofi86/universalJavaApplicationStub/issues/51) Version Requirement** | `:Java(X):JVMVersion` | `:JVMVersion` | -| **Java ClassPath** (`-cp …`) | `:Java(X):ClassPath` | `:JVMClassPath` | -| **Java Main Class** | `:Java(X):MainClass` | `:JVMMainClassName` | -| **Splash Image** (`-splash:…`) | `:Java(X):SplashFile` | `:JVMSplashFile` | -| **Java VM Options** (`-X…`) | `:Java(X):VMOptions` | `:JVMDefaultOptions` | -| **`-XstartOnFirstThread`** [*](https://stackoverflow.com/questions/28149634/what-does-the-xstartonfirstthread-vm-argument-do-mean) | `:Java(X):StartOnMainThread` | *not supported* | -| **Java Properties** (`-D…`) | `:Java(X):Properties` | `:JVMOptions` | -| **Main Class Arguments** | `:Java(X):Arguments` | `:JVMArguments` | +| Function | Apple PList key | Oracle PList key | +|--------------------------------------------|------------------------|-----------------------| +| **App Name** (Dock Name) | `:CFBundleName` | `:CFBundleName` | +| **App Icon** (Dock Icon) | `:CFBundleIconFile` | `:CFBundleIconFile` | +| **Working Directory** 🌟 | `:Java(X):WorkingDirectory`
fallback to `name.app/ | *not supported*
default: `name.app/Contents/Java/` | +| **Java Min/Max[★](https://github.com/tofi86/universalJavaApplicationStub/issues/51) Version Requirement** | `:Java(X):JVMVersion` | `:JVMVersion` | +| **Java ClassPath** (`-cp …`) 🌟 | `:Java(X):ClassPath` | `:JVMClassPath` | +| **Java Main Class** | `:Java(X):MainClass` | `:JVMMainClassName` | +| **Splash Image** (`-splash:…`) | `:Java(X):SplashFile` | `:JVMSplashFile` | +| **Java VM Options** (`-X…`) 🌟 | `:Java(X):VMOptions` | `:JVMDefaultOptions` | +| **`-XstartOnFirstThread`** [★](https://stackoverflow.com/questions/28149634/what-does-the-xstartonfirstthread-vm-argument-do-mean) | `:Java(X):StartOnMainThread` | *not supported* | +| **Java Properties** (`-D…`) 🌟 | `:Java(X):Properties` | `:JVMOptions` | +| **Main Class Arguments** 🌟 | `:Java(X):Arguments` | `:JVMArguments` | + +🌟 Variable placeholders `$APP_PACKAGE`, `$APP_ROOT`, `$JAVAROOT`, `$USER_HOME` get expanded in these contexts. + +### Specify min/max Java requirement + +Since v3.0 ([#51](https://github.com/tofi86/universalJavaApplicationStub/issues/51)) + +Use `Java(X):JVMVersion` (Apple style) or `:JVMVersion` (Oracle style) with the following values: + +* `1.8` or `1.8*` for Java 8 +* `1.8+` for Java 8 or higher +* `1.7;1.8*` for Java 7 or 8 +* `1.8;9.0` for Java 8* up to exactly 9.0 (but not 9.0.*) +* `1.8;9.0*` for Java 8* and 9.0.* but not 9.1.* + + +### Bundle a JRE/JDK with your app + +You can use the Plist key `LSEnvironment` to export and set the `$JAVA_HOME` environment variable relative to your App's root directory: + +```xml +LSEnvironment + + JAVA_HOME + Contents/Frameworks/jdk8u232-b09-jre/Contents/Home + +``` + + +Use a compiled binary for macOS 10.15 and above +----------------------------------------------- + +Starting with macOS 10.15 Apple by default prevents access to _Protected Resources_ like the user's _Download_, _Documents_ or _Desktop_ folders and shows a security dialog which the user has to accept before access is granted. + +When using `javax.swing.JFileChooser` in your application, which supports these kinds of security dialogs (interestingly `java.awt.FileDialog` does not!), you should use a compiled binary of the `universalJavaApplicationStub` script instead of the plain bash script. See [issue #85](https://github.com/tofi86/universalJavaApplicationStub/issues/85) for more details. + +Starting with version 3.1.0 we provide pre-built binaries on the [Releases page](https://github.com/tofi86/universalJavaApplicationStub/releases/) which are automatically compiled with [`shc`](https://github.com/neurobin/shc) via GitHub Actions CI. + +Additionaly we recommend you set _Usage Description_ Plist keys as described further below. + + +Recommended additional Plist keys +--------------------------------- + +### `NSAppleEventsUsageDescription` + +Starting with Mac OS 10.14 users may be confronted with an additional system security dialog before any warning dialog of this stub is shown. See [issue #77](https://github.com/tofi86/universalJavaApplicationStub/issues/77) for more details. + +This happens because the warning dialogs of this launcher stub are displayed with AppleScript. + +It's recommended to at least set the following Plist key in order to display a descriptive message to the user, why he should grant the app system access: + +```xml +NSAppleEventsUsageDescription +There was an error while launching the application. Please click OK to display a dialog with more information or cancel and view the syslog for details. +``` + +### Access to "Protected Resources" + +If your app requires access to _Protected Resources_ like the user's _Download_, _Documents_ or _Desktop_ folders, there are [a couple more properties](https://developer.apple.com/documentation/bundleresources/information_property_list/protected_resources) to add in your Plist file for setting a _Usage Description_: + +* [`NSDownloadsFolderUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nsdownloadsfolderusagedescription) +* [`NSDocumentsFolderUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nsdocumentsfolderusagedescription) +* [`NSDesktopFolderUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nsdesktopfolderusagedescription) +* and maybe more... + +This may be extra important when using `javax.swing.JFileChooser` in your application. See [issue #85](https://github.com/tofi86/universalJavaApplicationStub/issues/85) for more details. Logging diff --git a/src/universalJavaApplicationStub b/src/universalJavaApplicationStub index 6444b8c..43cb683 100755 --- a/src/universalJavaApplicationStub +++ b/src/universalJavaApplicationStub @@ -11,14 +11,14 @@ # # # @author Tobias Fischer # # @url https://github.com/tofi86/universalJavaApplicationStub # -# @date 2018-04-12 # -# @version 3.0.2 # +# @date 2023-02-04 # +# @version 3.3.0 # # # ################################################################################## # # # The MIT License (MIT) # # # -# Copyright (c) 2014-2018 Tobias Fischer # +# Copyright (c) 2014-2023 Tobias Fischer # # # # Permission is hereby granted, free of charge, to any person obtaining a copy # # of this software and associated documentation files (the "Software"), to deal # @@ -166,6 +166,8 @@ if [ $exitcode -eq 0 ]; then JavaFolder="${AppleJavaFolder}" ResourcesFolder="${AppleResourcesFolder}" + # set expandable variables + APP_ROOT="${AppPackageFolder}" APP_PACKAGE="${AppPackageFolder}" JAVAROOT="${AppleJavaFolder}" USER_HOME="$HOME" @@ -180,7 +182,7 @@ if [ $exitcode -eq 0 ]; then # AppPackageRoot is the standard WorkingDirectory when the script is started WorkingDirectory="${AppPackageRoot}" fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME WorkingDirectory=$(eval echo "${WorkingDirectory}") @@ -203,7 +205,7 @@ if [ $exitcode -eq 0 ]; then else JVMClassPath=${JVMClassPath_RAW} fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") # read the JVM Options in either Array or String style @@ -213,6 +215,8 @@ if [ $exitcode -eq 0 ]; then else JVMDefaultOptions=${JVMDefaultOptions_RAW} fi + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#84) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") # read StartOnMainThread and add as -XstartOnFirstThread JVMStartOnMainThread=$(plist_get_java ':StartOnMainThread') @@ -220,9 +224,14 @@ if [ $exitcode -eq 0 ]; then JVMDefaultOptions+=" -XstartOnFirstThread" fi - # read the JVM Arguments as an array and retain spaces + # read the JVM Arguments in either Array or String style (#76) and retain spaces IFS=$'\t\n' - MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + MainArgs_RAW=$(plist_get_java ':Arguments' | xargs) + if [[ $MainArgs_RAW == *Array* ]] ; then + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g'))) + else + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + fi unset IFS # post processing of the array follows further below... @@ -240,7 +249,11 @@ else ResourcesFolder="${OracleResourcesFolder}" WorkingDirectory="${OracleJavaFolder}" + # set expandable variables APP_ROOT="${AppPackageFolder}" + APP_PACKAGE="${AppPackageFolder}" + JAVAROOT="${OracleJavaFolder}" + USER_HOME="$HOME" # read the MainClass name JVMMainClass="$(plist_get ':JVMMainClassName')" @@ -258,12 +271,12 @@ else JVMClassPath_RAW=$(plist_get ':JVMClassPath') if [[ $JVMClassPath_RAW == *Array* ]] ; then JVMClassPath=.$(plist_get ':JVMClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs) - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") elif [[ ! -z ${JVMClassPath_RAW} ]] ; then JVMClassPath=${JVMClassPath_RAW} - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMClassPath=$(eval echo "${JVMClassPath}") else @@ -272,8 +285,11 @@ else # Do NOT expand the default 'AppName.app/Contents/Java/*' classpath (#42) fi - # read the JVM Default Options + # read the JVM Default Options by parsing the :JVMDefaultOptions + # and pulling all values starting with a dash (-) JVMDefaultOptions=$(plist_get ':JVMDefaultOptions' | grep -o " \-.*" | tr -d '\n' | xargs) + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#99) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") # read the Main Arguments from JVMArguments key as an array and retain spaces (see #46 for naming details) IFS=$'\t\n' @@ -287,6 +303,18 @@ else fi +# (#75) check for undefined icons or icon names without .icns extension and prepare +# an osascript statement for those cases when the icon can be shown in the dialog +DialogWithIcon="" +if [ ! -z ${CFBundleIconFile} ]; then + if [[ ${CFBundleIconFile} == *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}" ]] ; then + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + elif [[ ${CFBundleIconFile} != *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}.icns" ]] ; then + CFBundleIconFile+=".icns" + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + fi +fi + # JVMVersion: post processing and optional splitting if [[ ${JVMVersion} == *";"* ]]; then @@ -297,14 +325,14 @@ fi stub_logger "[JavaRequirement] JVM minimum version: ${JVMVersion}" stub_logger "[JavaRequirement] JVM maximum version: ${JVMMaxVersion}" -# MainArgs: replace occurences of $APP_ROOT with its content +# MainArgs: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME MainArgsArr=() for i in "${MainArgs[@]}" do MainArgsArr+=("$(eval echo "$i")") done -# JVMOptions: replace occurences of $APP_ROOT with its content +# JVMOptions: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME JVMOptionsArr=() for i in "${JVMOptions[@]}" do @@ -315,14 +343,41 @@ done # internationalized messages ############################################ -LANG=$(defaults read -g AppleLocale) -stub_logger "[Language] $LANG" +# supported languages / available translations +stubLanguages=("de" "en" "es" "fr" "pt-BR" "zh") + +# read user preferred languages as defined in macOS System Preferences (#101) +stub_logger '[LanguageSearch] Checking preferred languages in macOS System Preferences...' +appleLanguages=($(defaults read -g AppleLanguages | grep '\s"' | tr -d ',' | xargs)) +stub_logger "[LanguageSearch] ... found [${appleLanguages[*]}]" + +language="" +for i in "${appleLanguages[@]}" +do + langValue="${i%-*}" + if [[ " ${stubLanguages[*]} " =~ " ${i} " ]]; then + stub_logger "[LanguageSearch] ... selected '$i' as the default language for the launcher stub" + language=${i} + break + elif [[ " ${stubLanguages[*]} " =~ " ${langValue} " ]]; then + stub_logger "[LanguageSearch] ... selected '$langValue' (from '$i') as the default language for the launcher stub" + language=${langValue} + break + fi +done +if [ -z "${language}" ]; then + language="en" + stub_logger "[LanguageSearch] ... selected fallback 'en' as the default language for the launcher stub" +fi +stub_logger "[Language] $language" + -# French localization -if [[ $LANG == fr* ]] ; then +case "${language}" in +# French +fr) MSG_ERROR_LAUNCHING="ERREUR au lancement de '${CFBundleName}'." MSG_MISSING_MAINCLASS="'MainClass' n'est pas spécifié.\nL'application Java ne peut pas être lancée." - MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." + MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version de Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java %s" MSG_JAVA_VERSION_OR_LATER="ou ultérieur" MSG_JAVA_VERSION_LATEST="(dernière mise à jour)" @@ -330,10 +385,12 @@ if [[ $LANG == fr* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="Merci de bien vouloir installer la version de Java requise." MSG_INSTALL_JAVA="Java doit être installé sur votre système.\nRendez-vous sur java.com et suivez les instructions d'installation..." MSG_LATER="Plus tard" - MSG_VISIT_JAVA_DOT_COM="Visiter java.com" + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTIUM="Java by Adoptium" + ;; -# German localization -elif [[ $LANG == de* ]] ; then +# German +de) MSG_ERROR_LAUNCHING="FEHLER beim Starten von '${CFBundleName}'." MSG_MISSING_MAINCLASS="Die 'MainClass' ist nicht spezifiziert!\nDie Java-Anwendung kann nicht gestartet werden!" MSG_JVMVERSION_REQ_INVALID="Die Syntax der angeforderten Java-Version ist ungültig: %s\nBitte kontaktieren Sie den Entwickler der App." @@ -344,10 +401,12 @@ elif [[ $LANG == de* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="Stellen Sie sicher, dass die angeforderte Java-Version installiert ist." MSG_INSTALL_JAVA="Auf Ihrem System muss die 'Java'-Software installiert sein.\nBesuchen Sie java.com für weitere Installationshinweise." MSG_LATER="Später" - MSG_VISIT_JAVA_DOT_COM="java.com öffnen" + MSG_VISIT_JAVA_DOT_COM="Java von Oracle" + MSG_VISIT_ADOPTIUM="Java von Adoptium" + ;; -# Simplifyed Chinese localization -elif [[ $LANG == zh* ]] ; then +# Simplified Chinese +zh) MSG_ERROR_LAUNCHING="无法启动 '${CFBundleName}'." MSG_MISSING_MAINCLASS="没有指定 'MainClass'!\nJava程序无法启动!" MSG_JVMVERSION_REQ_INVALID="Java版本参数语法错误: %s\n请联系该应用的开发者。" @@ -358,10 +417,44 @@ elif [[ $LANG == zh* ]] ; then MSG_NO_SUITABLE_JAVA_CHECK="请确保系统中安装了所需的Java版本" MSG_INSTALL_JAVA="你需要在Mac中安装Java运行环境!\n访问 java.com 了解如何安装。" MSG_LATER="稍后" - MSG_VISIT_JAVA_DOT_COM="访问 java.com" - -# English default localization -else + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTIUM="Java by Adoptium" + ;; + +# Spanish +es) + MSG_ERROR_LAUNCHING="ERROR iniciando '${CFBundleName}'." + MSG_MISSING_MAINCLASS="¡'MainClass' no especificada!\n¡La aplicación Java no puede iniciarse!" + MSG_JVMVERSION_REQ_INVALID="La sintaxis de la versión Java requerida no es válida: %s\nPor favor, contacte con el desarrollador de la aplicación." + MSG_NO_SUITABLE_JAVA="¡No se encontró una versión de Java adecuada en su sistema!\nEste programa requiere Java %s" + MSG_JAVA_VERSION_OR_LATER="o posterior" + MSG_JAVA_VERSION_LATEST="(ultima actualización)" + MSG_JAVA_VERSION_MAX="superior a %s" + MSG_NO_SUITABLE_JAVA_CHECK="Asegúrese de instalar la versión Java requerida." + MSG_INSTALL_JAVA="¡Necesita tener JAVA instalado en su Mac!\nVisite java.com para consultar las instrucciones para su instalación..." + MSG_LATER="Más tarde" + MSG_VISIT_JAVA_DOT_COM="Java de Oracle" + MSG_VISIT_ADOPTIUM="Java de Adoptium" + ;; + +# Brazilian Portuguese +pt-BR) + MSG_ERROR_LAUNCHING="ERRO iniciando '${CFBundleName}'." + MSG_MISSING_MAINCLASS="'MainClass' não foi definida!\nA aplicação java não poderá ser iniciada!" + MSG_JVMVERSION_REQ_INVALID="A sintaxe da versão Java requerida não é valida: %s\nPor favor contacte o desenvolvedor dessa aplicação." + MSG_NO_SUITABLE_JAVA="Não foi encontrado uma versão Java compatível no seu sistema!\nEsta aplicação precisa do Java %s" + MSG_JAVA_VERSION_OR_LATER="ou maior" + MSG_JAVA_VERSION_LATEST="(última atualização)" + MSG_JAVA_VERSION_MAX="máxima %s" + MSG_NO_SUITABLE_JAVA_CHECK="Verifique se instalou a versão Java necessária." + MSG_INSTALL_JAVA="Você precisa instalar o JAVA no seu Mac!\nPor favor, visite java.com para instruções de instalação..." + MSG_LATER="Depois" + MSG_VISIT_JAVA_DOT_COM="Java por Oracle" + MSG_VISIT_ADOPTIUM="Java por Adoptium" + ;; + +# English | default +en|*) MSG_ERROR_LAUNCHING="ERROR launching '${CFBundleName}'." MSG_MISSING_MAINCLASS="'MainClass' isn't specified!\nJava application cannot be started!" MSG_JVMVERSION_REQ_INVALID="The syntax of the required Java version is invalid: %s\nPlease contact the App developer." @@ -372,8 +465,10 @@ else MSG_NO_SUITABLE_JAVA_CHECK="Make sure you install the required Java version." MSG_INSTALL_JAVA="You need to have JAVA installed on your Mac!\nVisit java.com for installation instructions..." MSG_LATER="Later" - MSG_VISIT_JAVA_DOT_COM="Visit java.com" -fi + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTIUM="Java by Adoptium" + ;; +esac @@ -387,7 +482,7 @@ fi ################################################################################ function get_java_version_from_cmd() { # second sed command strips " and -ea from the version string - echo $("$1" -version 2>&1 | awk '/version/{print $NF}' | sed -E 's/"//g;s/-ea//g') + echo $("$1" -version 2>&1 | awk '/version/{print $3}' | sed -E 's/"//g;s/-ea//g') } @@ -456,7 +551,7 @@ function get_comparable_java_version() { ################################################################################ function is_valid_requirement_pattern() { local java_req=$1 - java8pattern='1\.[4-8](\.0)?(\.0_[0-9]+)?[*+]?' + java8pattern='1\.[4-8](\.[0-9]+)?(\.0_[0-9]+)?[*+]?' java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?' # test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9) if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then @@ -489,20 +584,28 @@ if [ -n "$JAVA_HOME" ] ; then if [[ $JAVA_HOME == /* ]] ; then # if "$JAVA_HOME" starts with a Slash it's an absolute path JAVACMD="$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as absolute path to the executable '$JAVACMD'" else # otherwise it's a relative path to "$AppPackageFolder" JAVACMD="$AppPackageFolder/$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as relative path inside the App bundle to the executable '$JAVACMD'" fi JAVACMD_version=$(get_comparable_java_version $(get_java_version_from_cmd "${JAVACMD}")) else - stub_logger "[JavaSearch] ... didn't found JAVA_HOME" + stub_logger "[JavaSearch] ... haven't found JAVA_HOME" fi # check for any other or a specific Java version # also if $JAVA_HOME exists but isn't executable if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then - stub_logger "[JavaSearch] Checking for JavaVirtualMachines on the system ..." + + # add a warning in the syslog if JAVA_HOME is not executable or not found (#100) + if [ -n "$JAVA_HOME" ] ; then + stub_logger "[JavaSearch] ... but no 'java' executable was found at the JAVA_HOME location!" + fi + + stub_logger "[JavaSearch] Searching for JavaVirtualMachines on the system ..." # reset variables JAVACMD="" JAVACMD_version="" @@ -513,7 +616,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 4] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 4 fi @@ -523,7 +626,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 5] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 5 fi @@ -531,15 +634,41 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # find installed JavaVirtualMachines (JDK + JRE) allJVMs=() - # read JDK's from '/usr/libexec/java_home -V' command - while read -r line; do - version=$(echo $line | awk -F $',' '{print $1;}') - path=$(echo $line | awk -F $'" ' '{print $2;}') - path+="/bin/java" - allJVMs+=("$version:$path") - done < <(/usr/libexec/java_home -V 2>&1 | grep '^[[:space:]]') - # unset while loop variables - unset version path + + # read JDK's from '/usr/libexec/java_home --xml' command with PlistBuddy and a custom Dict iterator + # idea: https://stackoverflow.com/a/14085460/1128689 and https://scriptingosx.com/2018/07/parsing-dscl-output-in-scripts/ + javaXml=$(/usr/libexec/java_home --xml) + javaCounter=$(/usr/libexec/PlistBuddy -c "Print" /dev/stdin <<< $javaXml | grep "Dict" | wc -l | tr -d ' ') + + # iterate over all Dict entries + # but only if there are any JVMs at all (#93) + if [ "$javaCounter" -gt "0" ] ; then + for idx in $(seq 0 $((javaCounter - 1))) + do + version=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMVersion" /dev/stdin <<< $javaXml) + path=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMHomePath" /dev/stdin <<< $javaXml) + path+="/bin/java" + allJVMs+=("$version:$path") + done + # unset for loop variables + unset version path + fi + + # add SDKMAN! java versions (#95) + if [ -d ~/.sdkman/candidates/java/ ] ; then + for sdkjdk in ~/.sdkman/candidates/java/*/ + do + if [[ ${sdkjdk} =~ /current/$ ]] ; then + continue + fi + + sdkjdkcmd="${sdkjdk}bin/java" + version=$(get_java_version_from_cmd "${sdkjdkcmd}") + allJVMs+=("$version:$sdkjdkcmd") + done + # unset for loop variables + unset version + fi # add Apple JRE if available if [ -x "${apple_jre_plugin}" ] ; then @@ -559,6 +688,9 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # determine JVMs matching the min/max version requirement + + stub_logger "[JavaSearch] Filtering the result list for JVMs matching the min/max version requirement ..." + minC=$(get_comparable_java_version ${JVMVersion}) maxC=$(get_comparable_java_version ${JVMMaxVersion}) matchingJVMs=() @@ -643,7 +775,7 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # debug output for i in "${matchingJVMs[@]}" do - stub_logger "[JavaSearch] ... ... matches all requirements: $i" + stub_logger "[JavaSearch] ... matches all requirements: $i" done @@ -700,9 +832,10 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then stub_logger "[EXIT 3] ${MSG_NO_SUITABLE_JAVA_EXPANDED}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTIUM}\"} default button 1${DialogWithIcon}" \ -e "set response to button returned of the result" \ - -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTIUM}\" then open location \"https://adoptium.net/releases.html\"" # exit with error exit 3 @@ -710,9 +843,10 @@ if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then # log exit cause stub_logger "[EXIT 1] ${MSG_ERROR_LAUNCHING}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\"} default button \"${MSG_VISIT_JAVA_DOT_COM}\" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" \ + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTIUM}\"} default button 1${DialogWithIcon}" \ -e "set response to button returned of the result" \ - -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"http://java.com\"" + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTIUM}\" then open location \"https://adoptium.net/releases.html\"" # exit with error exit 1 fi @@ -727,7 +861,7 @@ if [ -z "${JVMMainClass}" ]; then # log exit cause stub_logger "[EXIT 2] ${MSG_MISSING_MAINCLASS}" # display error message with AppleScript - osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error exit 2 fi @@ -761,13 +895,13 @@ stub_logger "[WorkingDirectory] ${WorkingDirectory}" # - main class # - main class arguments # - passthrough arguments from Terminal or Drag'n'Drop to Finder icon -stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" -splash:\"${ResourcesFolder}/${JVMSplashFile}\" -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" +stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" ${JVMSplashFile:+ -splash:\"${ResourcesFolder}/${JVMSplashFile}\"} -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" exec "${JAVACMD}" \ -cp "${JVMClassPath}" \ - -splash:"${ResourcesFolder}/${JVMSplashFile}" \ + ${JVMSplashFile:+ -splash:"${ResourcesFolder}/${JVMSplashFile}"} \ -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \ -Xdock:name="${CFBundleName}" \ - ${JVMOptions:+"${JVMOptions[@]}" }\ + ${JVMOptionsArr:+"${JVMOptionsArr[@]}" }\ ${JVMDefaultOptions:+$JVMDefaultOptions }\ "${JVMMainClass}"\ ${MainArgsArr:+ "${MainArgsArr[@]}"}\ diff --git a/test/check-log.sh b/test/check-log.sh new file mode 100755 index 0000000..24f8c43 --- /dev/null +++ b/test/check-log.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# this is a helper script to work around issue with grep exit codes +# in `set -e` environments like GitHub Actions CI + +cat "$1" | grep "$2" ; test $? -eq 1 diff --git a/test/java-version-tester.sh b/test/java-version-tester.sh index 921957b..48151e7 100755 --- a/test/java-version-tester.sh +++ b/test/java-version-tester.sh @@ -1,7 +1,7 @@ #!/bin/bash # Tests for the functions used in universalJavaApplicationStub script -# tofi86 @ 2018-03-10 +# tofi86 @ 2020-02-11 @@ -15,7 +15,7 @@ ################################################################################ function get_java_version_from_cmd() { # second sed command strips " and -ea from the version string - echo $("$1" -version 2>&1 | awk '/version/{print $NF}' | sed -E 's/"//g;s/-ea//g') + echo $("$1" -version 2>&1 | awk '/version/{print $3}' | sed -E 's/"//g;s/-ea//g') } @@ -84,7 +84,7 @@ function get_comparable_java_version() { ################################################################################ function is_valid_requirement_pattern() { local java_req=$1 - java8pattern='1\.[4-8](\.0)?(\.0_[0-9]+)?[*+]?' + java8pattern='1\.[4-8](\.[0-9]+)?(\.0_[0-9]+)?[*+]?' java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?' # test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9) if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then @@ -179,6 +179,7 @@ echo "Tests with Java 1.6:" testExtractMajor "1.6" "6" testExtractMajor "1.6+" "6" testExtractMajor "1.6.0" "6" +testExtractMajor "1.6.2" "6" testExtractMajor "1.6.0_07" "6" testExtractMajor "1.6.0_45" "6" testExtractMajor "1.6.0_65-b14-468" "6" @@ -328,6 +329,7 @@ testValidReqPattern "1.6.0_45" "0" testValidReqPattern "1.6.0_45+" "0" testValidReqPattern "1.6.0_100" "0" testValidReqPattern "1.6.0_100+" "0" +testValidReqPattern "1.6.2" "0" echo "" echo "Tests with old version scheme (invalid requirements):" testValidReqPattern "1.2" "1"