As part of developing new AutoPkg recipes to support SapMachine‘s new Long Term Support (LTS) distribution for Java 17, I ran into a curious problem when testing. When I ran the SapMachine Java 17 LTS installer that was being generated by AutoPkg, I was seeing the following behavior:
- SapMachine Java 17 LTS is installed by itself – no problem
- SapMachine Java 17 LTS installed, then SapMachine Java 11 LTS is installed – no problem
- SapMachine Java 11 LTS installed, then SapMachine Java 17 LTS is installed – SapMachine Java 11 LTS is removed, only SapMachine Java 17 LTS is installed now.
I double-checked the preinstall script for the SapMachine Java 17 LTS installer. It is supposed to remove an existing SapMachine Java 17 LTS installation with the same version info, but it should not have also been removing SapMachine Java 11 LTS. After a re-review of the script and additional testing, I was able to rule out the script as the problem. But what was causing this behavior? Also, why was it happening in this order?
- SapMachine Java 11 LTS installed, then SapMachine Java 17 LTS is installed
But not this order?
- SapMachine Java 17 LTS installed, then SapMachine Java 11 LTS is installed
The answer was in how the package’s package identifier was set up. For more details, please see below the jump.
When I was writing the AutoPkg .pkg recipes for SapMachine Java 17 LTS, I used the existing SapMachine Java 11 LTS .pkg recipe as a template. Included with that recipe was the following:
<key>id</key> | |
<string>net.java.openjdk.sapmachine</string> |
For AutoPkg’s PkgCreator processor, this defines the package identifier.
I didn’t change that. That was a mistake, because that meant that Apple’s Installer was going to see SapMachine Java 17 LTS as an upgrade install for an existing SapMachine Java 11 LTS installation. Why is this important?
When macOS’s Installer does an upgrade install, it does the following:
- Consults its store of existing installer package receipts.
- Identifies if it has a receipt by a previous installer with a matching package identifier. If multiple receipts are found, the latest installed is used.
- Uses the Bill of Materials (BOM) stored with the receipt to generate a list of files which are in the receipt’s BOM and are not part of the new installer’s BOM.
- Removes the files in question.
- Adds the files from the current installer.
Note: Files added, removed or changed outside of the main installation process will not be included in the BOM. Since these files are not included in the BOM’s listing, the installer process will not move, change or delete these files. Examples of files not included or tracked by the BOM would be files added or moved by an installer package’s preinstall or postinstall scripts.
From Installer‘s point of view, the two packages were identified this way:
SapMachine Java 11 LTS
- Identifier: net.java.openjdk.sapmachine
- Version: 11.xx.xx
SapMachine Java 17 LTS
- Identifier: net.java.openjdk.sapmachine
- Version: 17.xx.xx
That meant that, on a Mac where SapMachine Java 11 LTS had been installed previously using an installer package with the net.java.openjdk.sapmachine package identifier, Installer interpreted the SapMachine Java 17 LTS install as being an upgrade for SapMachine Java 11 LTS.
In those conditions, Installer performs the following actions:
- Consults the existing installer package receipts.
- Identifies the latest version of the SapMachine Java 11 LTS receipt with a matching net.java.openjdk.sapmachine package identifier.
- Generates a list of the files installed by the SapMachine Java 11 LTS installer package, using the SapMachine Java 11 LTS receipt’s BOM, and identified those files which were not included in the SapMachine Java 17 LTS installer package’s BOM.
- Removes those files.
- Adds the files from the SapMachine Java 17 LTS installer.
The effect is that SapMachine Java 11 LTS’s files were automatically removed when SapMachine Java 11 LTS is installed first and then SapMachine Java 17 LTS is subsequently installed.
The fix? Make sure the SapMachine Java 17 LTS installer package has a different package identifier.
As I was using AutoPkg to build the installer package in question, I could include variables as part of the package identifier to help ensure the package identifier would be unique for each version of the SapMachine Java 17 LTS installer package.
<key>id</key> | |
<string>net.java.openjdk.sapmachine.universal.%version%.%BUILD_NUMBER%</string> |
For example, for SapMachine Java 17.35 LTS, the package identifier looks like this in the AutoPkg-created installer package:
<key>id</key> | |
<string>net.java.openjdk.sapmachine.universal.17.35</string> |