From 162b2249b152a00183614ebdacd2f1b490deef8c Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 7 Jan 2022 21:21:10 +0300 Subject: [PATCH] Rewrote build script, improved packaging - Renamed :packageWindows to :packageNsis - ImageMagick now required for :packageNsis - Packaging output is now in build/packages - Rewrote build script - Packaging logic and LWJGL dependencies now in separate files - Packaging logic now implemented with Gradle, not Bash scripts - Cross-platform? - Added :packageZip - Universal ZIP with start scripts - Changed version detection logic - Tags of ancestor commits are now considered - Only tags with format vMAJOR.MINOR.PATCH[-SUFFIX] are considered - If the tag's commit isn't HEAD, PATCH is incremented - When version detection fails, dummy version is 999.0.0- - LWJGL target platforms can be overridden with forceTargets project property --- .gitattributes | 2 +- build.gradle | 511 ++++++++++-------- buildPackages.sh | 191 ------- build_logic/lwjgl.gradle | 117 ++++ build_logic/packaging/deb/script.gradle | 38 ++ build_logic/packaging/nsis/script.gradle | 50 ++ build_logic/packaging/zip/script.gradle | 41 ++ build_packages/NSIS/left_side.bmp | Bin 154542 -> 0 bytes build_packages/NSIS/logo.ico | Bin 191671 -> 0 bytes docs/building/BuildGuide.md | 60 +- docs/building/BuildScriptReference.md | 103 ++++ .../packaging/deb}/DEBIAN/control | 6 +- .../packaging/nsis/config.nsi | 325 +++++------ src/packaging/nsis/left_side.png | Bin 0 -> 36296 bytes src/packaging/zip/start.bat | 2 + src/packaging/zip/start.sh | 11 + 16 files changed, 838 insertions(+), 619 deletions(-) delete mode 100755 buildPackages.sh create mode 100644 build_logic/lwjgl.gradle create mode 100644 build_logic/packaging/deb/script.gradle create mode 100644 build_logic/packaging/nsis/script.gradle create mode 100644 build_logic/packaging/zip/script.gradle delete mode 100644 build_packages/NSIS/left_side.bmp delete mode 100644 build_packages/NSIS/logo.ico create mode 100644 docs/building/BuildScriptReference.md rename {build_packages/DEB/template => src/packaging/deb}/DEBIAN/control (56%) rename build_packages/NSIS/ProgressiaInstaller.nsi => src/packaging/nsis/config.nsi (86%) create mode 100644 src/packaging/nsis/left_side.png create mode 100644 src/packaging/zip/start.bat create mode 100755 src/packaging/zip/start.sh diff --git a/.gitattributes b/.gitattributes index f2efb39..03959a9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,4 +6,4 @@ * text=auto eol=lf *.bat text eol=crlf - +*.nsi text eol=crlf diff --git a/build.gradle b/build.gradle index 7ed8c0e..9cc7031 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,12 @@ /* - * build.gradle for Progressia + * Build logic for Progressia + * build.gradle + * + * Please refer to + * + * docs/building/BuildScriptReference.md + * + * for user reference. */ plugins { @@ -8,19 +15,15 @@ plugins { // GrGit // A JGit wrapper for Groovy used to access git commit info id 'org.ajoberstar.grgit' version '4.1.1' - - /* - * Uncomment the following line to enable the Eclipse plugin. - * This is only necessary if you don't use Buildship plugin from the IDE - */ - //id 'eclipse' } + + +/* + * Configure Java version + */ + java { - /* - * We're Java 8 for now. - * Why? As of 2020, most users have Oracle Java, which only supports Java 8. - */ sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } @@ -37,6 +40,8 @@ compileJava { } } + + /* * Dependencies */ @@ -45,7 +50,7 @@ repositories { mavenCentral() /* - * Specify Windcorp Maven repository + * Windcorp Maven repository * Currently used by: * - ru.windcorp.fork.io.github.java-graphics:glm:1.0.1 */ @@ -75,262 +80,308 @@ dependencies { // A unit-testing library testImplementation 'junit:junit:4.13.2' - // See LWJGL dependencies below + // Also see LWJGL dependencies in build_logic/lwjgl.gradle } + + /* - * Progressia uses the following LWJGL libraries: - * - Core libraries - * - OpenGL - * - OpenAL - * - GLFW - * - STB + * Version resolution */ -/* - * LWJGL - * (auto-generated script) - * ((here be dragons)) - */ +import org.ajoberstar.grgit.* -import org.gradle.internal.os.OperatingSystem +// Pattern: vMAJOR.MINOR.PATCH[-SUFFIX] +project.ext.tagFormat = /^v(\d+)\.(\d+)\.(\d+)(-[\w\-]*)?$/ -project.ext.lwjglVersion = "3.2.3" - -switch (OperatingSystem.current()) { - case OperatingSystem.LINUX: - def osArch = System.getProperty("os.arch") - project.ext.lwjglNatives = osArch.startsWith("arm") || osArch.startsWith("aarch64") - ? "natives-linux-${osArch.contains("64") || osArch.startsWith("armv8") ? "arm64" : "arm32"}" - : "natives-linux" - break - case OperatingSystem.MAC_OS: - project.ext.lwjglNatives = "natives-macos" - break - case OperatingSystem.WINDOWS: - project.ext.lwjglNatives = System.getProperty("os.arch").contains("64") ? "natives-windows" : "natives-windows-x86" - break -} - -dependencies { - implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion") - - implementation "org.lwjgl:lwjgl" - implementation "org.lwjgl:lwjgl-glfw" - implementation "org.lwjgl:lwjgl-openal" - implementation "org.lwjgl:lwjgl-opengl" - implementation "org.lwjgl:lwjgl-stb" - - runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives" -} - -// LWJGL END - -/* - * Tasks - */ - -/* - * Additional native libraries specification - */ - -project.ext.platforms = new HashSet<>() - -task addNativeDependencies { - doFirst { - def archs = project.ext.platforms - - switch (archs.size()) { - case 0: - println "Adding LWJGL native dependencies for local platform only:\n\t$lwjglNatives" - archs.add project.ext.lwjglNatives - break - case 1: - println "Adding LWJGL native dependencies for platform\n\t" + archs.get(0) - break - default: - println "Adding LWJGL native dependencies for platforms:\n\t" + archs.join("\n\t") - } - - if (project.ext.lwjglNatives.isEmpty()) println "WTF" - - dependencies { - archs.each { arch -> - runtimeOnly "org.lwjgl:lwjgl::$arch" - runtimeOnly "org.lwjgl:lwjgl-glfw::$arch" - runtimeOnly "org.lwjgl:lwjgl-openal::$arch" - runtimeOnly "org.lwjgl:lwjgl-opengl::$arch" - runtimeOnly "org.lwjgl:lwjgl-stb::$arch" - } - } - } -} - -compileJava.mustRunAfter addNativeDependencies // Make sure runtimeOnly has not been resolved - -task requestLinuxDependencies { - description 'Adds linux, linux-arm64 and linux-arm32 native libraries to built artifacts.' - doFirst { - project.ext.platforms.addAll([ - 'natives-linux', - 'natives-linux-arm64', - 'natives-linux-arm32' - ]) - } -} -task requestWindowsDependencies { - description 'Adds windows and windows-x86 native libraries to built artifacts.' - doFirst { - project.ext.platforms.addAll([ - 'natives-windows', - 'natives-windows-x86' - ]) - } -} -task requestMacOSDependencies { - description 'Adds macos native libraries to built artifacts.' - doFirst { - project.ext.platforms.addAll(['natives-macos']) - } -} - -def dependencySpecificationTasks = tasks.findAll { task -> task.name.startsWith('request') && task.name.endsWith('Dependencies') } - -task requestCrossPlatformDependencies { - description 'Adds native libraries for all available platforms to built artifacts.' - dependsOn dependencySpecificationTasks -} - -addNativeDependencies.mustRunAfter dependencySpecificationTasks - -/* - * Determines if the provided dependency should be packaged - */ -def isDependencyRequested(String dep) { - if (dep.endsWith(".jar")) { - dep = dep.substring(0, dep.length() - ".jar".length()) - } - - return !dep.contains("natives-") || - project.ext.platforms.contains(dep.substring(dep.indexOf("natives-"), dep.length())) -} - -/* - * Manifest specification - */ - -task specifyLocalManifest { - dependsOn addNativeDependencies // Make sure all native dependencies are specified - - doFirst { - def classPath = [] - - configurations.runtimeClasspath.each { - if (isDependencyRequested(it.getName())) { - classPath.add("lib/" + it.getName()) - } else { - println "\tRemoving from JAR classpath (not requested): " + it.getName() - } - } - - if (classPath.size() == configurations.runtimeClasspath.size()) { - println "Nothing removed from JAR classpath" +String version_parseVersion(String tag, boolean increment) { + try { + + def data = (tag =~ tagFormat)[0] + + def major = data[1] + def minor = data[2] + def patch = data[3] as int + def suffix = data[4] ?: '' + + if (increment) { + def oldVersion = "$major.$minor.$patch$suffix" + patch++ + def newVersion = "$major.$minor.$patch$suffix" + + logger.info "Version parsed from Git: $oldVersion, incremented to $newVersion" + return newVersion + } else { + def newVersion = "$major.$minor.$patch$suffix" + logger.info "Version parsed from Git: $newVersion" + return newVersion } - def version = "dev"; - def commit = "-"; - def branch = "-"; - def buildId = project.findProperty('buildId') ?: "-"; + } catch (any) { + logger.warn "Could not parse version from tag \"$tag\"" + return tag + } +} + +Tag version_findRelevantTag(Grgit git) { + def tags = git.tag.list() + + def commits = [ git.head() ] + def visited = new HashSet<>() + + while (true) { + if (commits.isEmpty()) return null + + def nextCommits = new HashSet<>() + def formatSpecificationPrinted = false + for (def commit : commits) { + def tag = tags.findAll { it.commit == commit } ?.max { it.dateTime } + + if (tag != null) { + if (tag.name ==~ tagFormat) { + return tag + } else { + if (!formatSpecificationPrinted) { + formatSpecificationPrinted = true + logger.info 'Expecting tag format: vMAJOR.MINOR.PATCH[-SUFFIX]' + } + logger.info 'Ignoring tag due to invalid format: {}', tag.name + } + } + + nextCommits.addAll commit.parentIds.collect(git.resolve.&toCommit) + } + + visited.addAll commits + nextCommits.removeAll visited + commits = nextCommits + } +} + +task resolveVersion { + description 'Resolves version information from Git repository or project properties.' + + doFirst { try { - def git = org.ajoberstar.grgit.Grgit.open() - def head = git.head() + def git = Grgit.open(dir: project.projectDir) - commit = head.id - branch = git.branch.current().name + project.ext.commit = git.head().id + project.ext.branch = git.branch.current().name - def newestTag = git.tag.list().findAll { it.commit == head } ?.max { it.dateTime } ?.name - if (newestTag != null) { - version = newestTag; - } else if (project.hasProperty('buildId')) { - version = project.buildId; + if (project.version != 'unspecified') { + // Leave version as-is + return + } + + def tag = version_findRelevantTag(git) + if (tag == null) { + + String suffix + if (project.hasProperty('buildId')) { + suffix = project.buildId; + } else { + suffix = java.time.ZonedDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern('yyyy_MM_dd')) + } + project.version = "999.0.0-$suffix" + + logger.warn 'Git repository does not contain an applicable tag, using dummy version {}\nSpecify version with -Pversion=1.2.3 or create a Git tag named v1.2.3', project.version + } else { - version = head.dateTime.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE); + + project.version = version_parseVersion(tag.name, tag.commit != git.head()) + } } catch (org.eclipse.jgit.errors.RepositoryNotFoundException e) { - println "No Git repository found in project root" - } + if (project.version == 'unspecified') project.version = 'dev' + project.ext.commit = '-' + project.ext.branch = '-' - jar { - manifest { - attributes( - "Main-Class": "ru.windcorp.progressia.client.ProgressiaClientMain", - "Class-Path": configurations.runtimeClasspath.collect { "lib/" + it.getName() } .findAll { isDependencyRequested(it) } .join(' '), - - "Specification-Title": "Progressia", - - "Implementation-Title": "Progressia", - "Implementation-Version": version, - "Implementation-Version-Git-Commit": commit, - "Implementation-Version-Git-Branch": branch, - "Implementation-Version-BuildId": buildId, - ) - } + logger.warn 'No Git repository found in project root, using dummy version {}\nSpecify version with -Pversion=1.2.3 or create a Git tag named v1.2.3', project.version + } + } + + doLast { + if (!project.hasProperty('buildId')) { + project.ext.buildId = '-' } } } -jar.dependsOn specifyLocalManifest + /* - * Library export + * Configure JAR manifest + */ + +task configureManifest { + description 'Populates JAR manifest with Main-Class, Class-Path and version metadata.' + + jar.dependsOn configureManifest + dependsOn resolveVersion + + doFirst { + jar.manifest.attributes( + 'Main-Class': 'ru.windcorp.progressia.client.ProgressiaClientMain', + 'Class-Path': configurations.runtimeClasspath.collect { "lib/${it.name}" } .join(' '), + + 'Specification-Title': 'Progressia', + + 'Implementation-Title': 'Progressia', + 'Implementation-Version': project.version, + 'Implementation-Version-Git-Commit': project.commit, + 'Implementation-Version-Git-Branch': project.branch, + 'Implementation-Version-BuildId': project.buildId, + ) + } +} + + + +/* + * Copy libraries into buil/libs/lib directory, next to Progressia.jar */ task exportLibs(type: Sync) { - mustRunAfter addNativeDependencies + description 'Copies runtime libraries into a subdirectory next to the output JAR.' + + jar.dependsOn exportLibs - into libsDirectory.get().getAsFile().getPath() + "/lib" - exclude { !isDependencyRequested(it.getName()) } from configurations.runtimeClasspath + into 'build/libs/lib' } -jar.dependsOn(exportLibs) + /* - * Packaging + * Apply LWJGL logic + */ +apply from: 'build_logic/lwjgl.gradle' + + + +/* + * Packaging working directory configuration */ -task packageDebian(type: Exec) { - description 'Builds the project and creates a Debain package.' - group 'Progressia' - - dependsOn build - dependsOn requestLinuxDependencies - - commandLine './buildPackages.sh', 'debian' +import java.nio.file.* +import java.nio.file.attribute.* +task createPackagingDirs() { + description 'Resets build/tmp/packaging directory.' + doLast { - println "Debian package available in build_packages/" + def tmpDir = buildDir.toPath().resolve 'tmp/packaging' + + def nuke = new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException { + if (e == null) { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } else { + // directory iteration failed + throw e; + } + } + } + + // Fckn nuke tmpDir from orbit + // I'm so done with deleting file trees in Java/Groovy/whatever + // ...Not using File.deleteDir() because the latter recurses into symlinks, and we don't want to wipe build/libs/lib + if (Files.exists(tmpDir)) { + Files.walkFileTree tmpDir, nuke + } + + Files.createDirectories tmpDir.resolve('workingDir') + Files.createDirectories buildDir.toPath().resolve('packages') + } +} + +task linkBuildOutputForPackaging() { + description 'Symlinks the contents of build/libs into packaging working directory.' + + dependsOn build + dependsOn createPackagingDirs + + onlyIf { preparePackaging.ext.mode == 'symlink' } + + doLast { + def from = buildDir.toPath().resolve 'libs' + def into = buildDir.toPath().resolve "tmp/packaging/workingDir/${preparePackaging.ext.buildDest}" + + Files.createDirectories into + + Files.list(from).each { + def fileName = it.fileName.toString() + + // Exclude all JARs except the current one + if (fileName ==~ "${project.name}.*\\.jar" && fileName != tasks.jar.archiveFileName.get()) + return + + Files.createSymbolicLink into.resolve(it.fileName), it + } + } +} + +task copyBuildOutputForPackaging(type: Copy) { + description 'Copies the contents of build/libs into packaging working directory.' + + dependsOn build + dependsOn createPackagingDirs + + onlyIf { preparePackaging.ext.mode == 'copy' } + + from 'build/libs' + filesMatching("${project.name}*.jar") { + include tasks.jar.archiveFileName.get() + } + into "build/tmp/packaging/workingDir/${ -> preparePackaging.ext.buildDest}" +} + +task preparePackaging { + preparePackaging.ext.buildDest = '' + preparePackaging.ext.mode = 'symlink' + + dependsOn createPackagingDirs + dependsOn linkBuildOutputForPackaging + dependsOn copyBuildOutputForPackaging +} + + + +/* + * Apply all packaging scripts + */ + +new File(projectDir, 'build_logic/packaging').list().each { + apply from: "build_logic/packaging/$it/script.gradle" +} + + + +/* + * Ensure no more than one packaging task is scheduled + */ + +gradle.taskGraph.whenReady { graph -> + if (graph.allTasks.count { it.name ==~ /package[^_]*/ } > 1) { + def offenders = graph.allTasks.findAll { it.name ==~ /package[^_]*/ } + throw new GradleException("Cannot execute multiple package tasks within a single build\n" + + "\tOffending tasks: $offenders") } } -task packageWindows(type: Exec) { - description 'Builds the project and creates a Windows installer.' - group 'Progressia' - dependsOn build - dependsOn requestWindowsDependencies - commandLine './buildPackages.sh', 'windows' - - doLast { - println "Windows installer available in build_packages/" - } -} +/* + * Convenience build tasks + */ task buildCrossPlatform { description 'Builds the project including native libraries for all available platforms.' @@ -340,17 +391,17 @@ task buildCrossPlatform { dependsOn build doLast { - println "Native libraries for all platforms have been added" + logger.info 'Native libraries for all platforms have been added' } } task buildLocal { - description "Builds the project including only native libraries for current platform ($lwjglNatives)." + description "Builds the project including only native libraries for current platform (${lwjgl.localArch})." group 'Progressia' dependsOn build doLast { - println "Native libraries only for platform $lwjglNatives have been added" + logger.info "Native libraries only for platform ${lwjgl.localArch} have been added" } } diff --git a/buildPackages.sh b/buildPackages.sh deleted file mode 100755 index 464d641..0000000 --- a/buildPackages.sh +++ /dev/null @@ -1,191 +0,0 @@ -#!/bin/bash - -# -# Progressia -# Copyright (C) 2020-2021 Wind Corporation and contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -echoerr() { echo "$@" 1>&2; } - -buildDebianPackage() { - - # Commands that must be available to execute this action - requiredCommands='dpkg-deb fakeroot' - - # Package name. Sync with control file manually! - name='progressia-techdemo' - # Version that the package will receive. Sync with control file manually! - version='1.0_all' - - # This directory will be copied into $tmpDir - templateDirectory="build_packages/DEB/template" - - # Files that must be present - requiredFiles="$templateDirectory/DEBIAN/control" - - nameAndVersion="$name-$version" - tmpDir="build_packages/DEB/$nameAndVersion" - outputFile="build_packages/DEB/$nameAndVersion.deb" - - echo "Checking environment to build Debian package" - - for item in $requiredCommands; do - if command -v "$item" &> /dev/null; then - echo "- $item found" - else - echoerr "Command $item not found, cannot package" - exit 100 - fi - done - - for file in $requiredFiles; do - if ! [ -r "$file" ]; then - echoerr "$file is missing or not readable, cannot package" - exit 101 - else - echo "- $file is present and readable" - fi - done - - echo "Environment OK; packaging Debian package" - exitCode=0 - - { - shareDir="$tmpDir/usr/share/progressia" - - mkdir -p "$tmpDir" && - mkdir -p "$shareDir" && - cp -r "$templateDirectory"/* "$tmpDir" && - cp -r 'build/libs/lib' "$shareDir/lib" && - cp 'build/libs/Progressia.jar' "$shareDir/Progressia.jar" && - echo "------ DPKG-DEB ------" && - fakeroot dpkg-deb --build "$tmpDir" && - echo "---- DPKG-DEB END ----" && - mv "$outputFile" build_packages - } || { - echoerr "Could not create Debian package" - exitCode=1 - } - - { - if [ -d "$tmpDir" ]; then - rm -r "$tmpDir" - fi - echo "Cleaned up" - } || { - echoerr "Could not clean up after packaging Debian package" - exitCode=2 - } - - exit "$exitCode" -} - -buildWindowsInstaller() { - - # Commands that must be available to execute this action - requiredCommands='makensis' - - # NSIS configuration file that must be present - configurationFile='build_packages/NSIS/ProgressiaInstaller.nsi' - - # File that will be output - outputFile='build_packages/NSIS/ProgressiaInstaller.exe' - - echo "Checking environment to build Windows installer" - - for item in $requiredCommands; do - if command -v "$item" &> /dev/null; then - echo "- $item found" - else - echoerr "Command $item not found, cannot build" - exit 100 - fi - done - - if ! [ -r "$configurationFile" ]; then - echoerr "$configurationFile is missing or not readable, cannot build" - exit 101 - else - echo "- $configurationFile is present and readable" - fi - - echo "Environment OK; building Windows installer" - exitCode=0 - - { - cp -r 'build/libs/lib' 'build_packages/NSIS/lib' && - cp 'build/libs/Progressia.jar' 'build_packages/NSIS/Progressia.jar' && - cp 'LICENSE' 'build_packages/NSIS/LICENSE.txt' && - echo "------ NSIS ------" && - makensis "$configurationFile" && - echo "---- NSIS END ----" && - mv "$outputFile" build_packages - } || { - echoerr "Could not build Windows installer" - exitCode=1 - } - - { - if [ -d 'build_packages/NSIS/lib' ]; then - rm -r 'build_packages/NSIS/lib' - fi - if [ -e 'build_packages/NSIS/Progressia.jar' ]; then - rm 'build_packages/NSIS/Progressia.jar' - fi - if [ -e 'build_packages/NSIS/LICENSE.txt' ]; then - rm 'build_packages/NSIS/LICENSE.txt' - fi - echo "Cleaned up" - } || { - echoerr "Could not clean up after building Windows installer" - exitCode=2 - } - - exit "$exitCode" -} - -printUsage() { - echoerr "Usage: $0 TARGET" - echoerr " where TARGET is 'debian' or 'windows'" -} - -if [ -n "$2" ]; then - echoerr "Too many arguments." - printUsage - exit 202 -fi - -case "$1" in -"debian") - buildDebianPackage - ;; -"windows") - buildWindowsInstaller - ;; -"") - echoerr "No action specified" - printUsage - exit 200 - ;; -"--help" | "-help" | "help" | "?") - printUsage - ;; -*) - echoerr "Unknown action '$1'" - printUsage - exit 201 - ;; -esac diff --git a/build_logic/lwjgl.gradle b/build_logic/lwjgl.gradle new file mode 100644 index 0000000..4d9f68e --- /dev/null +++ b/build_logic/lwjgl.gradle @@ -0,0 +1,117 @@ +/* + * Build logic for Progressia + * LWJGL dependency logic + */ + +project.ext.lwjgl = new HashMap<>() + +// Version of LWJGL +lwjgl.version = '3.2.3' + +/* + * Target platforms for current operation. + * This is filled in by the request* tasks. This is referenced by the addLwjglNatives task. + * When empty, current platform is assumed. + */ +lwjgl.targets = new HashSet<>() + +// LWJGL components. To include org.lwjgl:lwjgl-foobar, add 'foobar' to this list. +lwjgl.libraries = [ + 'opengl', + 'glfw', + 'openal', + 'stb' +] + +// Determine the architecture of the build environment +import org.gradle.internal.os.OperatingSystem +switch (OperatingSystem.current()) { + case OperatingSystem.LINUX: + def osArch = System.getProperty('os.arch') + lwjgl.localArch = osArch.startsWith('arm') || osArch.startsWith('aarch64') + ? "linux-${osArch.contains('64') || osArch.startsWith('armv8') ? 'arm64' : 'arm32'}" + : 'linux' + break + case OperatingSystem.MAC_OS: + lwjgl.localArch = 'macos' + break + case OperatingSystem.WINDOWS: + lwjgl.localArch = System.getProperty('os.arch').contains('64') ? 'windows' : 'windows-x86' + break +} + +// Declare pure-Java dependencies +dependencies { + // BOM + implementation platform("org.lwjgl:lwjgl-bom:${lwjgl.version}") + + // Core + implementation 'org.lwjgl:lwjgl' + + // Components + lwjgl.libraries.each { implementation "org.lwjgl:lwjgl-$it" } +} + +/* + * Adds LWJGL native libraries to runtimeOnly configuration + */ +task lwjgl_addNativesToRuntimeOnly { + // Make sure runtimeOnly has not been resolved + compileJava.dependsOn lwjgl_addNativesToRuntimeOnly + configureManifest.dependsOn lwjgl_addNativesToRuntimeOnly + exportLibs.dependsOn lwjgl_addNativesToRuntimeOnly + + doFirst { + if (project.hasProperty('forceTargets')) { + try { + def oldTargets = lwjgl.targets.join(',') + + lwjgl.targets.clear() + lwjgl.targets.addAll project.forceTargets.split(',')*.trim().collect { it == 'local' ? lwjgl.localArch : it } + + logger.info 'Overriding selected platforms {} with {}', oldTargets, lwjgl.targets.join(',') + } catch (Exception e) { + throw new GradleException("Could not parse forceTargets \"${project.forceTargets}\", expecting platform-1,platform-2,local", e) + } + } + + if (lwjgl.targets.isEmpty()) { + logger.info 'Adding LWJGL native dependencies for local platform only: {}', lwjgl.localArch + lwjgl.targets.add lwjgl.localArch + } else { + logger.info 'Adding LWJGL native dependencies for platforms: {}', lwjgl.targets.sort().join(', ') + } + + dependencies { + lwjgl.targets.each { target -> + runtimeOnly "org.lwjgl:lwjgl::natives-$target" + lwjgl.libraries.each { lib -> + runtimeOnly "org.lwjgl:lwjgl-$lib::natives-$target" + } + } + } + } +} + +task requestCrossPlatformDependencies { + description 'Adds LWJGL natives for all available platforms.' + + lwjgl_addNativesToRuntimeOnly.mustRunAfter requestCrossPlatformDependencies +} + +def requestTask(String name, String... targets) { + def theTask = task "request${name}Dependencies" + + theTask.doFirst { + lwjgl.targets.addAll targets + } + + theTask.description "Adds LWJGL natives for $name (${targets.join(', ')})." + + requestCrossPlatformDependencies.dependsOn theTask + lwjgl_addNativesToRuntimeOnly.mustRunAfter theTask +} + +requestTask 'Linux', 'linux', 'linux-arm32', 'linux-arm64' +requestTask 'Windows', 'windows', 'windows-x86' +requestTask 'MacOS', 'macos' diff --git a/build_logic/packaging/deb/script.gradle b/build_logic/packaging/deb/script.gradle new file mode 100644 index 0000000..f5c380b --- /dev/null +++ b/build_logic/packaging/deb/script.gradle @@ -0,0 +1,38 @@ +task packageDeb_processResources(type: Copy) { + dependsOn resolveVersion + dependsOn preparePackaging + + from 'src/packaging/deb' + + filesMatching('DEBIAN/control') { + expand(version: { -> project.version}) + } + + into 'build/tmp/packaging/workingDir' +} + +task packageDeb_configure() { + preparePackaging.mustRunAfter packageDeb_configure + + doLast { + tasks.preparePackaging.ext.buildDest = '/usr/share/progressia' + tasks.preparePackaging.ext.mode = 'copy' + } +} + +task packageDeb(type: Exec) { + description 'Builds the project and creates a Debian package.' + group 'Progressia' + + dependsOn packageDeb_configure + dependsOn requestLinuxDependencies + dependsOn build + dependsOn preparePackaging + + dependsOn packageDeb_processResources + + executable 'dpkg-deb' + args '--root-owner-group' + args '--build', 'build/tmp/packaging/workingDir' + args 'build/packages' +} diff --git a/build_logic/packaging/nsis/script.gradle b/build_logic/packaging/nsis/script.gradle new file mode 100644 index 0000000..fe03b0f --- /dev/null +++ b/build_logic/packaging/nsis/script.gradle @@ -0,0 +1,50 @@ +task packageNsis_processResources(type: Copy) { + dependsOn preparePackaging + + from ('src/packaging/nsis') { + exclude 'left_side.png' + } + from('LICENSE') { + rename 'LICENSE', 'LICENSE.txt' + } + into 'build/tmp/packaging/workingDir' +} + +task packageNsis_generateIcon(type: Exec) { + mustRunAfter preparePackaging + + executable 'convert' + args files('src/main/resources/assets/icons/*.original.png').files*.path + args 'build/tmp/packaging/workingDir/logo.ico' +} + +task packageNsis_generateLeftSide(type: Exec) { + mustRunAfter preparePackaging + + executable 'convert' + args 'src/packaging/nsis/left_side.png' + args '-alpha', 'off' + args 'BMP3:build/tmp/packaging/workingDir/left_side.bmp' +} + +task packageNsis(type: Exec) { + description 'Builds the project and creates a Windows NSIS installer.' + group 'Progressia' + + dependsOn requestWindowsDependencies + dependsOn build + dependsOn resolveVersion + dependsOn preparePackaging + + dependsOn packageNsis_processResources + dependsOn packageNsis_generateIcon + dependsOn packageNsis_generateLeftSide + + executable 'makensis' + args '-NOCONFIG' + args "-DPROJECT_NAME=${project.name}" + args "-DPROJECT_VERSION=${ -> project.version}" + args "-DMAIN_JAR_FILE=${ -> project.tasks.jar.archiveFileName.get()}" + args "-DOUTPUT_DIR=${project.buildDir.absolutePath}/packages" + args 'build/tmp/packaging/workingDir/config.nsi' +} diff --git a/build_logic/packaging/zip/script.gradle b/build_logic/packaging/zip/script.gradle new file mode 100644 index 0000000..4975ac8 --- /dev/null +++ b/build_logic/packaging/zip/script.gradle @@ -0,0 +1,41 @@ +task packageZip_processResources(type: Copy) { + dependsOn preparePackaging + + from ('src/packaging/zip') { + filesMatching('start.*') { + filter( + org.apache.tools.ant.filters.ReplaceTokens, + tokens: [mainJarFile: project.tasks.jar.archiveFileName.get()] + ) + } + } + from ('src/main/resource/assets/icons/logo256.original.png') { + rename 'logo256.original.png', 'logo.png' + } + from('LICENSE') { + rename 'LICENSE', 'LICENSE.txt' + } + into 'build/tmp/packaging/workingDir' +} + +task packageZip(type: Zip) { + description 'Builds the project and creates a cross-platform ZIP package.' + group 'Progressia' + + dependsOn resolveVersion + dependsOn requestCrossPlatformDependencies + dependsOn build + dependsOn preparePackaging + + dependsOn packageZip_processResources + + archiveBaseName = project.name + archiveAppendix = 'universal' + + doFirst { + archiveVersion = project.version + } + + from 'build/tmp/packaging/workingDir' + destinationDirectory = file('build/packages') +} diff --git a/build_packages/NSIS/left_side.bmp b/build_packages/NSIS/left_side.bmp deleted file mode 100644 index 1dd523c665302af759548aefba2a81d1baf7d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154542 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 F{{hTpLtX#? diff --git a/build_packages/NSIS/logo.ico b/build_packages/NSIS/logo.ico deleted file mode 100644 index e858a481ddffc1f524cc554042fbc900fa7d3d9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 191671 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 O3V;Hj04Pwe75G0ZzIbc^ diff --git a/docs/building/BuildGuide.md b/docs/building/BuildGuide.md index 23833e9..a91eef8 100644 --- a/docs/building/BuildGuide.md +++ b/docs/building/BuildGuide.md @@ -1,8 +1,10 @@ # Build Guide -This document is a guide to building Progressia from source. +This document is a guide to building Progressia from source. For quick reference, see +[Build Script Reference](BuildScriptReference.md). -Compilation should be possible on all platforms that support JDK 8 or later, however, packaging scripts require Bash. +Compilation should be possible on all platforms that support JDK 8 or later, however, packaging scripts require +additional programs in `PATH`. This guide assumes you are familiar with using a terminal or Windows Command Prompt or PowerShell. @@ -150,54 +152,46 @@ GNU/Linux and Windows natives: ./gradlew build requestLinuxDependencies requestWindowsDependencies ``` -For finer control please edit `build.gradle` manually by adding the desired natives to the `project.ext.platforms` set like so: - -``` -project.ext.platforms = new HashSet<>() -project.ext.platforms.add 'natives-windows-x86' -``` - ## Packaging -A Debian package and a Windows installer can be created automatically on systems that support Bash. These tasks are delegated -by Gradle to `buildPackages.sh` in repository root. This script checks the environment and assembles the requested output; the -resulting files are moved into `build_packages`. +A universal ZIP distribution, a Debian package and a Windows NSIS installer may be created automatically by the build +script. + +### Creating a universal ZIP package + +A universal cross-platform ZIP archive can be created with the following Gradle task: + +``` +./gradlew packageZip +``` + +Gradle will then build all artifacts necessary to run the game on all available platforms and package game files, +libraries, launch scripts, etc. into a compressed ZIP archive. + +The resulting file can be found in `build/packages/` ### Creating a Debian package A Debian package can be created with the following Gradle task: ``` -./gradlew packageDebian +./gradlew packageDeb ``` Gradle will then build all artifacts necessary to run the game on GNU/Linux (all three architectures) and invoke -`./buildPackages.sh debian`. Commands `dpkg-deb` and `fakeroot` must be available in system path in order to build the package. +`dpkg-deb`. Commands `dpkg-deb` must be available in system path in order to build the package. ### Creating a Windows installer -A Windows installer can be created with the following Gradle task: +A Windows NSIS installer can be created with the following Gradle task: ``` -./gradlew packageWindows +./gradlew packageNsis ``` Gradle will then build all artifacts necessary to run the game on Windows (both x64 and x86 architectures) and invoke -`./buildPackages.sh windows`. +`makensis`. -Windows installers are implemented with [NSIS](https://nsis.sourceforge.io/). Command `makensis` must be available in system -path in order to build the installer. - -## Gradle tasks summary - -- `buildLocal` – creates a build optimized for current platform. Use this to quickly build the game during development. -- `buildCrossPlatform` – creates a build that supports all known architectures. Use this to build a universal version of the game. -- `build` – currently a synonym of `buildLocal`; creates a default build. -- `packageDebian` – creates a Debian package. Do not invoke together with `packageWindows`. -- `packageWindows` – creates a Windows installer. Do not invoke together with `packageDebian`. -- `requestLinuxDependencies` – requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included when building. -- `requestWindowsDependencies` – requests that `natives-windows` and `natives-windows-x86` binaries are included when building. -- `requestMacOSDependencies` – requests that `natives-macos` binaries are included when building. -- `requestCrossPlatformDependencies` – requests that all binaries are included when building. - -All other basic and Java-related Gradle tasks are available as well. \ No newline at end of file +Windows installers are implemented with [NSIS](https://nsis.sourceforge.io/). [ImageMagick](https://imagemagick.org), +a command-line image editing tool, is used to generate some assets for the installer. Commands `makensis` and +`convert` (from ImageMagick) must be available in system path in order to build the installer. diff --git a/docs/building/BuildScriptReference.md b/docs/building/BuildScriptReference.md new file mode 100644 index 0000000..c5d6b46 --- /dev/null +++ b/docs/building/BuildScriptReference.md @@ -0,0 +1,103 @@ +# Build Script Reference + +This document is a user's reference for the build script of Progressia. For a beginner-friendly guide, see +[Build Guide](BuildGuide.md). + +## Gradle tasks summary + +- `buildLocal` – creates a build optimized for current platform. Use this to quickly build the game during development. +- `buildCrossPlatform` – creates a build that supports all known architectures. Use this to build a universal version of the game. +- `build` – currently a synonym of `buildLocal`; creates a default build. +- `packageZip` – creates a universal ZIP. Incompatible with other `package` tasks. +- `packageDeb` – creates a Debian package. Incompatible with other `package` tasks. +- `packageNsis` – creates a Windows NSIS installer. Incompatible with other `package` tasks. +- `requestLinuxDependencies` – requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included when building. +- `requestWindowsDependencies` – requests that `natives-windows` and `natives-windows-x86` binaries are included when building. +- `requestMacOSDependencies` – requests that `natives-macos` binaries are included when building. +- `requestCrossPlatformDependencies` – requests that all binaries are included when building. + +To execute a task, run `./gradlew `. + +`build`-type tasks output the executable JAR and all libraries required at runtime into `build/libs`. `package`-type +tasks output packages into `build/packages`. + +## Packaging tasks + +Some packaging tasks require additional software in `PATH`. + +| Task | Commands required in `PATH` | +|---------------|------------------------------------------| +| `packageDeb` | `dpkg-deb` | +| `packageZip` | _none_ | +| `packageNsis` | `makensis`, `convert` (from ImageMagick) | + +## Version and metadata + +### Version scheme + +Progressia builds are identified by four parameters: version, Git commit, Git branch and build ID. + +Versions roughly follow [semantic versioning](https://semver.org/spec/v2.0.0.html), with each version fitting the +`MAJOR.MINOR.PATCH[-SUFFIX]` pattern. Depending on the build environment (see below), version is either "real" with +no metadata (e.g. `0.43.2` or `1.2.1-beta`) or a dummy fallback with build metadata (e.g. `999.0.0-2021_07_23` or +`999.0.0-WJ3`). + +### Version detection + +Build script considers three scenarios when determining the version: + +1. `version` project property is set explicitly. This may be done in a variety of ways, for example with command line +argument `-Pversion=1.2.3` +(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)) +2. Local Git repository is found, and HEAD is tagged appropriately: version is the tag name with leading `v` +stripped. Example: `v1.2.3` is version `1.2.3` +3. Local Git repository is found, and some ancestor of HEAD is tagged appropriately: version is the tag name with +leading `v` stripped and PATCH incremented by one. Example: `v1.2.3` is version `1.2.4` + +Tags not named like `vMAJOR.MINOR.PATCH[-SUFFIX]` are ignored for cases 2 and 3. + +In all other cases, a fallback dummy value is used for version, appended with build ID or current date. + +### Git metadata + +Git commit and Git branch are correspond to the state of the local Git repository, if any. In case Git metadata is +unavailable, `-` fallback is used for both fields. + +### Build ID + +Build ID uniquely identifies artifacts produced by automated build systems. For example, builds executed by WindCorp +Jenkins suite have build IDs like `WJ3` or `WJ142`. Build ID must be provided explicitly; it is `-` unless specified +otherwise. + +Build ID may be set with `buildId` project property. This may be done in a variety of ways, for example with command +line argument `-PbuildId=WJ3` +(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)). + +## Native libraries + +LWJGL uses native libraries. Build script declares platform-specific dependencies based on the set of target +platforms, `project.ext.lwjgl.targets` (aka `lwjgl.targets`). These dependencies are added to `runtimeOnly` +configuration. + +When this set is empty, the script selects natives for current platform. Otherwise, all platforms in the set are +included. + +`lwjgl.targets` is populated automatically by packaging tasks and by `buildCrossPlatform`. To add extra targets, +``requestXxxDependencies` tasks may be used. + +Target selection mechanism may be overridden with `forceTargets` project property. This may be done in a variety of +ways, for example with command line argument `-PforceTargets=windows-x86,local` +(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)). The +value is a comma-separated list of target architectures. `local` target will be replaced with the automatically +detected current architecture. + +### Available targets + +| Name | Task | +|---------------|------------------------------| +| `linux` | `requestLinuxDependencies` | +| `linux-arm32` | `requestLinuxDependencies` | +| `linux-arm64` | `requestLinuxDependencies` | +| `windows` | `requestWindowsDependencies` | +| `windows-x86` | `requestWindowsDependencies` | +| `macos` | `requestMacOSDependencies` | diff --git a/build_packages/DEB/template/DEBIAN/control b/src/packaging/deb/DEBIAN/control similarity index 56% rename from build_packages/DEB/template/DEBIAN/control rename to src/packaging/deb/DEBIAN/control index 0095cf7..fde9093 100644 --- a/build_packages/DEB/template/DEBIAN/control +++ b/src/packaging/deb/DEBIAN/control @@ -1,8 +1,8 @@ -Package: progressia-techdemo -Version: 1.0 +Package: progressia +Version: ${version} Section: custom Priority: optional Architecture: all Maintainer: Javapony Depends: java8-runtime -Description: Progressia Techdemo release +Description: Progressia - a 3D sandbox survival game diff --git a/build_packages/NSIS/ProgressiaInstaller.nsi b/src/packaging/nsis/config.nsi similarity index 86% rename from build_packages/NSIS/ProgressiaInstaller.nsi rename to src/packaging/nsis/config.nsi index abf8d73..0eb5d1f 100644 --- a/build_packages/NSIS/ProgressiaInstaller.nsi +++ b/src/packaging/nsis/config.nsi @@ -1,161 +1,164 @@ -;NSIS Modern User Interface -;Welcome/Finish Page Example Script -;Written by Joost Verburg - -;-------------------------------- -;Include Modern UI - - !include "MUI2.nsh" - -;-------------------------------- -;General - - !define PROJECT_NAME "Progressia" - - ; MUI Settings / Icons - !define MUI_ICON "logo.ico" - ;!define MUI_UNICON ;Uninstall icon - - ; MUI Settings / Header - ; !define MUI_HEADERIMAGE - ; !define MUI_HEADERIMAGE_RIGHT - ; !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-r-nsis.bmp" - ; !define MUI_HEADERIMAGE_UNBITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-uninstall-r-nsis.bmp" - - ; MUI Settings / Wizard - !define MUI_WELCOMEFINISHPAGE_BITMAP "left_side.bmp" - !define MUI_UNWELCOMEFINISHPAGE_BITMAP "left_side.bmp" - - ;Name and file - Name "${PROJECT_NAME}" - OutFile "${PROJECT_NAME}Installer.exe" - Unicode True - - ;Default installation folder - InstallDir "$PROGRAMFILES\${PROJECT_NAME}" - - ;Get installation folder from registry if available - InstallDirRegKey HKLM "Software\${PROJECT_NAME}" "" - - ;Request application privileges for Windows Vista - RequestExecutionLevel admin - -;-------------------------------- -;Interface Settings - - !define MUI_ABORTWARNING - -;-------------------------------- -;Pages - - !insertmacro MUI_PAGE_WELCOME - !insertmacro MUI_PAGE_LICENSE "LICENSE.txt" - !insertmacro MUI_PAGE_COMPONENTS - !insertmacro MUI_PAGE_DIRECTORY - !insertmacro MUI_PAGE_INSTFILES - !define MUI_FINISHPAGE_RUN - !define MUI_FINISHPAGE_RUN_TEXT "Start ${PROJECT_NAME}" - !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink" - !insertmacro MUI_PAGE_FINISH - - !insertmacro MUI_UNPAGE_WELCOME - !insertmacro MUI_UNPAGE_CONFIRM - !insertmacro MUI_UNPAGE_COMPONENTS - !insertmacro MUI_UNPAGE_INSTFILES - !insertmacro MUI_UNPAGE_FINISH - -;-------------------------------- -;Languages - - !insertmacro MUI_LANGUAGE "English" - -;-------------------------------- -;Installer Sections - -Section "Install ${PROJECT_NAME}" SEC0000 - - SectionIn RO ;Make it read-only - SetOutPath "$INSTDIR" - SetOverwrite on - - ;Files - File Progressia.jar - File logo.ico - File /r lib - - ;Store installation folder - WriteRegStr HKLM SOFTWARE\Progressia "Install_Dir" "$INSTDIR" - - ;Create uninstaller - - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "DisplayName" "${PROJECT_NAME} (remove only)" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe" - WriteUninstaller "$INSTDIR\Uninstall.exe" - -SectionEnd - -Section "Create Desktop Shortcut" SEC0001 - SetOutPath "$APPDATA\${PROJECT_NAME}" - CreateShortCut "$DESKTOP\${PROJECT_NAME}.lnk" "$INSTDIR\${PROJECT_NAME}.jar" "" "$INSTDIR\logo.ico" -SectionEnd - -Section "Start Menu Shortcuts" SEC0002 - - CreateDirectory "$SMPROGRAMS\${PROJECT_NAME}" - CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" - CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk" "$INSTDIR\${PROJECT_NAME}.jar" "" "$INSTDIR\logo.ico" - -SectionEnd - -;-------------------------------- -;Uninstaller Section - -Section "Uninstall" - - ;ADD YOUR OWN FILES HERE... - - Delete $INSTDIR\Uninstall.exe - Delete $INSTDIR\Progressia.jar - Delete $INSTDIR\lib\*.* - Delete $INSTDIR\logo.ico - - RMDir $INSTDIR\lib - - Delete $DESKTOP\${PROJECT_NAME}.lnk - - Delete $SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk - Delete $SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk - - RMDir $INSTDIR - - RMDir /r $SMPROGRAMS\${PROJECT_NAME} - - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" - DeleteRegKey HKLM "Software\${PROJECT_NAME}" - -SectionEnd - -Section "un.Remove user data" - - RMDir /r "$APPDATA\${PROJECT_NAME}" - -SectionEnd - -;-------------------------------- -;Functions - -Function LaunchLink - SetOutPath "$APPDATA\${PROJECT_NAME}" - ExecShell "" "$INSTDIR\${PROJECT_NAME}.jar" -FunctionEnd - -;-------------------------------- -;Descriptions - - ;Language strings - LangString DESC_SecDummy ${LANG_ENGLISH} "Install ${PROJECT_NAME}." - - ;Assign language strings to sections - !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${SEC0000} $(DESC_SecDummy) - !insertmacro MUI_FUNCTION_DESCRIPTION_END \ No newline at end of file +;NSIS Modern User Interface +;Welcome/Finish Page Example Script +;Written by Joost Verburg + +;-------------------------------- +;Include Modern UI + + !include "MUI2.nsh" + +;-------------------------------- +;General + + ; Expecting the following symbols from caller: + ; PROJECT_NAME + ; PROJECT_VERSION + ; MAIN_JAR_FILE + + ; MUI Settings / Icons + !define MUI_ICON "logo.ico" + ;!define MUI_UNICON ;Uninstall icon + + ; MUI Settings / Header + ; !define MUI_HEADERIMAGE + ; !define MUI_HEADERIMAGE_RIGHT + ; !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-r-nsis.bmp" + ; !define MUI_HEADERIMAGE_UNBITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-uninstall-r-nsis.bmp" + + ; MUI Settings / Wizard + !define MUI_WELCOMEFINISHPAGE_BITMAP "left_side.bmp" + !define MUI_UNWELCOMEFINISHPAGE_BITMAP "left_side.bmp" + + ;Name and file + Name "${PROJECT_NAME}" + OutFile "${OUTPUT_DIR}/${PROJECT_NAME}-${PROJECT_VERSION}-installer.exe" + Unicode True + + ;Default installation folder + InstallDir "$PROGRAMFILES\${PROJECT_NAME}" + + ;Get installation folder from registry if available + InstallDirRegKey HKLM "Software\${PROJECT_NAME}" "" + + ;Request application privileges for Windows Vista + RequestExecutionLevel admin + +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + +;-------------------------------- +;Pages + + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_LICENSE "LICENSE.txt" + !insertmacro MUI_PAGE_COMPONENTS + !insertmacro MUI_PAGE_DIRECTORY + !insertmacro MUI_PAGE_INSTFILES + !define MUI_FINISHPAGE_RUN + !define MUI_FINISHPAGE_RUN_TEXT "Start ${PROJECT_NAME}" + !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink" + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_WELCOME + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_COMPONENTS + !insertmacro MUI_UNPAGE_INSTFILES + !insertmacro MUI_UNPAGE_FINISH + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Installer Sections + +Section "Install ${PROJECT_NAME}" SEC0000 + + SectionIn RO ;Make it read-only + SetOutPath "$INSTDIR" + SetOverwrite on + + ;Files + File "${MAIN_JAR_FILE}" + File logo.ico + File /r lib + + ;Store installation folder + WriteRegStr HKLM "SOFTWARE\${PROJECT_NAME}" "Install_Dir" "$INSTDIR" + + ;Create uninstaller + + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "DisplayName" "${PROJECT_NAME} (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe" + WriteUninstaller "$INSTDIR\Uninstall.exe" + +SectionEnd + +Section "Create Desktop Shortcut" SEC0001 + SetOutPath "$APPDATA\${PROJECT_NAME}" + CreateShortCut "$DESKTOP\${PROJECT_NAME}.lnk" "$INSTDIR\${MAIN_JAR_FILE}" "" "$INSTDIR\logo.ico" +SectionEnd + +Section "Start Menu Shortcuts" SEC0002 + + CreateDirectory "$SMPROGRAMS\${PROJECT_NAME}" + CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk" "$INSTDIR\${MAIN_JAR_FILE}" "" "$INSTDIR\logo.ico" + +SectionEnd + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" + + ;ADD YOUR OWN FILES HERE... + + Delete $INSTDIR\Uninstall.exe + Delete "$INSTDIR\${MAIN_JAR_FILE}" + Delete $INSTDIR\lib\*.* + Delete $INSTDIR\logo.ico + + RMDir $INSTDIR\lib + + Delete $DESKTOP\${PROJECT_NAME}.lnk + + Delete $SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk + Delete $SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk + + RMDir $INSTDIR + + RMDir /r $SMPROGRAMS\${PROJECT_NAME} + + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" + DeleteRegKey HKLM "Software\${PROJECT_NAME}" + +SectionEnd + +Section "un.Remove user data" + + RMDir /r "$APPDATA\${PROJECT_NAME}" + +SectionEnd + +;-------------------------------- +;Functions + +Function LaunchLink + SetOutPath "$APPDATA\${PROJECT_NAME}" + ExecShell "" "$INSTDIR\${MAIN_JAR_FILE}" +FunctionEnd + +;-------------------------------- +;Descriptions + + ;Language strings + LangString DESC_SecDummy ${LANG_ENGLISH} "Install ${PROJECT_NAME}." + + ;Assign language strings to sections + !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SEC0000} $(DESC_SecDummy) + !insertmacro MUI_FUNCTION_DESCRIPTION_END diff --git a/src/packaging/nsis/left_side.png b/src/packaging/nsis/left_side.png new file mode 100644 index 0000000000000000000000000000000000000000..2c08662c18da7ec4377f5526af702572db36f7dc GIT binary patch literal 36296 zcmb??XH*ki*lmCaK@@_bgd$z(9i>+xNKl#*q=WP#RXT(g1tkb7RRgFHkrI#+dPgE6 z1OW-stAGRu5Q>z*mv`O2cilhtTUl8%IhmQvd2;4Cd+%qT=Vm5`7teE_2LJ#Ujqd1M z(6&VY0G%3$p0>x?@Arzf0ea}((**#k(pXNM&(S^$xZJV02LMFg0082U0KgHgDQ*=2 z2$2H-)|>zUwH(@+0q7=k4cZrskBklV0cZcc-nSONp|vmv+_4S@09e2N_omB~WaXiq z4lvT!eGopeP93jt8;|(?92-CmUI`hLV6ya~wpq6DuwKEx zo%5V$EUfAxv&(V;us}<2{B)a1I2xP04OyJc83#kmHlT9^SuUr_PgnfK*I5T zAF6jwg?9c-y*plSjSa)L5+`O4q*q&+k~FyAGsVy+O=+{bY3uR!A&@E=R8XMUG5dnq zzVO!%>xRj<$J4+`)%=40e+Mkd@coD~<2iU=xytZV0MykSTH7q%{9v=-^!pdix#QUT zTIuC%)n_EpBbMnoziV4EVT**s#J(AF^Ny}-OuGFzcS7@6d1q_5JO2@aeD~h$o>WVe zf{yww)uF-gQ)eqrD*w@GPea(JPR+c?Ye%OMjm5Oqd=FadkKoFCiN{|)2dy5mGF0)~!{r!m+*C&y~p+R}PIR~}H@rkx81K_IgzcC^!r!7Lm z(ivg#E+1vcdzOQEWq!octL6Lne3B*XDmBk`WV@| z4t^=Mr0k_^%Cc4Y2E@i_uYc<7mf@L_o#h9N%rOY?OhwJ|Ul^H76y%vQp5=$o+Jt$g zcxL%UM&<fQ6Yf$c_*i>QH z%#Et)T77m{V0Y};wtsbt?_r^#dSq>4BC_sC#S;)-87aP^`)Rr%^yz8J{t4z{>iaWM z)19O{2i+paVQr@#pJD;FZgqWt8?{4)Moe+d*0nHe?F>Juyu(1YRN1Lp1ns*U#~&ix z&uS{|s8)_t=aJa>n~}AYvUy#BP4~*vcPZ=dkG4M*M|<5qo1M*K`$0LLPp7Iow(tA5 zZSR{ZT?7E;DhpPr^#z(qKc`zhwr@Y7oSlUK8;M@j;_yU#San{j|8A4?pY%W3|h{yjdOes4(Y$82OES6pgr zAgMU-clIqMfYT--?>OctztUkMh7_gUy*sO+Nnt~XJ=*#}i$uMH-K|Xmc?z%nC#%uylAXlqg@al8N2_ciNAV8s%&`M^zbR01({lS zvc96MpFEv*v5}m#zL9FH{im4UcjP|elmAz3aCIiJ8#}4}w>T}~uekQK@>hae<7t;gF8>Hpnu!6px7)uEuHHFEvmOmN1d&WDv1EO^$v5h=raX6h#T}hcw z`V{MM8m$$YmeogYTc6&LCQp6%>xh~~c)3lqk$Wr-?XzfsYz*1^xf|s?Q81f=*=d%F zQsF(_Z#=v`LVopsI-lFDb+`G)!NHq*RMXgvpS$*R^^P`lh--il&NSxMcAu(pVg%qM z4Qrp_HXfjKG&IO|@9fF`!NHGG+CCSCLZN7rhc?}nU$UPxmOi-l_B40*muNUYJs#{TpU)yb9r?P+6!?SF&!_DDM*tmlB572|otx!ii(R$0wBkJdw{5nr)>$Vf_fE9FYb{X$L4=L<4PJ>@jt*0e z;7#HNk5z@ELyj%jPGgm#y2O{@_^&sq!rzWUv~LW`Rh%IYPW5;XB(+ou*cJ}pFooH& z?JVWrF7RuI>LqvYQ#*m}TOT;Zgwx|gi#5N0+bBu_zbyQxTku;jjK8J2u0^v!SS+m@ zYTp~EmH@tLIdq3RNfE;a`S(lFP$1#>__$t~*bV)HSXsvJL#;EE$NbBsushv?lT4uK z&A%hgykaGTd5DGOql<-49!tI$_l?~o&7O?F%ce>D{JTbcL17)nJ}gm_OvnYPAH(J_ zRXPAih`IZyQ*C`yWYP3mK_v0#qea}Jq9MCa82i59Gl>Gkt!NYV%@JYX7nzPA!rn_b& z^i31V0S3NjbbxfTsTWbHpPA$Q>(w%T=AN!6YOUNx=x&uPetVxZ;g#&vJoz9~2zVKK z)&1(h!M*@8#Iis$M8>3x+KGVZ+fKgY`-k1Yx)<&RUl~+cici!&{_E&1l4_K1X`ne( z5WXrHr^_oRr6J#u2$gKw+B}!=d-Pp)%0~!_iHwdt{^59hY3u#S8c;U?vcB~tPMca{ z`p`wJOAnNIVZLG9M8!j0T^;s!G!utS-AEUWQ2o0f8IiBIl+q;UVBdz2U-;hN?<=rr zh+V%uqyEo@ACa%fZNR?csl**|A>$Vwf-eCbJ|9&qg-<&$3F(9F(e`b)h{e^N?H^W^ zyKfZ>z0I<3>VFwoCncfk9i@^wann~j4Bb0LQ#vRm9Rq_8mkPlS>sUcJqUK_$+Le1}hnY*^Oa0kcyCtn*! zS{)pHF2?b@7S4NWXg~mDH!O3{aiTpcFl$+7v9a-xq+G$U(!TpgdqVqndmUo@A=Owm z#y!FdQ!3%pFPmN%&`YI}7A}kh@r~5AC1Jhi)zuZFcCl6CUcMVMB|g{bwR*!|NREr} z1ox$mk;42COTzq7>%SJ2{io$jDy1rJz8heQkxn|faHnu6V8+VQ{+FddxcLLHpwIfI zrw5uXgJ^y!GOZ9Qk`n1&RgkJ!^mBXk{afAUWF-f-leTu?4@a|-A;gg1X zTpD=dn%_BX)_SdG#=gQlJGzW9sPDmW7p%~eagF2BZvg2_~vG6%yk?K zoM-Qfuz7O4G32Bt#_aM+37$t0a^a4@O)N|5ol&VXM*9%d(I9U2Ker?xG(uUffyVAn!I) z16B9&vBy!f-Zv+*EA7+}yI-9>yN|g}))h@RQTt`(78Y)AG?MizC+Ya~ST1}4=wL%~ zIl+Z;tSuCRD!F9{YJDzla$@2a+|S?tpjpvlP$M))eFwo-b?&6=$xODvy?Dk?QK@X2LS{lP}ak7oEjE!fRq6&Znoq0>rZZ z)Qk5_NHdRedHjP3wI8?LGedBNAjP{R7#<5!k;MohmEIb?%I-LpW9<^72Wy0`KkwWE z2>m4OvW+y)7J#p3b|eJAn4M7%a(OvRir>#)vMkYqXO@cjj{XpK(CaeySXamrBdrxC4V@RU1$ikf08==W!!BXh-}LG^fEmxe81zarsknbKoy#Tk4IDIPh1MOdJq=_nV`Uhm!)fJiM#w?QN5Ji}_9D@>>O5Arhzsh!`zsXvpJlO-vj&MW8gI?A=0Le7`Btm=) zIxc=G%`%sKA^tft1NU~L-?B-HB9#0zct)*tSe;m~u|H9RX4%)xjk)+Nv9)!Y+_rsf zwUdSa=uX+Vp9ou6z8Yeuu?FH&l2Llo`L{LGwJ$%P$4QpdD)Al3v1$NjnoKH%goB@T zc}|lF?$&RwSlc(cd^4G93nuxW9?ia7*y^1y@8l=aFk=*TU~Hx}XuEe}2$tFXU7!rl zfA}+nvogOugapNu4u$_?;n(<4!=&ZcQ_Qc<%+5i_#Q1Onb&FNS)|P~ZPpFa56oR=) z=I{&yP{0{!e)Z`^Yh(SPof8-b-s`Q_-dDx6f|vv?bY*>6X(Z`{r*LRB?QEBYv!Zox z;?QcPiKSV+*&JN2F5UOHZ&;#GO7;cjDW<)jE>)hOiZrv#oQ|33d4gvg1xEn z7ksw1YkY*3K+dq_a!af?o=gAd!?M(UqB`jTmJSKlgC-BZRV0%8{m73IJ1*_NP_`TH zqR(H)p3I(&9FCtm4Y);8GCtc%DOgFEZ3=l4l%;>s*Z3$i(zYr66ZVj_laQ+QHR5sDYEVRspOXZ0U_C@4TpS> zuuvk~{sHGoHayFU94p1C3;7OvDum>_Sy+%-z`))+fZif%$X$gmn!IPVlD%wFkvB6je)9F3R>DhF^pJc}Lw7$2Em6O}|@V*DE$bJ2bU-Yo4rs%NIe}cxY~+ zQ>w*MnqFEjq3ZjbU^^dkigIyTPW?bD8-@M?jRRj{KN)EmetY%0=4N9MSL!q3+oamh z^4Dv}Jug1%mW}?yrghS9xG2WR$BQ~pJ&zr;@d8A@R$^d3ozF&`Wh%E>8b@po_e|O< zH-Zxr>9(Ar!X~*XJ(VXz#8XD#Z?#|#3h}Z>e(v9a2bQY6tm)rGU*>t<;!ZfHxY1~A zCClwI27fsdj3i#<)hdw9BRufeDN@QZ~?VP}p&?V?3bgFk}osg#< zOD3Pz7n|hw?f5z)=A$ZO(gJU3E6;j`@y-0n5PKo^!BX%nDfUo(07_Y24w=&p5{c)# zq>rkv5A$UrQg{^rp&kmjBoakyMSXrS&wdO-`~Tq#~Kbv*4GNF^x~D`om+9zXWK zX0Ps@*Q`D0f3j=HH#VW4YUb0!mBgX4h{+fz(q;b}7Io!wM8~9}H0=4S^TNZvb?SM3 z?Xv}Vi~y1kUvWHGQo8oT@lXM9+LtNmkB;4_MC>ce*fj;L{T>(Pk2>o56ULZ0f0Xy` zX+P&mmMZ&G0=pil!%O~kEsRt;Gpi|(9LcgELL1XSK9PZkAb6(5XpkJY3WReUZKviAkCdW(P z{PV=)3lp7G3b)?RjWEuvs}Hbg{HpN+sKtLDh#EbRH-E-YJLwiVTzG-=+l$}o59$bx z5oP^l)cMVlLJ$A)**i7giA4CVKFuw#FzjKwx*}g%sb1tyE zI^ajB#AM_9hDN{FZW;7iWfA?bvky#W9<~SVO3Kga{-fB9 zzxsVgT^I^eVr!>sY|Qbp$~C}6UpHSbF1?90sUPgRKa77UQXAu*1!mN~-AIdFdXrsg zzuS?9?+#SE1sB$Pt@4Pj5LK%-pdd*X=X^<<27!_g_7+b+22)G&!kn5U>WYQ>Z;ZkD!3t|M{pW3Vk34(6p|DH@O;CQTv z@Rw+n{Y8(_dS$;A1HNxnxcv{|FIWUCW?S}Kl^t7gfs6Zjw&{^8SVa@ie9;(eaNlD& zN^v4rfPLoB;*ZhKUvPh4-p0v^<9pLVeRc?9D$&#jIto;JOGo zzHoYt0H8DSRgDSoM zr^D*q^I*WwjVJuI0|ih^%d^d}vklI+qa;h~>G2s){ejL-9Uoyx5=4(FJ+Y=nF&_Ym ze|p2)(4urZ+zj3`+_huOf2jZVUZ2F^52h`KuY|22#g?7^4y=cs==l|Dlgut$t2`SI)I$m+psQy7 z;{j#TdI541{`y#l;`T3JYE|k*GVScOUb~I&Z?blI`ul6&yWi)@dwn+QxcS?dNt^#0 z1GPMp*CLfI`_rwR6}R1Ar-}(GSUITq$7SIqZmZq~FS{8r2hRL?^HJ=@Hxuo^5b89W z_Cb}hY_utGp;1(;r7iIO^02jI5r)Edsi;UO=K>paCi1SF{+%(2WCpgAa3%U)9yd*Z zwOVe0ty;)#zcD}cpXSE7?aPDcdxokPKOemB?`yJ%i)$*^1cr#0!TN02k(s{;YS(WH z<^;KC%D4rtt&TrI=W8I2HYolBL&#ysVCDkyjwijgZc1_ zdaJFZTJ>*f`5j=#Xi`EMTIS*o==NQK=lWli+RfmZ2Q$L{SkjY;)FMspG_}0VRGzV_ zIA`9?jSW?&vX8g$U*aOkDYc*bN+s4xOS|QkXxS?{odF~eXKBt3Gx*9N0}@SOq-o)B z&a@}Ztx;jwTi=5XX$<`!QTjf6N0^Fpv3;}QS$%adhsTd98Ha_1o)*Va)oH4$FuQcWY+EdM zB!>Z54?Dnlx42NiA&4^Rd* zx4T+xrN5bK#QKE=^WQJ`&P!Ebf3EQ(6=z^$22HJlxFF4@l52lq-Pc>PaTkO-_3)5w zzDU;_hpq~_D17&Ku^!OPN#-t)?&pjdTKa7WE|W^p!%RlKD}I?z{q;?&6<6O_U*9ZO z|L@dm77#b)a6A*%PF1-6HA*%!i15@IV&L39c@rv(q`#rjxnbfXr{$EPN%>VXsJVB7 zv$ZNN_Pj;f3Iu(ov>Nt$b=x z;G@0%%^AY*!j2}aq%)-~_`bY_L}7V3#$qCZtwlCP!VfwV)%Q0%o%`{AC}XJtNErD( z3o4!peqa&YDFEzIF}#X<1J7CkcME`Zd7Tml^TX*Macqe#nZL!@PTKxR`4Nb&o!mIE z6z`YJu53ANwek@kD3E4yMsZiRebyV_dOzO zHsC7`b^_urE~(758UnaI(z`!^4Xkr*gi)-aNuaJK3nN8F@Yewdy?`VpbqMw?H3z&v zw>9H}4Da<3=bFb^!X(&(DyetFK22`$Uf4IbmqtHC@&V1oFtsy&WWU+MvZJ1c5R$uj z*8PE*W3S3?uKTb+{LV)K=Td0 zTQ2>OZq+bCrrY>NEmt8SLhlZkv4l`sJ~h>RKQlzwYtwhb#s_-%St?jYzigaPbJyFx z7^jH%qW-Jz;VP+R*u(|a8tevVN2OMw?<3Qh;>`MQ-%?jUARdm9*QXFiQ#Ixsvng~J zOLt0Td@vkwa;Cv3aNJMZG%ykXaZ~l+3olzIZZdvQ;VG`pO24g_UPFv96ssbb!vulT zxuMNtN)s0h7w0|g+(Tq@y{=13-@K75&-gxM#-eLsm72+ROPZdM?h8>5KoeNgj>751%ZSJ4_+al@alU8z@-FS)lUZDo9;lNJ1V2F`_F!q z-mQfC8}pym3SOW+zMCTaNkYFIybJq2a&MTR>IuzHa)_967OrRW0kJ56 z0-h%08-E9;eC&w&oT>*AM(OdfePc4rHrYhovVxBhv(k7ku+o$gU|4<3Vz6leJy^k{ zHTdUY_2)&XK8TJle2)18)Ca4S0KUAWnQn2_>jP#vfdNP=heAvkAm!B^QU0135tv?| z_@{@Zk)LpKe5f(TbRm1OVeQSyE6HbWBX?84CJ8DHv5Hep~Du=fr z^*oKhUc^5P(1Kk2;uKcrA555S**a3;zYVIZQ?5}`#tR`6?&yHnp&Coo8H9(vRR%I0 z=$;IV*R_|CX5bW!f%pTVxzwV=ZB8xo@z>yLh4vc{S6i;J89GBkCtI7F-#_EDT1Fqt z*c4t^nSwB&$%I-#MgxZklHB!~#v-oZPIj7jVkrrr$;@9N(P&?rIyKfFgX#^>0-rR%s4 zeV+stp3_(?&lM37K@AmME3=^kaGTdyT)91O7dC%{^(lUtN0lr%Eeoy*K4yv%O+#N5 zbhOt}OZ96js~%g9KftSk1Uk|mp`W}Kk~9$0@4zXbMxg5Ptc-yGv}2AnjKX{o5-?+9 z%W)m^)izD;BRXQ`eNs=uznTpsZ<-3DCn8k*lDy7l$+rS~v}5GabC0a7&Cwi+?DKhq}exXn!H*6WHNolXjrC8QMO_rW; zt^hT%f!z?elnTF1Jnz!au!%}t_^Cb@ZwQtsEOdtq>x{ky*)6$&87<8P<1p|aERywp zvvzh55t}6|XO!&r@WUevHc!2>We@vpP(zcK^~T?Z>9whz-&b0Kp0Kljh2+W1iI;en z2qI^~Va$M^>SWC?cr{XDx(nmy_n?m&(&beky~1)P2cVtt0O%=XCuil&)WiGkndWdF zbr@T%JU?Q;kfzeC?;Yua_nTUoB%@q{7uWX6y5|F&{hZ}yVpqCs|9mblgMs3~!!|U; z0NS64BDWl5R4bXv+O>Wz>c^|b<)7!q(*?vSyr4}ZBQTeQnm~f8PwnMo!LMe(mU79* zPs}q$UUA+4ISr~#PfV1D#88g*j9$5Wh0gCxCMN0@&(2KGUY6?J@%3}Bc%`)YcAZn3 zO0NUf0iW+YciGt~^*ZVo1_}5QXXEj$yH={S@sHN0hdhN6qkro(c0;b?6ee;6Sbwwx zP5dz!H?e_|B(UN_8}5~3`J{s=3iX`c*7L&RLY2s!ZBbh+F%iZQM4%}oo0}WHk7omk z(gfM{bw5$_LiSoeyXH-FBKQ#!TLTi*qsiA`J13MF=8c-YgN`d$OjJeAg{P}6l58S87R8F_21XJtJ*o}C(@+vV zM_!HllQXXg>y3>2usc~-kqglly*4mR?J$6jsl_S5N&kxzk}eKG4Q|iXAE@ylwEY{( z?vjf(`-H`D&cv+Xl-mw^v=6(jX2KgKO3TJ7E<%~84h5G3sd&o^Rr1dQZ&7PJzXlc# zbs#+pZ`Ng2B#plxep>hXe3sH>5Wr0z$gB7$V?Kdlr8>|L(+$k@%1jNi?wfb*2c834 zTK_56q*aDgc*JSrZ}G{$lM(*TIZg6a47Tha zTH&eV4!2~$U-33Ka=;gaGF~e1owxL110-hK>|FOG+kA2qD2SF~BP+_l`W=@ew zb=&UwIU2Wl{MhePkJ$5fiQi{BJ3CWTebk$60a1K`moBZw)yzcA`YNgA5eQC626wp| zTWgAI;V^bRR2A@1a$J}L%&mxd5in0S7{2U#Pq+rL-dM z0HsJ!eHM;DXrXAh9Sa}UY75#~#_~XhM0_ixDmU2M`R6}6GiaVi{vxnl%|7ggo1kR))thGdzA(1pPp zrie9+qgKq$-NILQho3Bqx-wdZ?5+7!MxUm%k8OmVV@7NQw@a3U^hIP45Hjo+|Sju;7EG>(^aFBc6e$ zd_`x}K{~Ip0RWFYux|bAMo8qeU*(YJ$?tt{)Zv8k=`To4YfUSz#`;|!cXMmaHN$O{ zys4Iu#sAzUr22~1BYc=ip31;#)Y}(J5s1@;!_I&^;Bo%-XGS^j%ZvR1DxS5MeWaem z1=(=k)a&&or55D=jasi`YDT>t@?0-Z1oap#38oudQ_@4GE1DRkf*vJUKwBvsF2z!! zdXg@vOq@6Ftvs7};fQ?v0|k((+lBBBU|IF~%R60){G-E5*7NUG+k(6^E=EqDhHIP* z#_nKT3||^L|C?Ev`uBCb(9-h0iFnUnl_ZERNWYh4E1N+WGcKAKjR--)eQLqYc z4$BM4c>N^(G7KI3lYvZkQ4I6T=JGRLFeCnVilMg7QZaG9H}Z$-(+j$6Z?TMV`A+>R6ykHUC4*bycxQ0x$o9}^ z;i9hyDN>Gi)Q!5vGpiYOG!<3QK8F!zfvv%dRk=~EOmKB_-fOi24p4UkmxYNSveW{s zbK`SO{)kR#Q-7J)mI#DF#F+Dq4ecQEpD2lQ{rj;ydsFz>eu_a*s z5a>RpQ)-GE1h#b#TC&MzGLx9>=sd<`Ddh+XfM7yMelZ^)D9 z_P5@Vy5H&4F7`si2oVW&&0kS(Rv+_soaXVfbxY$_y*0rP00|&DoN|pVKS!ruhT1)* zdzKp7C6x(VHgNt@QF>lag$o0>y_+89K&+PV?(=+=ZQvk|jb{Su-L0x8Jh%#>S$^nz z2uc}m5}1?c`}(}iufoJVT7y}IUE^(S9?FoWBG}RoSA+T616ORChZ<{e^1Q729ilWE zQW{z|O&(|w9rqEn5)&R*85`CCx?acKg7T25O1_=8vh>TX2OTa@bTDYHTB59653=m_ z>ZPKK?=MhlHM&ZLHKpA5TdPU&W#ul1W`C?^#KLY`MYie+NHB3*_j(!TuqRBWwN zr~9PYs6};t#Acy(%!?gD59OWhJA*7+m&}qHB?d6+K=iMiGCr%Yv|j>NQgZiJ--meO zxEP4xMv(=ke8=den0v-080h-MYV~J%JXrU7=1rnE3!QHWPlqsHkp73jTWe6MWt+01 z@h=@;l4173$;s~z8+u1t`b%k*oPj;kUonpa^Sk?ulMz|slD5;IMj3^Jd=HUKCO$E) ze|n=L(&vSX;cD1W%h8-i9@0oNV3((&{T=xU&&OgPz`C@2G+|wg<-2yb<-pDQyUnA7 z)L(~1P6;j-DCHOQsv5rNvm3u=EG(b)4V%c@WZTt)83E=*@>&iFBm?W{16;P@U$cqV zk3xNpCpJ&(Gzk>7f+x5bIF`hpY%UTn`7Ce?6E`d#mHH;Yzl_l^gLOq{UmOM|q8*ixVDNdyR6e z4D6xm?cp9TIkQ$un}P`EK6oBXWL)YKV}k(r!gU}t9}lX$=B}B{!&jL^wYm7$=kKGy zT@X%duA4%4&2zJjB-urxx4R4et+Mc!m3kvWH>+yW1_^|Fr1S@tI9%%?|Jj^&%SoTI za=kJGpN&hQn4hxx1xo!)#BCzXc;FmKDatFK@Wdlg&a-|Z6=FzWGy6eJ1yfzvY} zV&sOpIRQ?=toO=OKqd z^JpW2TAHjX1X9saOmrUe(pw>us!25nNurReoA6!#s%z?lDv8YIPFnW00Zs@`~t~$(zL9j)H3Kh zb9q-J*d%q>9DKPSv5|fDcIejNjzb;&=ChYi-cDD>u9UH)q)4Xt zOh$!eSeU1;Z*GRO>3^+#;4GZXL-Xp{<=9WO)g)?)m+h2@7Wmyr<(C+K3V!={Fq&pA z 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 literal 0 HcmV?d00001 diff --git a/src/packaging/zip/start.bat b/src/packaging/zip/start.bat new file mode 100644 index 0000000..867a706 --- /dev/null +++ b/src/packaging/zip/start.bat @@ -0,0 +1,2 @@ +@ECHO OFF +java -jar "@mainJarFile@" diff --git a/src/packaging/zip/start.sh b/src/packaging/zip/start.sh new file mode 100755 index 0000000..3ba1381 --- /dev/null +++ b/src/packaging/zip/start.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +jvmFlags="" + +case "$OSTYPE" in + "darwin"*) + # On MacOS, use -XstartOnFirstThread to resolve an issue with OpenGL contexts + jvmFlags="$jvmFlags -XstartOnFirstThread" +esac + +java $jvmFlags -jar "@mainJarFile@"