bisq/desktop/package/package.gradle
cd2357 98597508be
Windows: Remove msi package
For Windows, generate only the exe installer.
2020-12-03 13:15:44 +01:00

296 lines
13 KiB
Groovy

import java.time.LocalDateTime
import org.apache.tools.ant.taskdefs.condition.Os
import static groovy.io.FileType.*
task jpackageSanityChecks {
description 'Interactive sanity checks on the version of the code that will be packaged'
doLast {
executeCmd("git --no-pager log -5 --oneline")
ant.input(message: "Above you see the current HEAD and its recent history.\n" +
"Is this the right commit for packaging? (y=continue, n=abort)",
addproperty: "sanity-check-1",
validargs: "y,n")
if (ant.properties['sanity-check-1'] == 'n') {
ant.fail('Aborting')
}
executeCmd("git status --short --branch")
ant.input(message: "Above you see any local changes that are not in the remote branch.\n" +
"If you have any local changes, please abort, get them merged, get the latest branch and try again.\n" +
"Continue with packaging? (y=continue, n=abort)",
addproperty: "sanity-check-2",
validargs: "y,n")
if (ant.properties['sanity-check-2'] == 'n') {
ant.fail('Aborting')
}
// TODO Evtl check programmatically in gradle (i.e. fail if below v11)
executeCmd("java --version")
ant.input(message: "Above you see the installed java version, which will be used to compile and build Bisq.\n" +
"Is this java version ok for that? (y=continue, n=abort)",
addproperty: "sanity-check-3",
validargs: "y,n")
if (ant.properties['sanity-check-3'] == 'n') {
ant.fail('Aborting')
}
}
}
task getJavaBinariesDownloadURLs {
description 'Find out which JDK will be used for jpackage and prepare to download it'
dependsOn 'jpackageSanityChecks'
doLast {
// The build directory will be deleted next time the clean task runs
// Therefore, we can use it to store any temp files (separate JDK for jpackage, etc) and resulting build artefacts
// We create a temp folder in the build directory which holds all jpackage-related artefacts (not just the final installers)
String tempRootDirName = 'temp-' + LocalDateTime.now().getNano()
File tempRootDir = new File(project.buildDir, tempRootDirName)
tempRootDir.mkdirs()
ext.tempRootDir = tempRootDir
println "Created temp root folder " + tempRootDir
File binariesFolderPath = new File(tempRootDir, "binaries")
binariesFolderPath.mkdirs();
ext.binariesFolderPath = binariesFolderPath
// TODO Extend script logic to alternatively allow a local (separate, v14+) JDK for jpackage
// TODO Another option is to use the local JDK for everything: build jars and use jpackage (but then it has to be v14+)
// It seems only the latest version of each JDK is available for download
// Therefore, if at any future AdoptOpenJDK release these download links won't work, simply update them
// See https://adoptopenjdk.net/releases.html?variant=openjdk15&jvmVariant=hotspot for latest download URLs
// The links must be for: x64 + JDK + zip (for windows) or tar.gz (for mac/linux)
Map jdk15DownloadURLs = [
'linux' : 'https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_linux_hotspot_15_36.tar.gz',
'mac' : 'https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz',
'windows' : 'https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_windows_hotspot_15_36.zip'
// TODO For some reason, using "--runtime-image jdk-11" does NOT work with a v15 jpackage, but works with v14
// v14
// 'linux' : 'https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_linux_hotspot_14.0.2_12.tar.gz',
// 'mac' : 'https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz',
// 'windows' : 'https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_windows_hotspot_14.0.2_12.zip'
]
String osKey
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
osKey = 'windows'
} else if (Os.isFamily(Os.FAMILY_MAC)) {
osKey = 'mac'
} else {
osKey = 'linux'
}
ext.jdk15DownloadURL = jdk15DownloadURLs[osKey]
// The download URLs can be manually overwritten here, if necessary
// ext.jdk15DownloadURL = ...
}
}
task retrieveAndExtractJavaBinaries {
description 'Retrieve necessary Java binaries and extract them'
dependsOn 'getJavaBinariesDownloadURLs'
doLast {
File tempRootDir = getJavaBinariesDownloadURLs.property("tempRootDir")
// Folder where the jpackage JDK archive will be downloaded and extracted
String jdkForJpackageDirName = "jdk-jpackage"
File jdkForJpackageDir = new File(tempRootDir, jdkForJpackageDirName)
jdkForJpackageDir.mkdirs();
String jdkForJpackageArchiveURL = getJavaBinariesDownloadURLs.property('jdk15DownloadURL')
String jdkForJpackageArchiveFileName = jdkForJpackageArchiveURL.tokenize('/').last()
File jdkForJpackageFile = new File(jdkForJpackageDir, jdkForJpackageArchiveFileName)
// Download necessary JDK binaries
ext.downloadArchive(jdkForJpackageArchiveURL, jdkForJpackageFile)
// Extract them
String jpackageBinaryFileName
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
ext.extractArchiveZip(jdkForJpackageFile, jdkForJpackageDir)
jpackageBinaryFileName = 'jpackage.exe'
} else {
ext.extractArchiveTarGz(jdkForJpackageFile, jdkForJpackageDir)
jpackageBinaryFileName = 'jpackage'
}
// Find jpackage in the newly extracted JDK
// Don't rely on hardcoded paths to reach it, because the path depends on the version and platform
jdkForJpackageDir.traverse(type: FILES, nameFilter: jpackageBinaryFileName) {
println 'Using jpackage binary from ' + it
ext.jpackageFilePath = it.path
}
}
ext.downloadArchive = {String archiveURL, File destinationArchiveFile ->
println "Downloading ${archiveURL}"
ant.get(src: archiveURL, dest: destinationArchiveFile)
println 'Download saved to ' + destinationArchiveFile
}
ext.extractArchiveTarGz = {File tarGzFile, File destinationDir ->
println "Extracting tar.gz ${tarGzFile}"
// Gradle's tar extraction preserves permissions (crucial for jpackage to function correctly)
copy {
from tarTree(resources.gzip(tarGzFile))
into destinationDir
}
println "Extracted to ${destinationDir}"
}
ext.extractArchiveZip = {File zipFile, File destinationDir ->
println "Extracting zip ${zipFile}..."
ant.unzip(src: zipFile, dest: destinationDir)
println "Extracted to ${destinationDir}"
}
}
task packageInstallers {
description 'Call jpackage to prepare platform-specific binaries for this platform'
dependsOn 'retrieveAndExtractJavaBinaries'
// Clean all previous artefacts and create a fresh shadowJar for the installers
dependsOn rootProject.clean
dependsOn ':desktop:shadowJar'
doLast {
String jPackageFilePath = retrieveAndExtractJavaBinaries.property('jpackageFilePath')
String licenseFilePath = "${rootProject.projectDir}/LICENSE"
File binariesFolderPath = file(getJavaBinariesDownloadURLs.property('binariesFolderPath'))
File tempRootDir = getJavaBinariesDownloadURLs.property("tempRootDir")
// The jpackateTempDir stores temp files used by jpackage for building the installers
// It can be inspected in order to troubleshoot the packaging process
File jpackateTempDir = new File(tempRootDir, "jpackage-temp")
jpackateTempDir.mkdirs();
// ALL contents of this folder will be included in the resulting installers
// However, the fat jar is the only one we need
// Therefore, this location should point to a folder that ONLY contains the fat jar
// If later we will need to include other non-jar resources, we can do that by adding --resource-dir to the jpackage opts
String fatJarFolderPath = "${project(':desktop').buildDir}/libs"
String mainJarName = file(fatJarFolderPath).list()[0]
// TODO For non-modular applications: use jlink to create a custom runtime containing only the modules required
// See jpackager argument documentation:
// https://docs.oracle.com/en/java/javase/15/docs/specs/man/jpackage.html
// For mac, valid versions are one to three integers separated by dot
// TODO Special handling for mac? Or always remove -SNAPSHOT suffix?
String appVersion = '1.1.1'
println "Packaging Bisq version ${appVersion}"
String commonOpts = (
// Generic options
" --dest \"${binariesFolderPath}\"" +
" --name Bisq" +
" --description \"A decentralized bitcoin exchange network.\"" +
" --app-version ${appVersion}" +
" --copyright \"© 2020 Bisq\"" +
" --vendor Bisq" +
" --temp \"${jpackateTempDir}\"" +
// Options for creating the application image
" --input ${fatJarFolderPath}" +
// Options for creating the application launcher
" --main-jar ${mainJarName}" +
" --main-class bisq.desktop.app.BisqAppMain" +
" --java-options -Xss1280k" +
" --java-options -XX:MaxRAM=4g" +
" --java-options -Djava.net.preferIPv4Stack=true" +
// Warning: this will cause guice reflection exceptions and lead to issues with the guice internal cache
// resulting in the UI not loading
// " --java-options -Djdk.module.illegalAccess=deny" +
// Options for creating the application package
" --license-file \"${licenseFilePath}\""
)
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
// TODO Found no benefit in using --resource-dir "..package/windows", it has the same outcome as opts below
// Actually using the --resource-dir option caused issues with uninstalling the newly installed Bisq
// Therefore, not using --resource-dir for windows, for now
String windowsOpts = (
" --icon ${project(':desktop').projectDir}/package/windows/Bisq.ico" +
" --win-per-user-install" +
" --win-menu" +
" --win-shortcut"
)
// TODO How does the current package/windows/Bisq.iss play into this?
executeCmd(jPackageFilePath + commonOpts + windowsOpts + " --type exe")
} else if (Os.isFamily(Os.FAMILY_MAC)) {
// TODO Include signing args, like --mac-sign / -mac-signing-keychain / --mac-signing-key-user-name
// See https://docs.oracle.com/en/java/javase/14/jpackage/override-jpackage-resources.html
// for details of "--resource-dir"
String macOpts = (
" --resource-dir \"${project(':desktop').projectDir}/package/macosx\""
)
executeCmd(jPackageFilePath + commonOpts + macOpts + " --type dmg")
} else {
String linuxOpts = (
" --icon ${project(':desktop').projectDir}/package/linux/icon.png" +
" --linux-package-name bisq-build-test" +
" --linux-app-release ${appVersion}" +
" --linux-menu-group Network" +
" --linux-shortcut"
)
// Package deb
executeCmd(jPackageFilePath + commonOpts + linuxOpts +
" --linux-deb-maintainer contact@bisq.network" +
" --type deb")
// Clean jpackage temp folder, needs to be empty for the next packaging step (rpm)
jpackateTempDir.deleteDir();
jpackateTempDir.mkdirs();
// Package rpm
executeCmd(jPackageFilePath + commonOpts + linuxOpts +
" --linux-rpm-license-type AGPLv3" + // https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses
" --type rpm")
}
println "The binaries are ready:"
binariesFolderPath.traverse {
println it.path
}
}
}
def executeCmd(String cmd) {
String shell
String shellArg
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
shell = 'cmd'
shellArg = '/c'
} else {
shell = 'bash'
shellArg = '-c'
}
println "Executing command:\n${cmd}\n"
// See "Executing External Processes" section of
// http://docs.groovy-lang.org/next/html/documentation/
def commands = [shell, shellArg, cmd]
def process = commands.execute(null, project.rootDir)
if (process.waitFor() == 0) {
println "Command output (stdout):\n${process.text}"
} else {
println "Command output (stderr):\n${process.err.text}"
}
}